pdfbox-1.8.11/0000755000000000000000000000000012645760246011576 5ustar rootrootpdfbox-1.8.11/LICENSE.txt0000644000000000000000000004326012645757434013433 0ustar rootroot Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. EXTERNAL COMPONENTS Apache PDFBox includes a number of components with separate copyright notices and license terms. Your use of these components is subject to the terms and conditions of the following licenses. Contributions made to the original PDFBox, JempBox and FontBox projects: Copyright (c) 2002-2007, www.pdfbox.org Copyright (c) 2006-2007, www.jempbox.org All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of pdfbox; 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 REGENTS 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. Adobe Font Metrics (AFM) for PDF Core 14 Fonts This file and the 14 PostScript(R) AFM files it accompanies may be used, copied, and distributed for any purpose and without charge, with or without modification, provided that all copyright notices are retained; that the AFM files are not distributed without this file; that all modifications to this file or any of the AFM files are prominently noted in the modified file(s); and that this paragraph is not modified. Adobe Systems has no responsibility or obligation to support the use of the AFM files. CMaps for PDF Fonts (http://opensource.adobe.com/wiki/display/cmap/Downloads) Copyright 1990-2009 Adobe Systems Incorporated. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Adobe Systems Incorporated 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 HOLDER 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. Glyphlist (http://www.adobe.com/devnet/opentype/archives/glyph.html) 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. PaDaF PDF/A preflight (http://sourceforge.net/projects/padaf) Copyright 2010 Atos Worldline SAS Licensed by Atos Worldline SAS under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. Atos Worldline SAS licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pdfbox-1.8.11/parent/0000755000000000000000000000000012645757436013076 5ustar rootrootpdfbox-1.8.11/parent/pom.xml0000644000000000000000000002164112645757434014415 0ustar rootroot 4.0.0 org.apache apache 10 org.apache.pdfbox pdfbox-parent 1.8.11 pom PDFBox parent 2002 The Apache Software Foundation http://pdfbox.apache.org jira https://issues.apache.org/jira/browse/PDFBOX ISO-8859-1 3.0.0 pedantic org.apache.rat apache-rat-plugin verify check maven-compiler-plugin 1.5 1.5 maven-javadoc-plugin 1.5 http://download.oracle.com/javase/1.5.0/docs/api/ maven-release-plugin false deploy -Papache-release,pedantic true org.apache.maven.plugins maven-jar-plugin true true org.codehaus.mojo animal-sniffer-maven-plugin 1.13 org.codehaus.mojo.signature java15 1.0 check-java-compatibility test check org.apache.rat apache-rat-plugin 0.6 release.properties org.apache.felix maven-bundle-plugin 2.3.7 org.eclipse.m2e lifecycle-mapping 1.0.0 org.apache.maven.plugins maven-antrun-plugin [1.6,) run lehmi Andreas Lehmkühler PMC Chair adam Adam Nichols PMC Member blitchfield Ben Litchfield PMC Member carrier Brian Carrier PMC Member danielwilson Daniel Wilson PMC Member leleueri Eric Leleu PMC Member (emeritus) gbailleul Guillaume Bailleul PMC Member jeremias Jeremias Maerki PMC Member koch Johannes Koch PMC Member jukka Jukka Zitting PMC Member (emeritus) kjackson Kevin Jackson PMC Member msayhoun Maruan Sayhoun PMC Member pkoch Phillipp Koch PMC Member tchojecki Thomas Chojecki PMC Member tboehme Timo Boehme PMC Member vfed Villu Ruusmann PMC Member scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/1.8.11/pdfbox-parent scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/1.8.11/pdfbox-parent http://svn.apache.org/viewvc/maven/pom/tags/1.8.11/pdfbox-parent pdfbox-1.8.11/pdfbox-checkstyle.xml0000644000000000000000000001642112645757426015750 0ustar rootroot pdfbox-1.8.11/war/0000755000000000000000000000000012645760124012362 5ustar rootrootpdfbox-1.8.11/war/src/0000755000000000000000000000000012645757434013163 5ustar rootrootpdfbox-1.8.11/war/src/main/0000755000000000000000000000000012645757434014107 5ustar rootrootpdfbox-1.8.11/war/src/main/webapp/0000755000000000000000000000000012645757434015365 5ustar rootrootpdfbox-1.8.11/war/src/main/webapp/WEB-INF/0000755000000000000000000000000012645757434016414 5ustar rootrootpdfbox-1.8.11/war/src/main/webapp/WEB-INF/web.xml0000644000000000000000000000200312645757434017706 0ustar rootroot Web application for PDFBox examples. pdfbox-1.8.11/war/src/main/webapp/bookmarks.xml0000644000000000000000000000210312645757434020073 0ustar rootroot pdfbox-1.8.11/war/src/main/webapp/highlight.jsp0000644000000000000000000000333012645757434020051 0ustar rootroot<%-- ! Licensed to the Apache Software Foundation (ASF) under one or more ! contributor license agreements. See the NOTICE file distributed with ! this work for additional information regarding copyright ownership. ! The ASF licenses this file to You under the Apache License, Version 2.0 ! (the "License"); you may not use this file except in compliance with ! the License. You may obtain a copy of the License at ! ! http://www.apache.org/licenses/LICENSE-2.0 ! ! Unless required by applicable law or agreed to in writing, software ! distributed under the License is distributed on an "AS IS" BASIS, ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ! See the License for the specific language governing permissions and ! limitations under the License. --%> <%@ page import="org.apache.pdfbox.pdmodel.PDDocument"%> <%@ page import="org.apache.pdfbox.util.PDFHighlighter"%> <%@ page import="java.net.URL"%> <% long start = System.currentTimeMillis(); response.setHeader("Cache-Control","no-cache") ; response.setHeader("Pragma","no-cache") ; response.setDateHeader("Expires",0); String pdfURLString = request.getParameter( "pdf" ); String highlightWords = request.getParameter( "words" ); URL pdfURL = new URL( pdfURLString ); PDDocument doc = null; try { doc = PDDocument.load( pdfURL.openStream() ); PDFHighlighter highlighter = new PDFHighlighter(); highlighter.generateXMLHighlight( doc, highlightWords.split( " " ), out ); } finally { if( doc != null ) { doc.close(); } } long stop = System.currentTimeMillis(); System.out.println( "Highlighter time:" +(stop-start) ); %> pdfbox-1.8.11/war/src/main/webapp/index.html0000644000000000000000000000450212645757434017363 0ustar rootroot PDFBox Examples

PDFBox Highlighter example

This is a simple example to show off the PDFBox highlighting capabilities. Enter a URL PDF that you would like to view and some words that you would like to search on.

See the PDF Highlighter spec for more detailed information.
PDF:
Highligh words:

pdfbox-1.8.11/war/pom.xml0000644000000000000000000000306512645757434013715 0ustar rootroot 4.0.0 org.apache.pdfbox pdfbox-parent 1.8.11 ../parent/pom.xml pdfbox-war war Apache PDFBox webapp ${project.groupId} pdfbox ${project.version} pdfbox-1.8.11/xmpbox/0000755000000000000000000000000012645757534013121 5ustar rootrootpdfbox-1.8.11/xmpbox/src/0000755000000000000000000000000012645757426013710 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/0000755000000000000000000000000012645757426014634 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/0000755000000000000000000000000012645757426015555 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/0000755000000000000000000000000012645757426016344 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/apache/0000755000000000000000000000000012645757426017565 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/0000755000000000000000000000000012645757426021102 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/0000755000000000000000000000000012645757426022342 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPRightsManagementSchema.java0000644000000000000000000002222512645757426030153 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.BooleanType; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.type.URLType; /** * Representation of XMP Rights Management Schema * * @author a183132 * */ @StructuredType(preferedPrefix = "xmpRights", namespace = "http://ns.adobe.com/xap/1.0/rights/") public class XMPRightsManagementSchema extends XMPSchema { @PropertyType(type = Types.URL, card = Cardinality.Simple) public static final String CERTIFICATE = "Certificate"; @PropertyType(type = Types.Boolean, card = Cardinality.Simple) public static final String MARKED = "Marked"; @PropertyType(type = Types.ProperName, card = Cardinality.Bag) public static final String OWNER = "Owner"; @PropertyType(type = Types.LangAlt, card = Cardinality.Simple) public static final String USAGETERMS = "UsageTerms"; @PropertyType(type = Types.URL, card = Cardinality.Simple) public static final String WEBSTATEMENT = "WebStatement"; /** * Constructor of XMPRightsManagement Schema with preferred prefix * * @param metadata * The metadata to attach this schema */ public XMPRightsManagementSchema(XMPMetadata metadata) { super(metadata); } /** * Constructor of XMPRightsManagement schema with specified prefix * * @param metadata * The metadata to attach this schema * @param ownPrefix * The prefix to assign */ public XMPRightsManagementSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } /** * Add a legal owner for the described resource. * * @param value * value to add */ public void addOwner(String value) { addQualifiedBagValue(OWNER, value); } public void removeOwner(String value) { removeUnqualifiedBagValue(OWNER, value); } /** * Return the Bag of owner(s) * * @return owners property */ public ArrayProperty getOwnersProperty() { return (ArrayProperty) getProperty(OWNER); } /** * Return a String list of owner(s) * * @return list of defined owners */ public List getOwners() { return getUnqualifiedBagValueList(OWNER); } /** * Set Marked value * * @param marked * value to add */ public void setMarked(Boolean marked) { BooleanType tt = (BooleanType) instanciateSimple(MARKED, marked ? BooleanType.TRUE : BooleanType.FALSE); setMarkedProperty(tt); } /** * Set Marked property * * @param marked * Marked property to set */ public void setMarkedProperty(BooleanType marked) { addProperty(marked); } /** * Get Marked property * * @return Marked property */ public BooleanType getMarkedProperty() { return (BooleanType) getProperty(MARKED); } /** * Get Marked value * * @return marked value */ public Boolean getMarked() { BooleanType bt = ((BooleanType) getProperty(MARKED)); return bt == null ? null : bt.getValue(); } /** * Add an usageTerms value * * @param lang * concerned language * @param value * value to set */ public void addUsageTerms(String lang, String value) { setUnqualifiedLanguagePropertyValue(USAGETERMS, lang, value); } /** * Set the default usage terms for this resource. * * @param terms * The resource usage terms. */ public void setUsageTerms(String terms) { addUsageTerms(null, terms); } /** * Convenience method for jempbox signature compatibility * * @see XMPRightsManagementSchema#addUsageTerms(String, String) */ @Deprecated public void setDescription(String language, String terms) { addUsageTerms(language, terms); } /** * Return the Lang alt UsageTerms * * @return usageterms property */ public ArrayProperty getUsageTermsProperty() { return (ArrayProperty) getProperty(USAGETERMS); } /** * Return a list of languages defined in description property * * @return list of languages defined for usageterms */ public List getUsageTermsLanguages() { return getUnqualifiedLanguagePropertyLanguagesValue(USAGETERMS); } /** * Return a language value for description property * * @param lang * concerned language * @return value of specified language */ public String getUsageTerms(String lang) { return getUnqualifiedLanguagePropertyValue(USAGETERMS, lang); } /** * Get the default usage terms for the document. * * @return The terms for this resource. */ public String getUsageTerms() { return getUsageTerms(null); } /** * Return the WebStatement URL as TextType. * * @return Webstatement URL property */ public TextType getWebStatementProperty() { return ((TextType) getProperty(WEBSTATEMENT)); } /** * Return the WebStatement URL as String. * * @return webStatement URL value */ public String getWebStatement() { TextType tt = ((TextType) getProperty(WEBSTATEMENT)); return tt == null ? null : tt.getStringValue(); } /** * Set the WebStatement url * * @param url * WebStatemen url value to set */ public void setWebStatement(String url) { URLType tt = (URLType) instanciateSimple(WEBSTATEMENT, url); setWebStatementProperty(tt); } /** * Set the WebStatement url * * @param url * WebStatemen url property to set */ public void setWebStatementProperty(URLType url) { addProperty(url); } /** * Return the Certificate URL as TextType. * * @return certificate url property */ public TextType getCertificateProperty() { return ((TextType) getProperty(CERTIFICATE)); } /** * Return the Certificate URL as String. * * @return certificate URL value */ public String getCertificate() { TextType tt = ((TextType) getProperty(CERTIFICATE)); return tt == null ? null : tt.getStringValue(); } /** * Convenience method for jempbox signature compatibility * * @see XMPRightsManagementSchema#getCertificate() */ @Deprecated public String getCopyright() { return getCertificate(); } /** * Convenience method for jempbox signature compatibility * * @see XMPRightsManagementSchema#getCertificate() */ @Deprecated public String getCertificateURL() { return getCertificate(); } /** * Set the Certificate URL. * * @param url * certficate url value to set */ public void setCertificate(String url) { URLType tt = (URLType) instanciateSimple(CERTIFICATE, url); setCertificateProperty(tt); } /** * Convenience method for jempbox signature compatibility * * @see XMPRightsManagementSchema#setCertificate(String) */ @Deprecated public void setCertificateURL(String certificate) { setCertificate(certificate); } /** * Convenience method for jempbox signature compatibility * * @see XMPRightsManagementSchema#setCertificate(String) */ @Deprecated public void setCopyright(String certificate) { setCertificate(certificate); } /** * Set the Certificate URL. * * @param url * certificate url property to set */ public void setCertificateProperty(URLType url) { addProperty(url); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPSchema.java0000644000000000000000000012770612645757426025007 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.Iterator; import java.util.List; import javax.xml.XMLConstants; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XmpConstants; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.AbstractSimpleProperty; import org.apache.xmpbox.type.AbstractStructuredType; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Attribute; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.BooleanType; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.ComplexPropertyContainer; import org.apache.xmpbox.type.DateType; import org.apache.xmpbox.type.IntegerType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.TypeMapping; import org.apache.xmpbox.type.Types; /** * This class represents a metadata schema that can be stored in an XMP document. It handles all generic properties that * are available. See subclasses for access to specific properties. MODIFIED TO INCLUDE OBJECT REPRESENTATION * */ public class XMPSchema extends AbstractStructuredType { /** * Create a new blank schema that can be populated. * * @param metadata * The parent XMP metadata that this schema will be part of. * @param namespaceURI * The URI of the namespace, ie "http://ns.adobe.com/pdf/1.3/" * @param prefix * The prefix to be used * @param name * The name of the namespace, ie pdf,dc,... * */ public XMPSchema(XMPMetadata metadata, String namespaceURI, String prefix, String name) { super(metadata, namespaceURI, prefix, name); addNamespace(getNamespace(), getPrefix()); } public XMPSchema(XMPMetadata metadata) { this(metadata, null, null, null); } public XMPSchema(XMPMetadata metadata, String prefix) { this(metadata, null, prefix, null); } public XMPSchema(XMPMetadata metadata, String namespaceURI, String prefix) { this(metadata, namespaceURI, prefix, null); } /** * Retrieve a generic simple type property * * @param qualifiedName * Full qualified name of proeprty wanted * @return The generic simple type property according to its qualified Name */ public AbstractField getAbstractProperty(String qualifiedName) { Iterator it = getContainer().getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (tmp.getPropertyName().equals(qualifiedName)) { return tmp; } } return null; } /** * Get the RDF about attribute * * @return The RDF 'about' attribute. */ public Attribute getAboutAttribute() { return getAttribute(XmpConstants.ABOUT_NAME); } /** * Get the RDF about value. * * @return The RDF 'about' value. If there are not rdf:about attribute, an empty string is returned. */ public String getAboutValue() { Attribute prop = getAttribute(XmpConstants.ABOUT_NAME); if (prop != null) { return prop.getValue(); } return ""; // PDFBOX-1685 : if missing rdf:about should be considered as empty string } /** * Set the RDF 'about' attribute * * @param about * the well-formed attribute * @throws BadFieldValueException * Bad Attribute name (not corresponding to about attribute) */ public void setAbout(Attribute about) throws BadFieldValueException { if (XmpConstants.RDF_NAMESPACE.equals(about.getNamespace())) { if (XmpConstants.ABOUT_NAME.equals(about.getName())) { setAttribute(about); return; } } // else throw new BadFieldValueException("Attribute 'about' must be named 'rdf:about' or 'about'"); } /** * Set the RDF 'about' attribute. Passing in null will clear this attribute. * * @param about * The new RFD about value. */ public void setAboutAsSimple(String about) { if (about == null) { removeAttribute(XmpConstants.ABOUT_NAME); } else { setAttribute(new Attribute(XmpConstants.RDF_NAMESPACE, XmpConstants.ABOUT_NAME, about)); } } private void setSpecifiedSimpleTypeProperty(Types type, String qualifiedName, Object propertyValue) { if (propertyValue == null) { // Search in properties to erase Iterator it = getContainer().getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (tmp.getPropertyName().equals(qualifiedName)) { getContainer().removeProperty(tmp); return; } } } else { AbstractSimpleProperty specifiedTypeProperty; try { TypeMapping tm = getMetadata().getTypeMapping(); specifiedTypeProperty = tm.instanciateSimpleProperty(null, getPrefix(), qualifiedName, propertyValue, type); } catch (Exception e) { throw new IllegalArgumentException( "Failed to create property with the specified type given in parameters", e); } // attribute placement for simple property has been removed // Search in properties to erase Iterator it = getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (tmp.getPropertyName().equals(qualifiedName)) { removeProperty(tmp); addProperty(specifiedTypeProperty); return; } } addProperty(specifiedTypeProperty); } } /** * Add a SimpleProperty to this schema * * @param prop * The Property to add */ private void setSpecifiedSimpleTypeProperty(AbstractSimpleProperty prop) { // attribute placement for simple property has been removed // Search in properties to erase Iterator it = getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (tmp.getPropertyName().equals(prop.getPropertyName())) { removeProperty(tmp); addProperty(prop); return; } } addProperty(prop); } /** * Set TextType property * * @param prop * The text property to add */ public void setTextProperty(TextType prop) { setSpecifiedSimpleTypeProperty(prop); } /** * Set a simple text property on the schema. * * @param qualifiedName * The name of the property, it must contain the namespace prefix, ie "pdf:Keywords" * @param propertyValue * The value for the property, can be any string. Passing null will remove the property. */ public void setTextPropertyValue(String qualifiedName, String propertyValue) { setSpecifiedSimpleTypeProperty(Types.Text, qualifiedName, propertyValue); } /** * Set a simple text property on the schema, using the current prefix. * * @param simpleName * the name of the property without prefix * @param propertyValue * The value for the property, can be any string. Passing null will remove the property. */ public void setTextPropertyValueAsSimple(String simpleName, String propertyValue) { this.setTextPropertyValue(simpleName, propertyValue); } /** * Get a TextProperty Type from its name * * @param name * The full qualified name of the property wanted * @return The Text Type property wanted */ public TextType getUnqualifiedTextProperty(String name) { String qualifiedName = name; AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof TextType) { return (TextType) prop; } else { throw new IllegalArgumentException("Property asked is not a Text Property"); } } return null; } /** * Get the value of a simple text property. * * @param name * The name of the property to get, it must include the namespace prefix. ie "pdf:Keywords". * * @return The value of the text property or the null if there is no value. * */ public String getUnqualifiedTextPropertyValue(String name) { TextType tt = getUnqualifiedTextProperty(name); return tt == null ? null : tt.getStringValue(); } /** * Get the Date property with its name * * @param qualifiedName * The name of the property to get, it must include the namespace prefix. ie "pdf:Keywords". * @return Date Type property * */ public DateType getDateProperty(String qualifiedName) { AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof DateType) { return (DateType) prop; } else { throw new IllegalArgumentException("Property asked is not a Date Property"); } } return null; } /** * Get a simple date property value on the schema, using the current prefix. * * @param simpleName * the local name of the property to get * @return The value of the property as a calendar. * */ public Calendar getDatePropertyValueAsSimple(String simpleName) { return this.getDatePropertyValue(simpleName); } /** * Get the value of the property as a date. * * @param qualifiedName * The fully qualified property name for the date. * * @return The value of the property as a date. * */ public Calendar getDatePropertyValue(String qualifiedName) { AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof DateType) { return ((DateType) prop).getValue(); } else { throw new IllegalArgumentException("Property asked is not a Date Property"); } } return null; } /** * Set a new DateProperty * * @param date * The DateType Property */ public void setDateProperty(DateType date) { setSpecifiedSimpleTypeProperty(date); } /** * Set a simple Date property on the schema, using the current prefix. * * @param simpleName * the name of the property without prefix * @param date * The calendar value for the property, can be any string. Passing null will remove the property. */ public void setDatePropertyValueAsSimple(String simpleName, Calendar date) { this.setDatePropertyValue(simpleName, date); } /** * Set the value of the property as a date. * * @param qualifiedName * The fully qualified property name for the date. * @param date * The date to set, or null to clear. */ public void setDatePropertyValue(String qualifiedName, Calendar date) { setSpecifiedSimpleTypeProperty(Types.Date, qualifiedName, date); } /** * Get a BooleanType property with its name * * @param qualifiedName * the full qualified name of property wanted * @return boolean Type property */ public BooleanType getBooleanProperty(String qualifiedName) { AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof BooleanType) { return (BooleanType) prop; } else { throw new IllegalArgumentException("Property asked is not a Boolean Property"); } } return null; } /** * Get a simple boolean property value on the schema, using the current prefix. * * @param simpleName * the local name of property wanted * @return The value of the property as a boolean. */ public Boolean getBooleanPropertyValueAsSimple(String simpleName) { return this.getBooleanPropertyValue(simpleName); } /** * Get the value of the property as a boolean. * * @param qualifiedName * The fully qualified property name for the boolean. * * @return The value of the property as a boolean. Return null if property not exist */ public Boolean getBooleanPropertyValue(String qualifiedName) { AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof BooleanType) { return ((BooleanType) prop).getValue(); } else { throw new IllegalArgumentException("Property asked is not a Boolean Property"); } } // Return null if property not exist. This method give the property // value so treat this return in this way. // If you want to use this value like a condition, you must check this // return before return null; } /** * Set a BooleanType property * * @param bool * the booleanType property */ public void setBooleanProperty(BooleanType bool) { setSpecifiedSimpleTypeProperty(bool); } /** * Set a simple Boolean property on the schema, using the current prefix. * * @param simpleName * the name of the property without prefix * @param bool * The value for the property, can be any string. Passing null will remove the property. */ public void setBooleanPropertyValueAsSimple(String simpleName, Boolean bool) { this.setBooleanPropertyValue(simpleName, bool); } /** * Set the value of the property as a boolean. * * @param qualifiedName * The fully qualified property name for the boolean. * @param bool * The boolean to set, or null to clear. */ public void setBooleanPropertyValue(String qualifiedName, Boolean bool) { setSpecifiedSimpleTypeProperty(Types.Boolean, qualifiedName, bool); } /** * Get the Integer property with its name * * @param qualifiedName * the full qualified name of property wanted * @return Integer Type property */ public IntegerType getIntegerProperty(String qualifiedName) { AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof IntegerType) { return ((IntegerType) prop); } else { throw new IllegalArgumentException("Property asked is not an Integer Property"); } } return null; } /** * Get a simple integer property value on the schema, using the current prefix. * * @param simpleName * the local name of property wanted * @return The value of the property as an integer. */ public Integer getIntegerPropertyValueAsSimple(String simpleName) { return this.getIntegerPropertyValue(simpleName); } /** * Get the value of the property as an integer. * * @param qualifiedName * The fully qualified property name for the integer. * * @return The value of the property as an integer. */ public Integer getIntegerPropertyValue(String qualifiedName) { AbstractField prop = getAbstractProperty(qualifiedName); if (prop != null) { if (prop instanceof IntegerType) { return ((IntegerType) prop).getValue(); } else { throw new IllegalArgumentException("Property asked is not an Integer Property"); } } return null; } /** * Add an integerProperty * * @param prop * The Integer Type property */ public void setIntegerProperty(IntegerType prop) { setSpecifiedSimpleTypeProperty(prop); } /** * Set a simple Integer property on the schema, using the current prefix. * * @param simpleName * the name of the property without prefix * @param intValue * The value for the property, can be any string. Passing null will remove the property. */ public void setIntegerPropertyValueAsSimple(String simpleName, Integer intValue) { this.setIntegerPropertyValue(simpleName, intValue); } /** * Set the value of the property as an integer. * * @param qualifiedName * The fully qualified property name for the integer. * @param intValue * The int to set, or null to clear. */ public void setIntegerPropertyValue(String qualifiedName, Integer intValue) { setSpecifiedSimpleTypeProperty(Types.Integer, qualifiedName, intValue); } /** * Generic array property removing * * @param qualifiedArrayName * the full qualified name of property wanted * @param fieldValue * the field value */ private void removeUnqualifiedArrayValue(String arrayName, String fieldValue) { ArrayProperty array = (ArrayProperty) getAbstractProperty(arrayName); if (array != null) { ArrayList toDelete = new ArrayList(); Iterator it = array.getContainer().getAllProperties().iterator(); AbstractSimpleProperty tmp; while (it.hasNext()) { tmp = (AbstractSimpleProperty) it.next(); if (tmp.getStringValue().equals(fieldValue)) { toDelete.add(tmp); } } Iterator eraseProperties = toDelete.iterator(); while (eraseProperties.hasNext()) { array.getContainer().removeProperty(eraseProperties.next()); } } } /** * Remove all matching entries with the given value from the bag. * * @param bagName * The name of the bag, it must include the namespace prefix. ie "pdf:Keywords". * @param bagValue * The value to remove from the bagList. */ public void removeUnqualifiedBagValue(String bagName, String bagValue) { removeUnqualifiedArrayValue(bagName, bagValue); } /** * add a bag value property on the schema, using the current prefix. * * @param simpleName * the local name of property * @param bagValue * the string value to add */ public void addBagValueAsSimple(String simpleName, String bagValue) { this.internalAddBagValue(simpleName, bagValue); } private void internalAddBagValue(String qualifiedBagName, String bagValue) { ArrayProperty bag = (ArrayProperty) getAbstractProperty(qualifiedBagName); TextType li = createTextType(XmpConstants.LIST_NAME, bagValue); if (bag != null) { bag.getContainer().addProperty(li); } else { ArrayProperty newBag = createArrayProperty(qualifiedBagName, Cardinality.Bag); newBag.getContainer().addProperty(li); addProperty(newBag); } } /** * Add an entry to a bag property. * * @param simpleName * The name of the bag without the namespace prefix * @param bagValue * The value to add to the bagList. */ public void addQualifiedBagValue(String simpleName, String bagValue) { internalAddBagValue(simpleName, bagValue); } /** * Get all the values of the bag property. This will return a list of java.lang.String objects, this is a read-only * list. * * @param bagName * The name of the bag property to get without namespace prefix. * * @return All values of the bag property in a list. */ public List getUnqualifiedBagValueList(String bagName) { ArrayProperty array = (ArrayProperty) getAbstractProperty(bagName); if (array != null) { return array.getElementsAsString(); } else { return null; } } /** * Remove all matching values from a sequence property. * * @param qualifiedSeqName * The name of the sequence property. It must include the namespace prefix. ie "pdf:Keywords". * @param seqValue * The value to remove from the list. */ public void removeUnqualifiedSequenceValue(String qualifiedSeqName, String seqValue) { removeUnqualifiedArrayValue(qualifiedSeqName, seqValue); } /** * Generic method to remove a field from an array with an Elementable Object * * @param arrayName * the full qualified name of the property concerned * @param fieldValue * the elementable field value */ public void removeUnqualifiedArrayValue(String arrayName, AbstractField fieldValue) { String qualifiedArrayName = arrayName; ArrayProperty array = (ArrayProperty) getAbstractProperty(qualifiedArrayName); if (array != null) { ArrayList toDelete = new ArrayList(); Iterator it = array.getContainer().getAllProperties().iterator(); AbstractSimpleProperty tmp; while (it.hasNext()) { tmp = (AbstractSimpleProperty) it.next(); if (tmp.equals(fieldValue)) { toDelete.add(tmp); } } Iterator eraseProperties = toDelete.iterator(); while (eraseProperties.hasNext()) { array.getContainer().removeProperty(eraseProperties.next()); } } } /** * Remove a value from a sequence property. This will remove all entries from the list. * * @param qualifiedSeqName * The name of the sequence property. It must include the namespace prefix. ie "pdf:Keywords". * @param seqValue * The value to remove from the list. */ public void removeUnqualifiedSequenceValue(String qualifiedSeqName, AbstractField seqValue) { removeUnqualifiedArrayValue(qualifiedSeqName, seqValue); } /** * Add a new value to a sequence property. * * @param simpleSeqName * The name of the sequence property without the namespace prefix * @param seqValue * The value to add to the sequence. */ public void addUnqualifiedSequenceValue(String simpleSeqName, String seqValue) { String qualifiedSeqName = simpleSeqName; ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); TextType li = createTextType(XmpConstants.LIST_NAME, seqValue); if (seq != null) { seq.getContainer().addProperty(li); } else { ArrayProperty newSeq = createArrayProperty(simpleSeqName, Cardinality.Seq); newSeq.getContainer().addProperty(li); addProperty(newSeq); } } /** * Add a new value to a bag property. * * @param qualifiedSeqName * The name of the sequence property, it must include the namespace prefix. ie "pdf:Keywords" * @param seqValue * The value to add to the bag. */ public void addBagValue(String qualifiedSeqName, AbstractField seqValue) { ArrayProperty bag = (ArrayProperty) getAbstractProperty(qualifiedSeqName); if (bag != null) { bag.getContainer().addProperty(seqValue); } else { ArrayProperty newBag = createArrayProperty(qualifiedSeqName, Cardinality.Bag); newBag.getContainer().addProperty(seqValue); addProperty(newBag); } } /** * Add a new value to a sequence property. * * @param seqName * The name of the sequence property, it must include the namespace prefix. ie "pdf:Keywords" * @param seqValue * The value to add to the sequence. */ public void addUnqualifiedSequenceValue(String seqName, AbstractField seqValue) { String qualifiedSeqName = seqName; ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); if (seq != null) { seq.getContainer().addProperty(seqValue); } else { ArrayProperty newSeq = createArrayProperty(seqName, Cardinality.Seq); newSeq.getContainer().addProperty(seqValue); addProperty(newSeq); } } /** * Get all the values in a sequence property. * * @param seqName * The name of the sequence property without namespace prefix. * * @return A read-only list of java.lang.String objects or null if the property does not exist. */ public List getUnqualifiedSequenceValueList(String seqName) { ArrayProperty array = (ArrayProperty) getAbstractProperty(seqName); if (array != null) { return array.getElementsAsString(); } else { return null; } } /** * Remove a date sequence value from the list. * * @param seqName * The name of the sequence property, it must include the namespace prefix. ie "pdf:Keywords" * @param date * The date to remove from the sequence property. */ public void removeUnqualifiedSequenceDateValue(String seqName, Calendar date) { String qualifiedSeqName = seqName; ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); if (seq != null) { ArrayList toDelete = new ArrayList(); Iterator it = seq.getContainer().getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (tmp instanceof DateType) { if (((DateType) tmp).getValue().equals(date)) { toDelete.add(tmp); } } } Iterator eraseProperties = toDelete.iterator(); while (eraseProperties.hasNext()) { seq.getContainer().removeProperty(eraseProperties.next()); } } } /** * Add a date sequence value to the list using the current prefix * * @param simpleName * the local name of the property * @param date * the value to add */ public void addSequenceDateValueAsSimple(String simpleName, Calendar date) { addUnqualifiedSequenceDateValue(simpleName, date); } /** * Add a date sequence value to the list. * * @param seqName * The name of the sequence property, it must include the namespace prefix. ie "pdf:Keywords" * @param date * The date to add to the sequence property. */ public void addUnqualifiedSequenceDateValue(String seqName, Calendar date) { addUnqualifiedSequenceValue( seqName, getMetadata().getTypeMapping().createDate(null, XmpConstants.DEFAULT_RDF_LOCAL_NAME, XmpConstants.LIST_NAME, date)); } /** * Get all the date values in a sequence property. * * @param seqName * The name of the sequence property, it must include the namespace prefix. ie "pdf:Keywords". * * @return A read-only list of java.util.Calendar objects or null if the property does not exist. * */ public List getUnqualifiedSequenceDateValueList(String seqName) { String qualifiedSeqName = seqName; List retval = null; ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); if (seq != null) { retval = new ArrayList(); Iterator it = seq.getContainer().getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (tmp instanceof DateType) { retval.add(((DateType) tmp).getValue()); } } } return retval; } /** * Method used to place the 'x-default' value in first in Language alternatives as said in xmp spec * * @param alt * The property to reorganize */ public void reorganizeAltOrder(ComplexPropertyContainer alt) { Iterator it = alt.getAllProperties().iterator(); AbstractField xdefault = null; boolean xdefaultFound = false; // If alternatives contains x-default in first value if (it.hasNext()) { if (it.next().getAttribute(XmpConstants.LANG_NAME).getValue().equals(XmpConstants.X_DEFAULT)) { return; } } // Find the xdefault definition while (it.hasNext() && !xdefaultFound) { xdefault = it.next(); if (xdefault.getAttribute(XmpConstants.LANG_NAME).getValue().equals(XmpConstants.X_DEFAULT)) { alt.removeProperty(xdefault); xdefaultFound = true; } } if (xdefaultFound) { it = alt.getAllProperties().iterator(); ArrayList reordered = new ArrayList(); ArrayList toDelete = new ArrayList(); reordered.add(xdefault); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); reordered.add(tmp); toDelete.add(tmp); } Iterator eraseProperties = toDelete.iterator(); while (eraseProperties.hasNext()) { alt.removeProperty(eraseProperties.next()); } it = reordered.iterator(); while (it.hasNext()) { alt.addProperty(it.next()); } } } /** * Set the value of a multi-lingual property. * * @param name * The name of the property, it must include the namespace prefix. ie "pdf:Keywords" * @param language * The language code of the value. If null then "x-default" is assumed. * @param value * The value of the property in the specified language. */ public void setUnqualifiedLanguagePropertyValue(String name, String language, String value) { String qualifiedName = name; AbstractField property = getAbstractProperty(qualifiedName); ArrayProperty prop; if (property != null) { // Analyzing content of property if (property instanceof ArrayProperty) { prop = (ArrayProperty) property; Iterator itCplx = prop.getContainer().getAllProperties().iterator(); // try to find the same lang definition AbstractField tmp; // Try to find a definition while (itCplx.hasNext()) { tmp = itCplx.next(); // System.err.println(tmp.getAttribute("xml:lang").getStringValue()); if (tmp.getAttribute(XmpConstants.LANG_NAME).getValue().equals(language)) { // the same language has been found if (value == null) { // if value null, erase this definition prop.getContainer().removeProperty(tmp); } else { prop.getContainer().removeProperty(tmp); TextType langValue; langValue = createTextType(XmpConstants.LIST_NAME, value); langValue.setAttribute(new Attribute(XMLConstants.XML_NS_URI, XmpConstants.LANG_NAME, language)); prop.getContainer().addProperty(langValue); } reorganizeAltOrder(prop.getContainer()); return; } } // if no definition found, we add a new one TextType langValue; langValue = createTextType(XmpConstants.LIST_NAME, value); langValue.setAttribute(new Attribute(XMLConstants.XML_NS_URI, XmpConstants.LANG_NAME, language)); prop.getContainer().addProperty(langValue); reorganizeAltOrder(prop.getContainer()); } } else { prop = createArrayProperty(name, Cardinality.Alt); TextType langValue; langValue = createTextType(XmpConstants.LIST_NAME, value); langValue.setAttribute(new Attribute(XMLConstants.XML_NS_URI, XmpConstants.LANG_NAME, language)); prop.getContainer().addProperty(langValue); addProperty(prop); } } /** * Get the value of a multi-lingual property. * * @param name * The name of the property, without the namespace prefix. * @param expectedLanguage * The language code of the value. If null then "x-default" is assumed. * * @return The value of the language property. */ public String getUnqualifiedLanguagePropertyValue(String name, String expectedLanguage) { String language = (expectedLanguage != null) ? expectedLanguage : XmpConstants.X_DEFAULT; AbstractField property = getAbstractProperty(name); if (property != null) { if (property instanceof ArrayProperty) { ArrayProperty prop = (ArrayProperty) property; Iterator langsDef = prop.getContainer().getAllProperties().iterator(); AbstractField tmp; Attribute text; while (langsDef.hasNext()) { tmp = langsDef.next(); text = tmp.getAttribute(XmpConstants.LANG_NAME); if (text != null) { if (text.getValue().equals(language)) { return ((TextType) tmp).getStringValue(); } } } return null; } else { throw new IllegalArgumentException("The property '" + name + "' is not of Lang Alt type"); } } return null; } /** * Get a list of all languages that are currently defined for a specific property. * * @param name * The name of the property, it must include the namespace prefix. ie "pdf:Keywords" * * @return A list of all languages, this will return an non-null empty list if none have been defined. */ public List getUnqualifiedLanguagePropertyLanguagesValue(String name) { List retval = new ArrayList(); AbstractField property = getAbstractProperty(name); if (property != null) { if (property instanceof ArrayProperty) { ArrayProperty prop = (ArrayProperty) property; Iterator langsDef = prop.getContainer().getAllProperties().iterator(); AbstractField tmp; Attribute text; while (langsDef.hasNext()) { tmp = langsDef.next(); text = tmp.getAttribute(XmpConstants.LANG_NAME); if (text != null) { retval.add(text.getValue()); } else { retval.add(XmpConstants.X_DEFAULT); } } return retval; } else { throw new IllegalArgumentException("The property '" + name + "' is not of Lang Alt type"); } } // no property with that name return null; } /** * A basic schema merge, it merges bags and sequences and replace everything else. * * @param xmpSchema * The schema to merge. * @throws IOException * If there is an error during the merge. */ public void merge(XMPSchema xmpSchema) throws IOException { if (!xmpSchema.getClass().equals(this.getClass())) { throw new IOException("Can only merge schemas of the same type."); } Iterator itAtt = xmpSchema.getAllAttributes().iterator(); Attribute att; while (itAtt.hasNext()) { att = itAtt.next(); if (att.getNamespace().equals(getNamespace())) { setAttribute(att); } } String analyzedPropQualifiedName; Iterator itProp = xmpSchema.getContainer().getAllProperties().iterator(); AbstractField prop; while (itProp.hasNext()) { prop = itProp.next(); if (prop.getPrefix().equals(getPrefix())) { if (prop instanceof ArrayProperty) { analyzedPropQualifiedName = prop.getPropertyName(); Iterator itActualEmbeddedProperties = getAllProperties().iterator(); AbstractField tmpEmbeddedProperty; Iterator itNewValues; TextType tmpNewValue; Iterator itOldValues; TextType tmpOldValue; boolean alreadyPresent = false; while (itActualEmbeddedProperties.hasNext()) { tmpEmbeddedProperty = itActualEmbeddedProperties.next(); if (tmpEmbeddedProperty instanceof ArrayProperty) { if (tmpEmbeddedProperty.getPropertyName().equals(analyzedPropQualifiedName)) { itNewValues = ((ArrayProperty) prop).getContainer().getAllProperties().iterator(); // Merge a complex property while (itNewValues.hasNext()) { tmpNewValue = (TextType) itNewValues.next(); itOldValues = ((ArrayProperty) tmpEmbeddedProperty).getContainer() .getAllProperties().iterator(); while (itOldValues.hasNext() && !alreadyPresent) { tmpOldValue = (TextType) itOldValues.next(); if (tmpOldValue.getStringValue().equals(tmpNewValue.getStringValue())) { alreadyPresent = true; } } if (!alreadyPresent) { ((ArrayProperty) tmpEmbeddedProperty).getContainer().addProperty(tmpNewValue); } } } } } } else { addProperty(prop); } } } } /** * Get an AbstractField list corresponding to the content of an array Return null if the property is unknown * * @param name * the property name whitout namespace; * @return List of property contained in the complex property * @throws BadFieldValueException * Property not contains property (not complex property) */ public List getUnqualifiedArrayList(String name) throws BadFieldValueException { ArrayProperty array = null; Iterator itProp = getAllProperties().iterator(); AbstractField tmp; while (itProp.hasNext()) { tmp = itProp.next(); if (tmp.getPropertyName().equals(name)) { if (tmp instanceof ArrayProperty) { array = (ArrayProperty) tmp; break; } else { throw new BadFieldValueException("Property asked not seems to be an array"); } } } if (array != null) { Iterator it = array.getContainer().getAllProperties().iterator(); List list = new ArrayList(); while (it.hasNext()) { list.add(it.next()); } return list; } return null; } protected AbstractSimpleProperty instanciateSimple(String param, Object value) { TypeMapping tm = getMetadata().getTypeMapping(); return tm.instanciateSimpleField(getClass(), null, getPrefix(), param, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/DublinCoreSchema.java0000644000000000000000000004657612645757426026376 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.Calendar; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.MIMEType; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.Types; /** * Representation of a DublinCore Schema * * @author a183132 * */ @StructuredType(preferedPrefix = "dc", namespace = "http://purl.org/dc/elements/1.1/") public class DublinCoreSchema extends XMPSchema { @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String CONTRIBUTOR = "contributor"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String COVERAGE = "coverage"; @PropertyType(type = Types.Text, card = Cardinality.Seq) public static final String CREATOR = "creator"; @PropertyType(type = Types.Date, card = Cardinality.Seq) public static final String DATE = "date"; @PropertyType(type = Types.LangAlt, card = Cardinality.Simple) public static final String DESCRIPTION = "description"; @PropertyType(type = Types.MIMEType, card = Cardinality.Simple) public static final String FORMAT = "format"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String IDENTIFIER = "identifier"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String LANGUAGE = "language"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String PUBLISHER = "publisher"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String RELATION = "relation"; @PropertyType(type = Types.LangAlt, card = Cardinality.Simple) public static final String RIGHTS = "rights"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String SOURCE = "source"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String SUBJECT = "subject"; @PropertyType(type = Types.LangAlt, card = Cardinality.Simple) public static final String TITLE = "title"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String TYPE = "type"; /** * Constructor of a Dublin Core schema with preferred prefix * * @param metadata * The metadata to attach this schema */ public DublinCoreSchema(XMPMetadata metadata) { super(metadata); } /** * Constructor of a Dublin Core schema with specified prefix * * @param metadata * The metadata to attach this schema * @param ownPrefix * The prefix to assign */ public DublinCoreSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } /** * set contributor(s) to the resource (other than the authors) * * @param properName * Value to set */ public void addContributor(String properName) { addQualifiedBagValue(CONTRIBUTOR, properName); } public void removeContributor(String properName) { removeUnqualifiedBagValue(CONTRIBUTOR, properName); } /** * set the extent or scope of the resource * * @param text * Value to set */ public void setCoverage(String text) { addProperty(createTextType(COVERAGE, text)); } /** * set the extent or scope of the resource * * @param text * Property to set */ public void setCoverageProperty(TextType text) { addProperty(text); } /** * set the autor(s) of the resource * * @param properName * Value to add * @throws InappropriateTypeException */ public void addCreator(String properName) { addUnqualifiedSequenceValue(CREATOR, properName); } public void removeCreator(String name) { removeUnqualifiedSequenceValue(CREATOR, name); } /** * Set date(s) that something interesting happened to the resource * * @param date * Value to add */ public void addDate(Calendar date) { addUnqualifiedSequenceDateValue(DATE, date); } public void removeDate(Calendar date) { removeUnqualifiedSequenceDateValue(DATE, date); } /** * add a textual description of the content of the resource (multiple values may be present for different languages) * * @param lang * language concerned * @param value * Value to add */ public void addDescription(String lang, String value) { setUnqualifiedLanguagePropertyValue(DESCRIPTION, lang, value); } /** * Set the default value for the description. * * @param value * The description of this resource. */ public void setDescription(String value) { addDescription(null, value); } /** * Convenience method for signature compatibility with jempbox * * @see DublinCoreSchema#addDescription(String, String) */ @Deprecated public void setDescription(String language, String description) { addDescription(language, description); } /** * set the file format used when saving the resource. * * @param mimeType * Value to set */ public void setFormat(String mimeType) { addProperty(createTextType(FORMAT, mimeType)); } /** * Set the unique identifier of the resource * * @param text * Value to set */ public void setIdentifier(String text) { addProperty(createTextType(IDENTIFIER, text)); } /** * Set the unique identifier of the resource * * @param text * Property to set */ public void setIdentifierProperty(TextType text) { addProperty(text); } /** * Add language(s) used in this resource * * @param locale * Value to set */ public void addLanguage(String locale) { addQualifiedBagValue(LANGUAGE, locale); } public void removeLanguage(String locale) { removeUnqualifiedBagValue(LANGUAGE, locale); } /** * add publisher(s) * * @param properName * Value to add */ public void addPublisher(String properName) { addQualifiedBagValue(PUBLISHER, properName); } public void removePublisher(String name) { removeUnqualifiedBagValue(PUBLISHER, name); } /** * Add relationships to other documents * * @param text * Value to set */ public void addRelation(String text) { addQualifiedBagValue(RELATION, text); } public void removeRelation(String text) { removeUnqualifiedBagValue(RELATION, text); } /** * add informal rights statement, by language. * * @param lang * Language concerned * @param value * Value to set */ public void addRights(String lang, String value) { setUnqualifiedLanguagePropertyValue(RIGHTS, lang, value); } /** * Convenience method for signature compatibility with jempbox * * @see DublinCoreSchema#addRights(String, String) */ @Deprecated public void setRights(String language, String rights) { addRights(language, rights); } /** * Convenience method for signature compatibility with jempbox. Add default rights * * @see DublinCoreSchema#addRights(String, String) */ @Deprecated public void setRights(String rights) { addRights(null, rights); } /** * Set the unique identifer of the work from which this resource was derived * * @param text * Value to set */ public void setSource(String text) { addProperty(createTextType(SOURCE, text)); } /** * Set the unique identifer of the work from which this resource was derived * * @param text * Property to set */ public void setSourceProperty(TextType text) { addProperty(text); } /** * Set the unique identifer of the work from which this resource was derived * * @param text * Property to set */ public void setFormatProperty(MIMEType text) { addProperty(text); } /** * add descriptive phrases or keywords that specify the topic of the content of the resource * * @param text * Value to add */ public void addSubject(String text) { addQualifiedBagValue(SUBJECT, text); } public void removeSubject(String text) { removeUnqualifiedBagValue(SUBJECT, text); } /** * set the title of the document, or the name given to the resource (by language) * * @param lang * Language concerned * @param value * Value to set */ public void setTitle(String lang, String value) { setUnqualifiedLanguagePropertyValue(TITLE, lang, value); } /** * set default title * * @param value * Value to set */ public void setTitle(String value) { setTitle(null, value); } /** * set the title of the document, or the name given to the resource (by language) * * @see DublinCoreSchema#setTitle(String) * */ public void addTitle(String lang, String value) { setTitle(lang, value); } /** * set the document type (novel, poem, ...) * * @param type * Value to set */ public void addType(String type) { addQualifiedBagValue(TYPE, type); } /** * Return the Bag of contributor(s) * * @return Contributor property */ public ArrayProperty getContributorsProperty() { return (ArrayProperty) getProperty(CONTRIBUTOR); } /** * Return a String list of contributor(s) * * @return List of contributors values */ public List getContributors() { return getUnqualifiedBagValueList(CONTRIBUTOR); } /** * Return the Coverage TextType Property * * @return Coverage property */ public TextType getCoverageProperty() { return (TextType) getProperty(COVERAGE); } /** * Return the value of the coverage * * @return Coverage value */ public String getCoverage() { TextType tt = (TextType) getProperty(COVERAGE); return tt == null ? null : tt.getStringValue(); } /** * Return the Sequence of contributor(s) * * @return Creator property */ public ArrayProperty getCreatorsProperty() { return (ArrayProperty) getProperty(CREATOR); } /** * Return the creator(s) string value * * @return List of creators values */ public List getCreators() { return getUnqualifiedSequenceValueList(CREATOR); } /** * Return the sequence of date(s) * * @return date property */ public ArrayProperty getDatesProperty() { return (ArrayProperty) getProperty(DATE); } /** * Return a calendar list of date * * @return List of dates values */ public List getDates() { return getUnqualifiedSequenceDateValueList(DATE); } /** * Return the Lang alt Description * * @return Description property */ public ArrayProperty getDescriptionProperty() { return (ArrayProperty) getProperty(DESCRIPTION); } /** * Return a list of languages defined in description property * * @return get List of languages defined for description property */ public List getDescriptionLanguages() { return getUnqualifiedLanguagePropertyLanguagesValue(DESCRIPTION); } /** * Return a language value for description property * * @param lang * The language wanted * @return Desription value for specified language */ public String getDescription(String lang) { return getUnqualifiedLanguagePropertyValue(DESCRIPTION, lang); } /** * Get the default value for the description. * * @return The description of this resource. */ public String getDescription() { return getDescription(null); } /** * Return the file format property * * @return the format property */ public TextType getFormatProperty() { return (TextType) getProperty(FORMAT); } /** * return the file format value * * @return the format value */ public String getFormat() { TextType tt = (TextType) getProperty(FORMAT); return tt == null ? null : tt.getStringValue(); } /** * Return the unique identifier property of this resource * * @return the identifier property */ public TextType getIdentifierProperty() { return (TextType) getProperty(IDENTIFIER); } /** * return the unique identifier value of this resource * * @return the unique identifier value */ public String getIdentifier() { TextType tt = (TextType) getProperty(IDENTIFIER); return tt == null ? null : tt.getStringValue(); } /** * Return the bag DC language * * @return language property */ public ArrayProperty getLanguagesProperty() { return (ArrayProperty) getProperty(LANGUAGE); } /** * Return the list of values defined in the DC language * * @return list of languages defined for language property */ public List getLanguages() { return getUnqualifiedBagValueList(LANGUAGE); } /** * Return the bag DC publisher * * @return publisher property */ public ArrayProperty getPublishersProperty() { return (ArrayProperty) getProperty(PUBLISHER); } /** * Return the list of values defined in the DC publisher * * @return list of values for publisher property */ public List getPublishers() { return getUnqualifiedBagValueList(PUBLISHER); } /** * Return the bag DC relation * * @return relation property */ public ArrayProperty getRelationsProperty() { return (ArrayProperty) getProperty(RELATION); } /** * Return the list of values defined in the DC relation * * @return list of values for relation property */ public List getRelations() { return getUnqualifiedBagValueList(RELATION); } /** * Convenience method for signature compatibility with jempbox * * @see DublinCoreSchema#getRelations() */ @Deprecated public List getRelationships() { return getRelations(); } /** * Return the Lang alt Rights * * @return rights property */ public ArrayProperty getRightsProperty() { return (ArrayProperty) getProperty(RIGHTS); } /** * Return a list of languages defined in Right property * * @return list of rights languages values defined */ public List getRightsLanguages() { return getUnqualifiedLanguagePropertyLanguagesValue(RIGHTS); } /** * Return a language value for Right property * * @param lang * language concerned * @return the rights value for specified language */ public String getRights(String lang) { return getUnqualifiedLanguagePropertyValue(RIGHTS, lang); } /** * Return the default value for Right property * * @see DublinCoreSchema#getRights(String) */ public String getRights() { return getRights(null); } /** * Return the source property of this resource * * @return source property */ public TextType getSourceProperty() { return (TextType) getProperty(SOURCE); } /** * return the source value of this resource * * @return value of source property */ public String getSource() { TextType tt = (TextType) getProperty(SOURCE); return tt == null ? null : tt.getStringValue(); } /** * Return the bag DC Subject * * @return the subject property */ public ArrayProperty getSubjectsProperty() { return (ArrayProperty) getProperty(SUBJECT); } /** * Return the list of values defined in the DC Subject * * @return the list of subject values */ public List getSubjects() { return getUnqualifiedBagValueList(SUBJECT); } /** * Return the Lang alt Title * * @return the title property */ public ArrayProperty getTitleProperty() { return (ArrayProperty) getProperty(TITLE); } /** * Return a list of languages defined in Title property * * @return list of languages defined for title property */ public List getTitleLanguages() { return getUnqualifiedLanguagePropertyLanguagesValue(TITLE); } /** * Return a language value for Title property * * @param lang * the language concerned * @return the title value for specified language */ public String getTitle(String lang) { return getUnqualifiedLanguagePropertyValue(TITLE, lang); } /** * Get the default value for the title. * * @return The default title of this resource. */ public String getTitle() { return getTitle(null); } /** * Return the bag DC Type * * @return the type property */ public ArrayProperty getTypesProperty() { return (ArrayProperty) getProperty(TYPE); } /** * Return the list of values defined in the DC Type * * @return the value of type property */ public List getTypes() { return getUnqualifiedBagValueList(TYPE); } public void removeType(String type) { removeUnqualifiedBagValue(TYPE, type); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/AdobePDFSchema.java0000644000000000000000000001332612645757426025677 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.Types; /** * Representation of Adobe PDF Schema * * @author a183132 * */ @StructuredType(preferedPrefix = "pdf", namespace = "http://ns.adobe.com/pdf/1.3/") public class AdobePDFSchema extends XMPSchema { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String KEYWORDS = "Keywords"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String PDF_VERSION = "PDFVersion"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String PRODUCER = "Producer"; /** * Constructor of an Adobe PDF schema with preferred prefix * * @param metadata * The metadata to attach this schema */ public AdobePDFSchema(XMPMetadata metadata) { super(metadata); } /** * Constructor of an Adobe PDF schema with specified prefix * * @param metadata * The metadata to attach this schema * @param ownPrefix * The prefix to assign */ public AdobePDFSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } /** * Set the PDF keywords * * @param value * Value to set */ public void setKeywords(String value) { TextType keywords; keywords = createTextType(KEYWORDS, value); addProperty(keywords); } /** * Set the PDF keywords * * @param keywords * Property to set */ public void setKeywordsProperty(TextType keywords) { addProperty(keywords); } /** * Set the PDFVersion * * @param value * Value to set */ public void setPDFVersion(String value) { TextType version; version = createTextType(PDF_VERSION, value); addProperty(version); } /** * Set the PDFVersion * * @param version * Property to set */ public void setPDFVersionProperty(TextType version) { addProperty(version); } /** * Set the PDFProducer * * @param value * Value to set */ public void setProducer(String value) { TextType producer; producer = createTextType(PRODUCER, value); addProperty(producer); } /** * Set the PDFProducer * * @param producer * Property to set */ public void setProducerProperty(TextType producer) { addProperty(producer); } /** * Give the PDF Keywords property * * @return The property object */ public TextType getKeywordsProperty() { AbstractField tmp = getProperty(KEYWORDS); if (tmp instanceof TextType) { return (TextType) tmp; } return null; } /** * Give the PDF Keywords property value (string) * * @return The property value */ public String getKeywords() { AbstractField tmp = getProperty(KEYWORDS); if (tmp instanceof TextType) { return ((TextType) tmp).getStringValue(); } return null; } /** * Give the PDFVersion property * * @return The property object */ public TextType getPDFVersionProperty() { AbstractField tmp = getProperty(PDF_VERSION); if (tmp instanceof TextType) { return (TextType) tmp; } return null; } /** * Give the PDFVersion property value (string) * * @return The property value */ public String getPDFVersion() { AbstractField tmp = getProperty(PDF_VERSION); if (tmp instanceof TextType) { return ((TextType) tmp).getStringValue(); } return null; } /** * Give the producer property * * @return The property object */ public TextType getProducerProperty() { AbstractField tmp = getProperty(PRODUCER); if (tmp instanceof TextType) { return (TextType) tmp; } return null; } /** * Give the producer property value (string) * * @return The property value */ public String getProducer() { AbstractField tmp = getProperty(PRODUCER); if (tmp instanceof TextType) { return ((TextType) tmp).getStringValue(); } return null; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/PhotoshopSchema.java0000644000000000000000000003746012645757426026323 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.DateType; import org.apache.xmpbox.type.IntegerType; import org.apache.xmpbox.type.LayerType; import org.apache.xmpbox.type.ProperNameType; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.type.URIType; @StructuredType(preferedPrefix = "photoshop", namespace = "http://ns.adobe.com/photoshop/1.0/") public class PhotoshopSchema extends XMPSchema { public PhotoshopSchema(XMPMetadata metadata) { super(metadata); } public PhotoshopSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } public static final String PREFERED_PREFIX = "photoshop"; public static final String PHOTOSHOPURI = "http://ns.adobe.com/photoshop/1.0/"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String ANCESTORID = "AncestorID"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String AUTHORS_POSITION = "AuthorsPosition"; @PropertyType(type = Types.ProperName, card = Cardinality.Simple) public static final String CAPTION_WRITER = "CaptionWriter"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String CATEGORY = "Category"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String CITY = "City"; @PropertyType(type = Types.Integer, card = Cardinality.Simple) public static final String COLOR_MODE = "ColorMode"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String COUNTRY = "Country"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String CREDIT = "Credit"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String DATE_CREATED = "DateCreated"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String DOCUMENT_ANCESTORS = "DocumentAncestors"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String HEADLINE = "Headline"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String HISTORY = "History"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String ICC_PROFILE = "ICCProfile"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String INSTRUCTIONS = "Instructions"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String SOURCE = "Source"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String STATE = "State"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String SUPPLEMENTAL_CATEGORIES = "SupplementalCategories"; @PropertyType(type = Types.Layer, card = Cardinality.Seq) public static final String TEXT_LAYERS = "TextLayers"; private ArrayProperty seqLayer; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String TRANSMISSION_REFERENCE = "TransmissionReference"; @PropertyType(type = Types.Integer, card = Cardinality.Simple) public static final String URGENCY = "Urgency"; public URIType getAncestorIDProperty() { return (URIType) getProperty(ANCESTORID); } public String getAncestorID() { TextType tt = ((TextType) getProperty(ANCESTORID)); return tt == null ? null : tt.getStringValue(); } public void setAncestorID(String text) { URIType tt = (URIType) instanciateSimple(ANCESTORID, text); setAncestorIDProperty(tt); } public void setAncestorIDProperty(URIType text) { addProperty(text); } public TextType getAuthorsPositionProperty() { return (TextType) getProperty(AUTHORS_POSITION); } public String getAuthorsPosition() { TextType tt = ((TextType) getProperty(AUTHORS_POSITION)); return tt == null ? null : tt.getStringValue(); } public void setAuthorsPosition(String text) { TextType tt = (TextType) instanciateSimple(AUTHORS_POSITION, text); setAuthorsPositionProperty(tt); } public void setAuthorsPositionProperty(TextType text) { addProperty(text); } public TextType getCaptionWriterProperty() { return (TextType) getProperty(CAPTION_WRITER); } public String getCaptionWriter() { TextType tt = ((TextType) getProperty(CAPTION_WRITER)); return tt == null ? null : tt.getStringValue(); } public void setCaptionWriter(String text) { ProperNameType tt = (ProperNameType) instanciateSimple(CAPTION_WRITER, text); setCaptionWriterProperty(tt); } public void setCaptionWriterProperty(ProperNameType text) { addProperty(text); } public TextType getCategoryProperty() { return (TextType) getProperty(CATEGORY); } public String getCategory() { TextType tt = ((TextType) getProperty(CATEGORY)); return tt == null ? null : tt.getStringValue(); } public void setCategory(String text) { TextType tt = (TextType) instanciateSimple(CATEGORY, text); setCategoryProperty(tt); } public void setCategoryProperty(TextType text) { addProperty(text); } public TextType getCityProperty() { return (TextType) getProperty(CITY); } public String getCity() { TextType tt = ((TextType) getProperty(CITY)); return tt == null ? null : tt.getStringValue(); } public void setCity(String text) { TextType tt = (TextType) instanciateSimple(CITY, text); setCityProperty(tt); } public void setCityProperty(TextType text) { addProperty(text); } public IntegerType getColorModeProperty() { return (IntegerType) getProperty(COLOR_MODE); } public Integer getColorMode() { IntegerType tt = ((IntegerType) getProperty(COLOR_MODE)); return tt == null ? null : tt.getValue(); } public void setColorMode(String text) { IntegerType tt = (IntegerType) instanciateSimple(COLOR_MODE, text); setColorModeProperty(tt); } public void setColorModeProperty(IntegerType text) { addProperty(text); } public TextType getCountryProperty() { return (TextType) getProperty(COUNTRY); } public String getCountry() { TextType tt = ((TextType) getProperty(COUNTRY)); return tt == null ? null : tt.getStringValue(); } public void setCountry(String text) { TextType tt = (TextType) instanciateSimple(COUNTRY, text); setCountryProperty(tt); } public void setCountryProperty(TextType text) { addProperty(text); } public TextType getCreditProperty() { return (TextType) getProperty(CREDIT); } public String getCredit() { TextType tt = ((TextType) getProperty(CREDIT)); return tt == null ? null : tt.getStringValue(); } public void setCredit(String text) { TextType tt = (TextType) instanciateSimple(CREDIT, text); setCreditProperty(tt); } public void setCreditProperty(TextType text) { addProperty(text); } public DateType getDateCreatedProperty() { return (DateType) getProperty(DATE_CREATED); } public String getDateCreated() { TextType tt = ((TextType) getProperty(DATE_CREATED)); return tt == null ? null : tt.getStringValue(); } public void setDateCreated(String text) { DateType tt = (DateType) instanciateSimple(DATE_CREATED, text); setDateCreatedProperty(tt); } public void setDateCreatedProperty(DateType text) { addProperty(text); } public void addDocumentAncestors(String text) { addQualifiedBagValue(DOCUMENT_ANCESTORS, text); } public ArrayProperty getDocumentAncestorsProperty() { return (ArrayProperty) getProperty(DOCUMENT_ANCESTORS); } public List getDocumentAncestors() { return getUnqualifiedBagValueList(DOCUMENT_ANCESTORS); } public TextType getHeadlineProperty() { return (TextType) getProperty(HEADLINE); } public String getHeadline() { TextType tt = ((TextType) getProperty(HEADLINE)); return tt == null ? null : tt.getStringValue(); } public void setHeadline(String text) { TextType tt = (TextType) instanciateSimple(HEADLINE, text); setHeadlineProperty(tt); } public void setHeadlineProperty(TextType text) { addProperty(text); } public TextType getHistoryProperty() { return (TextType) getProperty(HISTORY); } public String getHistory() { TextType tt = ((TextType) getProperty(HISTORY)); return tt == null ? null : tt.getStringValue(); } public void setHistory(String text) { TextType tt = (TextType) instanciateSimple(HISTORY, text); setHistoryProperty(tt); } public void setHistoryProperty(TextType text) { addProperty(text); } public TextType getICCProfileProperty() { return (TextType) getProperty(ICC_PROFILE); } public String getICCProfile() { TextType tt = ((TextType) getProperty(ICC_PROFILE)); return tt == null ? null : tt.getStringValue(); } public void setICCProfile(String text) { TextType tt = (TextType) instanciateSimple(ICC_PROFILE, text); setICCProfileProperty(tt); } public void setICCProfileProperty(TextType text) { addProperty(text); } public TextType getInstructionsProperty() { return (TextType) getProperty(INSTRUCTIONS); } public String getInstructions() { TextType tt = ((TextType) getProperty(INSTRUCTIONS)); return tt == null ? null : tt.getStringValue(); } public void setInstructions(String text) { TextType tt = (TextType) instanciateSimple(INSTRUCTIONS, text); setInstructionsProperty(tt); } public void setInstructionsProperty(TextType text) { addProperty(text); } public TextType getSourceProperty() { return (TextType) getProperty(SOURCE); } public String getSource() { TextType tt = ((TextType) getProperty(SOURCE)); return tt == null ? null : tt.getStringValue(); } public void setSource(String text) { TextType source = (TextType) instanciateSimple(SOURCE, text); setSourceProperty(source); } public void setSourceProperty(TextType text) { addProperty(text); } public TextType getStateProperty() { return (TextType) getProperty(STATE); } public String getState() { TextType tt = ((TextType) getProperty(STATE)); return tt == null ? null : tt.getStringValue(); } public void setState(String text) { TextType tt = (TextType) instanciateSimple(STATE, text); setStateProperty(tt); } public void setStateProperty(TextType text) { addProperty(text); } public void addSupplementalCategories(String text) { addQualifiedBagValue(SUPPLEMENTAL_CATEGORIES, text); } public void removeSupplementalCategories(String text) { removeUnqualifiedBagValue(SUPPLEMENTAL_CATEGORIES, text); } /** * Add a new supplemental category. * * @param s * The supplemental category. */ public void addSupplementalCategory(String s) { addSupplementalCategories(s); } public void removeSupplementalCategory(String text) { removeSupplementalCategories(text); } public ArrayProperty getSupplementalCategoriesProperty() { return (ArrayProperty) getProperty(SUPPLEMENTAL_CATEGORIES); } public List getSupplementalCategories() { return getUnqualifiedBagValueList(SUPPLEMENTAL_CATEGORIES); } public void addTextLayers(String layerName, String layerText) { if (seqLayer == null) { seqLayer = createArrayProperty(TEXT_LAYERS, Cardinality.Seq); addProperty(seqLayer); } LayerType layer = new LayerType(getMetadata()); layer.setLayerName(layerName); layer.setLayerText(layerText); seqLayer.getContainer().addProperty(layer); } public List getTextLayers() throws BadFieldValueException { List tmp = getUnqualifiedArrayList(TEXT_LAYERS); if (tmp != null) { List layers = new ArrayList(); for (AbstractField abstractField : tmp) { if (abstractField instanceof LayerType) { layers.add((LayerType) abstractField); } else { throw new BadFieldValueException("Layer expected and " + abstractField.getClass().getName() + " found."); } } return layers; } return null; } public TextType getTransmissionReferenceProperty() { return (TextType) getProperty(TRANSMISSION_REFERENCE); } public String getTransmissionReference() { TextType tt = ((TextType) getProperty(TRANSMISSION_REFERENCE)); return tt == null ? null : tt.getStringValue(); } public void setTransmissionReference(String text) { TextType tt = (TextType) instanciateSimple(TRANSMISSION_REFERENCE, text); setTransmissionReferenceProperty(tt); } public void setTransmissionReferenceProperty(TextType text) { addProperty(text); } public IntegerType getUrgencyProperty() { return (IntegerType) getProperty(URGENCY); } public Integer getUrgency() { IntegerType tt = ((IntegerType) getProperty(URGENCY)); return tt == null ? null : tt.getValue(); } public void setUrgency(String s) { IntegerType tt = (IntegerType) instanciateSimple(URGENCY, s); setUrgencyProperty(tt); } public void setUrgency(Integer s) { IntegerType tt = (IntegerType) instanciateSimple(URGENCY, s); setUrgencyProperty(tt); } public void setUrgencyProperty(IntegerType text) { addProperty(text); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XmpSchemaException.java0000644000000000000000000000344512645757426026757 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; /** * Exception thrown when problems occurs in Schema Treatment * * @author a183132 * */ public class XmpSchemaException extends Exception { /** * serial version uid */ private static final long serialVersionUID = -980712488563404867L; /** * Create an instance of XmpSchemaException * * @param message * a description of the encountered problem */ public XmpSchemaException(String message) { super(message); } /** * Create an instance of XmpSchemaException * * @param message * a description of the encountered problem * @param cause * the cause of the exception */ public XmpSchemaException(String message, Throwable cause) { super(message, cause); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPMediaManagementSchema.java0000644000000000000000000004340612645757426027736 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AgentNameType; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.RenditionClassType; import org.apache.xmpbox.type.ResourceRefType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.type.URIType; /** * Representation of XMPMediaManagement Schema * * @author gbailleul * */ @StructuredType(preferedPrefix = "xmpMM", namespace = "http://ns.adobe.com/xap/1.0/mm/") public class XMPMediaManagementSchema extends XMPSchema { /** * Constructor of XMPMediaManagement Schema with preferred prefix * * @param metadata * The metadata to attach this schema */ public XMPMediaManagementSchema(XMPMetadata metadata) { super(metadata); } /** * Constructor of XMPMediaManagementSchema schema with specified prefix * * @param metadata * The metadata to attach this schema * @param ownPrefix * The prefix to assign */ public XMPMediaManagementSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } // -------------------------------- ResourceRef -------------------- @PropertyType(type = Types.ResourceRef, card = Cardinality.Simple) public static final String DERIVED_FROM = "DerivedFrom"; /** * Set ResourceRef property * * @param tt * ResourceRef property to set */ public void setDerivedFromProperty(ResourceRefType tt) { addProperty(tt); } /** * Get ResourceRef property * * @return ResourceRef property */ public ResourceRefType getResourceRefProperty() { return (ResourceRefType) getProperty(DERIVED_FROM); } // --------------------------------------- DocumentID // ---------------------------- @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String DOCUMENTID = "DocumentID"; /** * Set DocumentId value * * @param url * DocumentId value to set */ public void setDocumentID(String url) { URIType tt = (URIType) instanciateSimple(DOCUMENTID, url); setDocumentIDProperty(tt); } /** * Set DocumentId Property * * @param tt * DocumentId Property to set */ public void setDocumentIDProperty(URIType tt) { addProperty(tt); } /** * Get DocumentId property * * @return DocumentId property */ public TextType getDocumentIDProperty() { return (TextType) getProperty(DOCUMENTID); } /** * Get DocumentId value * * @return DocumentId value */ public String getDocumentID() { TextType tt = getDocumentIDProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- Manager // ---------------------------- @PropertyType(type = Types.AgentName, card = Cardinality.Simple) public static final String MANAGER = "Manager"; /** * Set Manager value * * @param value * Manager value to set */ public void setManager(String value) { AgentNameType tt = (AgentNameType) instanciateSimple(MANAGER, value); setManagerProperty(tt); } /** * Set Manager property * * @param tt * Manager property to set */ public void setManagerProperty(AgentNameType tt) { addProperty(tt); } /** * Get Manager property * * @return Manager property */ public TextType getManagerProperty() { return (TextType) getProperty(MANAGER); } /** * Get Manager value * * @return Manager value */ public String getManager() { TextType tt = getManagerProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- ManageTo // ---------------------------- @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String MANAGETO = "ManageTo"; /** * Set ManageTo Value * * @param value * ManageTo Value to set */ public void setManageTo(String value) { URIType tt = (URIType) instanciateSimple(MANAGETO, value); setManageToProperty(tt); } /** * Set ManageTo property * * @param tt * ManageTo property to set */ public void setManageToProperty(URIType tt) { addProperty(tt); } /** * get ManageTo property * * @return ManageTo property */ public TextType getManageToProperty() { return (TextType) getProperty(MANAGETO); } /** * get ManageTo value * * @return ManageTo value */ public String getManageTo() { TextType tt = getManageToProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- ManageUI // ---------------------------- @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String MANAGEUI = "ManageUI"; /** * Set ManageUI value * * @param value * ManageUI value to set */ public void setManageUI(String value) { URIType tt = (URIType) instanciateSimple(MANAGEUI, value); setManageUIProperty(tt); } /** * Set ManageUI property * * @param tt * ManageUI property to set */ public void setManageUIProperty(URIType tt) { addProperty(tt); } /** * Get ManageUI property * * @return ManageUI property */ public TextType getManageUIProperty() { return (TextType) getProperty(MANAGEUI); } /** * Get ManageUI Value * * @return ManageUI Value */ public String getManageUI() { TextType tt = getManageUIProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- ManagerVariant // ---------------------------- @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String MANAGERVARIANT = "ManagerVariant"; /** * Set ManagerVariant value * * @param value * ManagerVariant value to set */ public void setManagerVariant(String value) { TextType tt = (TextType) instanciateSimple(MANAGERVARIANT, value); setManagerVariantProperty(tt); } /** * Set ManagerVariant Property * * @param tt * ManagerVariant Property to set */ public void setManagerVariantProperty(TextType tt) { addProperty(tt); } /** * Get ManagerVariant property * * @return ManagerVariant property */ public TextType getManagerVariantProperty() { return (TextType) getProperty(MANAGERVARIANT); } /** * Get ManagerVariant value * * @return ManagerVariant value */ public String getManagerVariant() { TextType tt = getManagerVariantProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- InstanceID // ---------------------------- @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String INSTANCEID = "InstanceID"; /** * Set InstanceId value * * @param value * InstanceId value to set */ public void setInstanceID(String value) { URIType tt = (URIType) instanciateSimple(INSTANCEID, value); setInstanceIDProperty(tt); } /** * Set InstanceId property * * @param tt * InstanceId property to set */ public void setInstanceIDProperty(URIType tt) { addProperty(tt); } /** * Get InstanceId property * * @return InstanceId property */ public TextType getInstanceIDProperty() { return (TextType) getProperty(INSTANCEID); } /** * Get InstanceId value * * @return InstanceId value */ public String getInstanceID() { TextType tt = getInstanceIDProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- ManageFrom // ---------------------------- @PropertyType(type = Types.ResourceRef, card = Cardinality.Simple) public static final String MANAGED_FROM = "ManagedFrom"; // /** // * set ManageFrom Value // * // * @param url // * ManageFrom Value to set // */ // public void setManagedFrom(ResourceRefType resourceRef) { // // setManagedFromProperty(new TextType(metadata, localPrefix, MANAGED_FROM, // url)); // } /** * set ManageFrom Property * * @param resourceRef * ManageFrom Property to set */ public void setManagedFromProperty(ResourceRefType resourceRef) { addProperty(resourceRef); } /** * get ManageFrom Property * * @return ManageFrom Property */ public ResourceRefType getManagedFromProperty() { return (ResourceRefType) getProperty(MANAGED_FROM); } // /** // * Get ManageFrom value // * // * @return ManageFrom value // */ // public String getManagedFrom() { // TextType tt = getManagedFromProperty(); // return tt != null ? tt.getStringValue() : null; // } // --------------------------------------- OriginalDocumentID // ---------------------------- @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String ORIGINALDOCUMENTID = "OriginalDocumentID"; /** * Set OriginalDocumentId value * * @param url * OriginalDocumentId value to set */ public void setOriginalDocumentID(String url) { TextType tt = (TextType) instanciateSimple(ORIGINALDOCUMENTID, url); setOriginalDocumentIDProperty(tt); } /** * Set OriginalDocumentId property * * @param tt * OriginalDocumentId property to set */ public void setOriginalDocumentIDProperty(TextType tt) { addProperty(tt); } /** * Get OriginalDocumentId property * * @return OriginalDocumentId property */ public TextType getOriginalDocumentIDProperty() { return (TextType) getProperty(ORIGINALDOCUMENTID); } /** * Get OriginalDocumentId value * * @return OriginalDocumentId value */ public String getOriginalDocumentID() { TextType tt = getOriginalDocumentIDProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- RenditionClass // ---------------------------- @PropertyType(type = Types.RenditionClass, card = Cardinality.Simple) public static final String RENDITIONCLASS = "RenditionClass"; /** * Set renditionClass Value * * @param value * renditionClass Value to set */ public void setRenditionClass(String value) { RenditionClassType tt = (RenditionClassType) instanciateSimple(RENDITIONCLASS, value); setRenditionClassProperty(tt); } /** * Set RenditionClass Property * * @param tt * renditionClass Property to set */ public void setRenditionClassProperty(RenditionClassType tt) { addProperty(tt); } /** * Get RenditionClass property * * @return RenditionClass property */ public TextType getRenditionClassProperty() { return (TextType) getProperty(RENDITIONCLASS); } /** * Get RenditionClass value * * @return RenditionClass value */ public String getRenditionClass() { TextType tt = getRenditionClassProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- RenditionParams // ---------------------------- @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String RENDITIONPARAMS = "RenditionParams"; /** * Set RenditionParams Value * * @param url * RenditionParams Value to set */ public void setRenditionParams(String url) { TextType tt = (TextType) instanciateSimple(RENDITIONPARAMS, url); setRenditionParamsProperty(tt); } /** * Set RenditionParams property * * @param tt * RenditionParams property to set */ public void setRenditionParamsProperty(TextType tt) { addProperty(tt); } /** * Get RenditionParams property * * @return RenditionParams property */ public TextType getRenditionParamsProperty() { return (TextType) getProperty(RENDITIONPARAMS); } /** * Get RenditionParams value * * @return RenditionParams value */ public String getRenditionParams() { TextType tt = getRenditionParamsProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- VersionID // ---------------------------- @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String VERSIONID = "VersionID"; /** * Set VersionId value * * @param value * VersionId value to set */ public void setVersionID(String value) { TextType tt = (TextType) instanciateSimple(VERSIONID, value); setVersionIDProperty(tt); } /** * Set VersionId property * * @param tt * VersionId property to set */ public void setVersionIDProperty(TextType tt) { addProperty(tt); } /** * Get VersionId property * * @return VersionId property */ public TextType getVersionIDProperty() { return (TextType) getProperty(VERSIONID); } /** * Get VersionId value * * @return VersionId value */ public String getVersionID() { TextType tt = getVersionIDProperty(); return tt != null ? tt.getStringValue() : null; } // --------------------------------------- Versions // ---------------------------- @PropertyType(type = Types.Version, card = Cardinality.Seq) public static final String VERSIONS = "Versions"; public void addVersions(String value) { addQualifiedBagValue(VERSIONS, value); } /** * Get Versions property * * @return version property to set */ public ArrayProperty getVersionsProperty() { return (ArrayProperty) getProperty(VERSIONS); } public List getVersions() { return getUnqualifiedBagValueList(VERSIONS); } // --------------------------------------- History // ---------------------------- @PropertyType(type = Types.ResourceEvent, card = Cardinality.Seq) public static final String HISTORY = "History"; /** * Add a History Value * * @param history * History Value to add */ public void addHistory(String history) { addUnqualifiedSequenceValue(HISTORY, history); } /** * Get History Property * * @return History Property */ public ArrayProperty getHistoryProperty() { return (ArrayProperty) getProperty(HISTORY); } /** * Get List of History values * * @return List of History values */ public List getHistory() { return getUnqualifiedSequenceValueList(HISTORY); } // --------------------------------------- Ingredients // ---------------------------- @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String INGREDIENTS = "Ingredients"; /** * Add an Ingredients value * * @param ingredients * Ingredients value to add */ public void addIngredients(String ingredients) { addQualifiedBagValue(INGREDIENTS, ingredients); } /** * . Get Ingredients Property * * @return Ingredients property */ public ArrayProperty getIngredientsProperty() { return (ArrayProperty) getProperty(INGREDIENTS); } /** * Get List of Ingredients values * * @return List of Ingredients values */ public List getIngredients() { return getUnqualifiedBagValueList(INGREDIENTS); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/PDFAIdentificationSchema.java0000644000000000000000000002056112645757426027716 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.Attribute; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.IntegerType; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.Types; /** * Representation of PDF/A Identification Schema * * @author a183132 * */ @StructuredType(preferedPrefix = "pdfaid", namespace = "http://www.aiim.org/pdfa/ns/id/") public class PDFAIdentificationSchema extends XMPSchema { @PropertyType(type = Types.Integer, card = Cardinality.Simple) public static final String PART = "part"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String AMD = "amd"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String CONFORMANCE = "conformance"; /* * * B 1 */ /** * Constructor of a PDF/A Identification schema * * @param metadata * The metadata to attach this schema */ public PDFAIdentificationSchema(XMPMetadata metadata) { super(metadata); } public PDFAIdentificationSchema(XMPMetadata metadata, String prefix) { super(metadata, prefix); } /** * Set the PDFA Version identifier (with string) * * @param value * The version Id value to set * */ public void setPartValueWithString(String value) { IntegerType part = (IntegerType) instanciateSimple(PART, value); addProperty(part); } /** * Set the PDFA Version identifier (with an int) * * @param value * The version Id value to set */ public void setPartValueWithInt(int value) { IntegerType part = (IntegerType) instanciateSimple(PART, value); addProperty(part); } /** * Set the PDF/A Version identifier (with an int) * * @param value * The version Id property to set */ public void setPart(Integer value) { setPartValueWithInt(value.intValue()); } /** * Set the PDF/A Version identifier * * @param part * set the PDF/A Version id property */ public void setPartProperty(IntegerType part) { addProperty(part); } /** * Set the PDF/A amendment identifier * * @param value * The amendment identifier value to set */ public void setAmd(String value) { TextType amd = createTextType(AMD, value); addProperty(amd); } /** * Set the PDF/A amendment identifier * * @param amd * The amendment identifier property to set */ public void setAmdProperty(TextType amd) { addProperty(amd); } /** * Set the PDF/A conformance level * * @param value * The conformance level value to set * @throws BadFieldValueException * If Conformance Value not 'A' or 'B' */ public void setConformance(String value) throws BadFieldValueException { if (value.equals("A") || value.equals("B")) { TextType conf = createTextType(CONFORMANCE, value); addProperty(conf); } else { throw new BadFieldValueException( "The property given not seems to be a PDF/A conformance level (must be A or B)"); } } /** * Set the PDF/A conformance level * * @param conf * The conformance level property to set * @throws BadFieldValueException * If Conformance Value not 'A' or 'B' */ public void setConformanceProperty(TextType conf) throws BadFieldValueException { String value = conf.getStringValue(); if (value.equals("A") || value.equals("B")) { addProperty(conf); } else { throw new BadFieldValueException( "The property given not seems to be a PDF/A conformance level (must be A or B)"); } } /** * Give the PDFAVersionId (as an integer) * * @return Part value (Integer) */ public Integer getPart() { AbstractField tmp = getPartProperty(); if (tmp instanceof IntegerType) { return ((IntegerType) tmp).getValue(); } else { for (Attribute attribute : getAllAttributes()) { if (attribute.getName().equals(PART)) { return Integer.valueOf(attribute.getValue()); } } return null; } } /** * Give the property corresponding to the PDFA Version id * * @return Part property */ public IntegerType getPartProperty() { AbstractField tmp = getProperty(PART); if (tmp instanceof IntegerType) { return (IntegerType) tmp; } return null; } /** * Give the PDFAAmendmentId (as an String) * * @return Amendment value */ public String getAmendment() { AbstractField tmp = getProperty(AMD); if (tmp instanceof TextType) { return ((TextType) tmp).getStringValue(); } return null; } /** * Give the property corresponding to the PDFA Amendment id * * @return Amendment property */ public TextType getAmdProperty() { AbstractField tmp = getProperty(AMD); if (tmp instanceof TextType) { return (TextType) tmp; } return null; } /** * Give the PDFA Amendment Id (as an String) * * @return Amendment Value */ public String getAmd() { TextType tmp = getAmdProperty(); if (tmp == null) { for (Attribute attribute : getAllAttributes()) { if (attribute.getName().equals(AMD)) { return attribute.getValue(); } } return null; } else { return tmp.getStringValue(); } } /** * Give the property corresponding to the PDFA Conformance id * * @return conformance property */ public TextType getConformanceProperty() { AbstractField tmp = getProperty(CONFORMANCE); if (tmp instanceof TextType) { return (TextType) tmp; } return null; } /** * Give the Conformance id * * @return conformance id value */ public String getConformance() { TextType tt = getConformanceProperty(); if (tt == null) { for (Attribute attribute : getAllAttributes()) { if (attribute.getName().equals(CONFORMANCE)) { return attribute.getValue(); } } return null; } else { return tt.getStringValue(); } } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPBasicSchema.java0000644000000000000000000003677512645757426025756 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.AgentNameType; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.DateType; import org.apache.xmpbox.type.IntegerType; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.ThumbnailType; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.type.URLType; /** * Representation of XMPBasic Schema * * @author a183132 * */ @StructuredType(preferedPrefix = "xmp", namespace = "http://ns.adobe.com/xap/1.0/") public class XMPBasicSchema extends XMPSchema { @PropertyType(type = Types.XPath, card = Cardinality.Bag) public static final String ADVISORY = "Advisory"; @PropertyType(type = Types.URL, card = Cardinality.Simple) public static final String BASEURL = "BaseURL"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String CREATEDATE = "CreateDate"; @PropertyType(type = Types.AgentName, card = Cardinality.Simple) public static final String CREATORTOOL = "CreatorTool"; @PropertyType(type = Types.Text, card = Cardinality.Bag) public static final String IDENTIFIER = "Identifier"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String LABEL = "Label"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String METADATADATE = "MetadataDate"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String MODIFYDATE = "ModifyDate"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String NICKNAME = "Nickname"; @PropertyType(type = Types.Integer, card = Cardinality.Simple) public static final String RATING = "Rating"; @PropertyType(type = Types.Thumbnail, card = Cardinality.Alt) public static final String THUMBNAILS = "Thumbnails"; private ArrayProperty altThumbs; /** * Constructor of XMPBasic schema with preferred prefix * * @param metadata * The metadata to attach this schema */ public XMPBasicSchema(XMPMetadata metadata) { super(metadata); } /** * Constructor of XMPBasic schema with specified prefix * * @param metadata * The metadata to attach this schema * @param ownPrefix * The prefix to assign */ public XMPBasicSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } /** * Add thumbnail to thumbnails list * * @param height * height format * @param width * width format * @param format * thumbnail format * @param img * Image data */ public void addThumbnails(Integer height, Integer width, String format, String img) { if (altThumbs == null) { altThumbs = createArrayProperty(THUMBNAILS, Cardinality.Alt); addProperty(altThumbs); } ThumbnailType thumb = new ThumbnailType(getMetadata()); thumb.setHeight(height); thumb.setWidth(width); thumb.setFormat(format); thumb.setImage(img); altThumbs.getContainer().addProperty(thumb); } /** * Add a property specification that were edited outside the authoring application * * @param xpath * the value to add */ public void addAdvisory(String xpath) { addQualifiedBagValue(ADVISORY, xpath); } public void removeAdvisory(String xpath) { removeUnqualifiedBagValue(ADVISORY, xpath); } /** * Set the base URL for relative URLs in the document content * * @param url * the Base url value to set */ public void setBaseURL(String url) { URLType tt = (URLType) instanciateSimple(BASEURL, url); setBaseURLProperty(tt); } /** * Set the base URL property * * @param url * the Base url property to set */ public void setBaseURLProperty(URLType url) { addProperty(url); } /** * Set the date and time the resource was originally created * * @param date * the value to set */ public void setCreateDate(Calendar date) { DateType tt = (DateType) instanciateSimple(CREATEDATE, date); setCreateDateProperty(tt); } /** * Set the create date property * * @param date * the create date property to set */ public void setCreateDateProperty(DateType date) { addProperty(date); } /** * set the name of the first known tool used to create this resource * * @param creatorTool * the creator tool value to set */ public void setCreatorTool(String creatorTool) { AgentNameType tt = (AgentNameType) instanciateSimple(CREATORTOOL, creatorTool); setCreatorToolProperty(tt); } /** * set the creatorTool property * * @param creatorTool * the creator tool property to set */ public void setCreatorToolProperty(AgentNameType creatorTool) { addProperty(creatorTool); } /** * Add a text string which unambiguously identify the resource within a given context * * @param text * the identifier value to add */ public void addIdentifier(String text) { addQualifiedBagValue(IDENTIFIER, text); } public void removeIdentifier(String text) { removeUnqualifiedBagValue(IDENTIFIER, text); } /** * set a word or a short phrase which identifies a document as a member of a user-defined collection * * @param text * the label value to set */ public void setLabel(String text) { TextType tt = (TextType) instanciateSimple(LABEL, text); setLabelProperty(tt); } /** * set the label property * * @param text * the label property to set */ public void setLabelProperty(TextType text) { addProperty(text); } /** * Set the date and time that any metadata for this resource was last changed. (should be equals or more recent than * the createDate) * * @param date * the Metadata Date value to set */ public void setMetadataDate(Calendar date) { DateType tt = (DateType) instanciateSimple(METADATADATE, date); setMetadataDateProperty(tt); } /** * Set the MetadataDate property * * @param date * the Metadata Date property to set */ public void setMetadataDateProperty(DateType date) { addProperty(date); } /** * Set the date and time the resource was last modified * * @param date * the Modify Date value to set */ public void setModifyDate(Calendar date) { DateType tt = (DateType) instanciateSimple(MODIFYDATE, date); setModifyDateProperty(tt); } /** * Set the ModifyDate property * * @param date * the Modify Date property to set */ public void setModifyDateProperty(DateType date) { addProperty(date); } /** * Set a short informal name for the resource * * @param text * the Nickname value to set */ public void setNickname(String text) { TextType tt = (TextType) instanciateSimple(NICKNAME, text); setNicknameProperty(tt); } /** * Set the NickName property * * @param text * the Nickname property to set */ public void setNicknameProperty(TextType text) { addProperty(text); } /** * Set a number that indicates a document's status relative to other documents, used to organize documents in a file * browser (values are user-defined within an application-defined range) * * @param rate * the rate value to set */ public void setRating(Integer rate) { // addProperty(new IntegerType(metadata, localPrefix, RATING, rate)); IntegerType tt = (IntegerType) instanciateSimple(RATING, rate); setRatingProperty(tt); } /** * Set Rating Property * * @param rate * the rate property to set */ public void setRatingProperty(IntegerType rate) { addProperty(rate); } /** * Get the Advisory property * * @return the advisory property */ public ArrayProperty getAdvisoryProperty() { return (ArrayProperty) getProperty(ADVISORY); } /** * Get the Advisory property values * * @return list of adivory values */ public List getAdvisory() { return getUnqualifiedBagValueList(ADVISORY); } /** * Convenience method for jempbox signature compatibility * * @see XMPBasicSchema#getAdvisory() */ @Deprecated public List getAdvisories() { return getAdvisory(); } /** * Get the BaseURL property * * @return the base url property */ public TextType getBaseURLProperty() { return (TextType) getProperty(BASEURL); } /** * Get the BaseURL property value * * @return the base url value */ public String getBaseURL() { TextType tt = ((TextType) getProperty(BASEURL)); return tt == null ? null : tt.getStringValue(); } /** * Get the CreateDate property * * @return the CreateDate property */ public DateType getCreateDateProperty() { return (DateType) getProperty(CREATEDATE); } /** * Get the CreateDate property value * * @return the CreateDate value */ public Calendar getCreateDate() { DateType createDate = (DateType) getProperty(CREATEDATE); if (createDate != null) { return createDate.getValue(); } return null; } /** * Get the CreationTool property * * @return the CreationTool property */ public TextType getCreatorToolProperty() { return (TextType) getProperty(CREATORTOOL); } /** * Get the CreationTool property value * * @return the CreationTool value */ public String getCreatorTool() { TextType tt = ((TextType) getProperty(CREATORTOOL)); return tt == null ? null : tt.getStringValue(); } /** * Get the Identifier property * * @return the Identifier property */ public ArrayProperty getIdentifiersProperty() { return (ArrayProperty) getProperty(IDENTIFIER); } /** * Get the Identifier property values * * @return list of all identifier values */ public List getIdentifiers() { return getUnqualifiedBagValueList(IDENTIFIER); } /** * Get the label property * * @return the label property */ public TextType getLabelProperty() { return (TextType) getProperty(LABEL); } /** * Get the label property value * * @return the label value */ public String getLabel() { TextType tt = ((TextType) getProperty(LABEL)); return tt == null ? null : tt.getStringValue(); } /** * Get the MetadataDate property * * @return the MetadataDate property */ public DateType getMetadataDateProperty() { return (DateType) getProperty(METADATADATE); } /** * Get the MetadataDate property value * * @return the MetadataDate value */ public Calendar getMetadataDate() { DateType dt = ((DateType) getProperty(METADATADATE)); return dt == null ? null : dt.getValue(); } /** * Get the ModifyDate property * * @return the ModifyDate property */ public DateType getModifyDateProperty() { return (DateType) getProperty(MODIFYDATE); } /** * Get the ModifyDate property value * * @return the ModifyDate value */ public Calendar getModifyDate() { DateType modifyDate = (DateType) getProperty(MODIFYDATE); if (modifyDate != null) { return modifyDate.getValue(); } return null; } /** * Get the Nickname property * * @return the Nickname property */ public TextType getNicknameProperty() { return (TextType) getProperty(NICKNAME); } /** * Get the Nickname property value * * @return the Nickname value */ public String getNickname() { TextType tt = ((TextType) getProperty(NICKNAME)); return tt == null ? null : tt.getStringValue(); } /** * Get the Rating property * * @return the Rating property */ public IntegerType getRatingProperty() { return ((IntegerType) getProperty(RATING)); } /** * Get the Rating property value * * @return the Rating value */ public Integer getRating() { IntegerType it = ((IntegerType) getProperty(RATING)); return it == null ? null : it.getValue(); } /** * Get list of Thumbnails * * @return List of all thumbnails properties defined * @throws BadFieldValueException * if one thumbnail is not thumbnail type */ public List getThumbnailsProperty() throws BadFieldValueException { List tmp = getUnqualifiedArrayList(THUMBNAILS); if (tmp != null) { List thumbs = new ArrayList(); for (AbstractField abstractField : tmp) { if (abstractField instanceof ThumbnailType) { thumbs.add((ThumbnailType) abstractField); } else { throw new BadFieldValueException("Thumbnail expected and " + abstractField.getClass().getName() + " found."); } } return thumbs; } return null; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPBasicJobTicketSchema.java0000644000000000000000000000714512645757426027542 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.JobType; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.Types; @StructuredType(preferedPrefix = "xmpBJ", namespace = "http://ns.adobe.com/xap/1.0/bj/") public class XMPBasicJobTicketSchema extends XMPSchema { @PropertyType(type = Types.Job, card = Cardinality.Bag) public static final String JOB_REF = "JobRef"; private ArrayProperty bagJobs; public XMPBasicJobTicketSchema(XMPMetadata metadata) { this(metadata, null); } public XMPBasicJobTicketSchema(XMPMetadata metadata, String ownPrefix) { super(metadata, ownPrefix); } public void addJob(String id, String name, String url) { addJob(id, name, url, null); } public void addJob(String id, String name, String url, String fieldPrefix) { JobType job = new JobType(getMetadata(), fieldPrefix); job.setId(id); job.setName(name); job.setUrl(url); addJob(job); } public void addJob(JobType job) { String prefix = getNamespacePrefix(job.getNamespace()); if (prefix != null) { // use same prefix for all jobs job.setPrefix(prefix); } else { // add prefix addNamespace(job.getNamespace(), job.getPrefix()); } // create bag if not existing if (bagJobs == null) { bagJobs = createArrayProperty(JOB_REF, Cardinality.Bag); addProperty(bagJobs); } // add job bagJobs.getContainer().addProperty(job); } public List getJobs() throws BadFieldValueException { List tmp = getUnqualifiedArrayList(JOB_REF); if (tmp != null) { List layers = new ArrayList(); for (AbstractField abstractField : tmp) { if (abstractField instanceof JobType) { layers.add((JobType) abstractField); } else { throw new BadFieldValueException("Job expected and " + abstractField.getClass().getName() + " found."); } } return layers; } return null; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/PDFAExtensionSchema.java0000644000000000000000000000417312645757426026742 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.Types; /** * Representation of a PDF/A Extension schema description schema * * @author a183132 * */ @StructuredType(preferedPrefix = "pdfaExtension", namespace = "http://www.aiim.org/pdfa/ns/extension/") public class PDFAExtensionSchema extends XMPSchema { @PropertyType(type = Types.PDFASchema, card = Cardinality.Bag) public static final String SCHEMAS = "schemas"; /** * Build a new PDFExtension schema * * @param metadata * The metadata to attach this schema XMPMetadata */ public PDFAExtensionSchema(XMPMetadata metadata) { super(metadata); } public PDFAExtensionSchema(XMPMetadata metadata, String prefix) { super(metadata, prefix); } /** * * @return the list of subject values */ public ArrayProperty getSchemasProperty() { return (ArrayProperty) getProperty(SCHEMAS); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPSchemaFactory.java0000644000000000000000000001021612645757426026322 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.lang.reflect.Constructor; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.PropertiesDescription; import org.apache.xmpbox.type.PropertyType; /** * A factory for each kind of schemas * * @author a183132 * */ public class XMPSchemaFactory { private String namespace; private Class schemaClass; private PropertiesDescription propDef; private String nsName; /** * Factory Constructor for basic known schemas * * @param namespace * namespace URI to treat * @param schemaClass * Class representation associated to this URI * @param propDef * Properties Types list associated */ public XMPSchemaFactory(String namespace, Class schemaClass, PropertiesDescription propDef) { this.namespace = namespace; this.schemaClass = schemaClass; this.propDef = propDef; } /** * Get namespace URI treated by this factory * * @return The namespace URI */ public String getNamespace() { return namespace; } /** * Get type declared for the name property given * * @param name * The property name * @return null if propery name is unknown */ public PropertyType getPropertyType(String name) { return propDef.getPropertyType(name); } /** * Create a schema that corresponding to this factory and add it to metadata * * @param metadata * Metadata to attach the Schema created * @param prefix * The namespace prefix (optional) * @return the schema created and added to metadata * @throws XmpSchemaException * When Instancing specified Object Schema failed */ public XMPSchema createXMPSchema(XMPMetadata metadata, String prefix) throws XmpSchemaException { XMPSchema schema = null; Class[] argsClass; Object[] schemaArgs; if (schemaClass == XMPSchema.class) { argsClass = new Class[] { XMPMetadata.class, String.class, String.class }; schemaArgs = new Object[] { metadata, namespace, nsName }; } else if (prefix != null && !"".equals(prefix)) { argsClass = new Class[] { XMPMetadata.class, String.class }; schemaArgs = new Object[] { metadata, prefix }; } else { argsClass = new Class[] { XMPMetadata.class }; schemaArgs = new Object[] { metadata }; } Constructor schemaConstructor; try { schemaConstructor = schemaClass.getConstructor(argsClass); schema = schemaConstructor.newInstance(schemaArgs); if (schema != null) { metadata.addSchema(schema); } return schema; } catch (Exception e) { throw new XmpSchemaException("Cannot Instanciate specified Object Schema", e); } } public PropertiesDescription getPropertyDefinition() { return this.propDef; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/XmpConstants.java0000644000000000000000000000400112645757426024401 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; public final class XmpConstants { public static final String RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; public static final String DEFAULT_XPACKET_BEGIN = "\uFEFF"; public static final String DEFAULT_XPACKET_ID = "W5M0MpCehiHzreSzNTczkc9d"; public static final String DEFAULT_XPACKET_ENCODING = "UTF-8"; public static final String DEFAULT_XPACKET_BYTES = null; public static final String DEFAULT_XPACKET_END = "w"; public static final String DEFAULT_RDF_PREFIX = "rdf"; public static final String DEFAULT_RDF_LOCAL_NAME = "RDF"; public static final String LIST_NAME = "li"; public static final String LANG_NAME = "lang"; public static final String ABOUT_NAME = "about"; public static final String DESCRIPTION_NAME = "Description"; public static final String RESOURCE_NAME = "Resource"; public static final String PARSE_TYPE = "parseType"; public static final String X_DEFAULT = "x-default"; private XmpConstants() { // hide constructor } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java0000644000000000000000000002402412645757426024514 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.SimpleTimeZone; /** * This class is used to convert dates to strings and back using the PDF date standards. Date are described in * PDFReference1.4 section 3.8.2 * * @author Ben Litchfield * @author Christopher Oezbek * * @version $Revision: 1.3 $ */ public class DateConverter { // The Date format is supposed to be the PDF_DATE_FORMAT, but not all PDF // documents // will use that date, so I have added a couple other potential formats // to try if the original one does not work. private static final SimpleDateFormat[] POTENTIAL_FORMATS = new SimpleDateFormat[] { new SimpleDateFormat("EEEE, dd MMM yyyy hh:mm:ss a"), new SimpleDateFormat("EEEE, MMM dd, yyyy hh:mm:ss a"), new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"), new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz") }; /** * According to check-style, Utility classes should not have a public or default constructor. */ protected DateConverter() { }; /** * This will convert a string to a calendar. * * @param date * The string representation of the calendar. * * @return The calendar that this string represents. * * @throws IOException * If the date string is not in the correct format. */ public static Calendar toCalendar(String date) throws IOException { Calendar retval = null; if ((date != null) && (date.trim().length() > 0)) { // these are the default values int year = 0; int month = 1; int day = 1; int hour = 0; int minute = 0; int second = 0; // first string off the prefix if it exists try { SimpleTimeZone zone = null; if (date.startsWith("D:")) { date = date.substring(2, date.length()); } date = date.replaceAll("[-:T]", ""); if (date.length() < 4) { throw new IOException("Error: Invalid date format '" + date + "'"); } year = Integer.parseInt(date.substring(0, 4)); if (date.length() >= 6) { month = Integer.parseInt(date.substring(4, 6)); } if (date.length() >= 8) { day = Integer.parseInt(date.substring(6, 8)); } if (date.length() >= 10) { hour = Integer.parseInt(date.substring(8, 10)); } if (date.length() >= 12) { minute = Integer.parseInt(date.substring(10, 12)); } int timeZonePos = 12; if (date.length() - 12 > 5 || (date.length() - 12 == 3 && date.endsWith("Z"))) { if (date.length() >= 14) { second = Integer.parseInt(date.substring(12, 14)); } timeZonePos = 14; } else { second = 0; } if (date.length() >= (timeZonePos + 1)) { char sign = date.charAt(timeZonePos); if (sign == 'Z') { zone = new SimpleTimeZone(0, "Unknown"); } else { int hours = 0; int minutes = 0; if (date.length() >= (timeZonePos + 3)) { if (sign == '+') { // parseInt cannot handle the + sign hours = Integer.parseInt(date.substring((timeZonePos + 1), (timeZonePos + 3))); } else { hours = -Integer.parseInt(date.substring(timeZonePos, (timeZonePos + 2))); } } if (sign == '+') { if (date.length() >= (timeZonePos + 5)) { minutes = Integer.parseInt(date.substring((timeZonePos + 3), (timeZonePos + 5))); } } else { if (date.length() >= (timeZonePos + 4)) { minutes = Integer.parseInt(date.substring((timeZonePos + 2), (timeZonePos + 4))); } } zone = new SimpleTimeZone(hours * 60 * 60 * 1000 + minutes * 60 * 1000, "Unknown"); } } if (zone == null) { retval = new GregorianCalendar(); } else { retval = new GregorianCalendar(zone); } retval.clear(); retval.set(year, month - 1, day, hour, minute, second); } catch (NumberFormatException e) { // remove the arbitrary : in the timezone. SimpleDateFormat // can't handle it if (date.substring(date.length() - 3, date.length() - 2).equals(":") && (date.substring(date.length() - 6, date.length() - 5).equals("+") || date.substring( date.length() - 6, date.length() - 5).equals("-"))) { // thats a timezone string, remove the : date = date.substring(0, date.length() - 3) + date.substring(date.length() - 2); } for (int i = 0; (retval == null) && (i < POTENTIAL_FORMATS.length); i++) { try { Date utilDate = POTENTIAL_FORMATS[i].parse(date); retval = new GregorianCalendar(); retval.setTime(utilDate); } catch (ParseException pe) { // ignore and move to next potential format } } if (retval == null) { // we didn't find a valid date format so throw an exception IOException ioe = new IOException("Error converting date:" + date); ioe.initCause(e); throw ioe; } } } return retval; } /** * Append Zero to String Buffer before number < 10 ('1' become '01') * * @param out * The String buffer * @param number * The concerned number */ private static void zeroAppend(StringBuffer out, int number) { if (number < 10) { out.append("0"); } out.append(number); } /** * Convert the date to iso 8601 string format. * * @param cal * The date to convert. * @return The date represented as an ISO 8601 string. */ public static String toISO8601(Calendar cal) { StringBuffer retval = new StringBuffer(); retval.append(cal.get(Calendar.YEAR)); retval.append("-"); zeroAppend(retval, cal.get(Calendar.MONTH) + 1); retval.append("-"); zeroAppend(retval, cal.get(Calendar.DAY_OF_MONTH)); retval.append("T"); zeroAppend(retval, cal.get(Calendar.HOUR_OF_DAY)); retval.append(":"); zeroAppend(retval, cal.get(Calendar.MINUTE)); retval.append(":"); zeroAppend(retval, cal.get(Calendar.SECOND)); int timeZone = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); if (timeZone < 0) { retval.append("-"); } else { retval.append("+"); } timeZone = Math.abs(timeZone); // milliseconds/1000 = seconds = seconds / 60 = minutes = minutes/60 = // hours int hours = timeZone / 1000 / 60 / 60; int minutes = (timeZone - (hours * 1000 * 60 * 60)) / 1000 / 1000; if (hours < 10) { retval.append("0"); } retval.append(Integer.toString(hours)); retval.append(":"); if (minutes < 10) { retval.append("0"); } retval.append(Integer.toString(minutes)); return retval.toString(); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/0000755000000000000000000000000012645757426021702 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpSerializationException.java0000644000000000000000000000337312645757426027734 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.xml; /** * Exception when Parsing cannot be made * * @author a183132 * */ public class XmpSerializationException extends Exception { private static final long serialVersionUID = -3495894314480173555L; /** * Create an instance of TransformException * * @param message * a description of the encountered problem */ public XmpSerializationException(String message) { super(message); } /** * Create an instance of TransformException * * @param message * a description of the encountered problem * @param cause * the cause of the exception */ public XmpSerializationException(String message, Throwable cause) { super(message, cause); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpParsingException.java0000644000000000000000000000474212645757426026523 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.xml; /** * Exception thrown when Parsing failed * * @author a183132 * */ public class XmpParsingException extends Exception { public enum ErrorType { Undefined, Configuration, XpacketBadStart, XpacketBadEnd, NoRootElement, NoSchema, // undefined // schema InvalidPdfaSchema, NoType, // undefined type InvalidType, Format, // weird things in serialized document NoValueType, RequiredProperty, InvalidPrefix, // unexpected namespace // prefix used } private ErrorType errorType; /** * serial version uid */ private static final long serialVersionUID = -8843096358184702908L; /** * Create an instance of XmpParsingException * * @param message * a description of the encountered problem * @param cause * the cause of the exception */ public XmpParsingException(ErrorType error, String message, Throwable cause) { super(message, cause); this.errorType = error; } /** * Create an instance of XmpParsingException * * @param message * a description of the encountered problem */ public XmpParsingException(ErrorType error, String message) { super(message); this.errorType = error; } public ErrorType getErrorType() { return errorType; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/DomHelper.java0000644000000000000000000000743412645757426024434 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.xml; import java.util.ArrayList; import java.util.List; import javax.xml.namespace.QName; import org.apache.xmpbox.XmpConstants; import org.apache.xmpbox.xml.XmpParsingException.ErrorType; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public final class DomHelper { private DomHelper() { } public static Element getUniqueElementChild(Element description) throws XmpParsingException { NodeList nl = description.getChildNodes(); int pos = -1; for (int i = 0; i < nl.getLength(); i++) { if (nl.item(i) instanceof Element) { if (pos >= 0) { // invalid : found two child elements throw new XmpParsingException(ErrorType.Undefined, "Found two child elements in " + description); } else { pos = i; } } } return (Element) nl.item(pos); } /** * Return the first child element of the element parameter. If there is no child, null is returned * * @param description * @return the first child element. Might be null. * @throws XmpParsingException */ public static Element getFirstChildElement(Element description) throws XmpParsingException { NodeList nl = description.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { if (nl.item(i) instanceof Element) { return (Element) nl.item(i); } } return null; } public static List getElementChildren(Element description) throws XmpParsingException { NodeList nl = description.getChildNodes(); List ret = new ArrayList(nl.getLength()); for (int i = 0; i < nl.getLength(); i++) { if (nl.item(i) instanceof Element) { ret.add((Element) nl.item(i)); } } return ret; } public static QName getQName(Element element) { return new QName(element.getNamespaceURI(), element.getLocalName(), element.getPrefix()); } public static boolean isRdfDescription(Element element) { return (XmpConstants.DEFAULT_RDF_PREFIX.equals(element.getPrefix()) && XmpConstants.DESCRIPTION_NAME .equals(element.getLocalName())); } public static boolean isParseTypeResource(Element element) { Attr parseType = element.getAttributeNodeNS(XmpConstants.RDF_NAMESPACE, XmpConstants.PARSE_TYPE); if (parseType != null && XmpConstants.RESOURCE_NAME.equals(parseType.getValue())) { // parseType resourc return true; } // else return false; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/PdfaExtensionHelper.java0000644000000000000000000003434512645757426026465 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.xml; import java.util.List; import java.util.Map; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.PDFAExtensionSchema; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.schema.XMPSchemaFactory; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.AbstractStructuredType; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.DefinedStructuredType; import org.apache.xmpbox.type.PDFAFieldType; import org.apache.xmpbox.type.PDFAPropertyType; import org.apache.xmpbox.type.PDFASchemaType; import org.apache.xmpbox.type.PDFATypeType; import org.apache.xmpbox.type.PropertiesDescription; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TypeMapping; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.xml.XmpParsingException.ErrorType; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; public final class PdfaExtensionHelper { public static final String CLOSED_CHOICE = "closed Choice of "; public static final String OPEN_CHOICE = "open Choice of "; private PdfaExtensionHelper() { } public static void validateNaming(XMPMetadata meta, Element description) throws XmpParsingException { NamedNodeMap nnm = description.getAttributes(); for (int i = 0; i < nnm.getLength(); i++) { Attr attr = (Attr) nnm.item(i); checkNamespaceDeclaration(attr, PDFAExtensionSchema.class); checkNamespaceDeclaration(attr, PDFAFieldType.class); checkNamespaceDeclaration(attr, PDFAPropertyType.class); checkNamespaceDeclaration(attr, PDFASchemaType.class); checkNamespaceDeclaration(attr, PDFATypeType.class); } } private static void checkNamespaceDeclaration(Attr attr, Class clz) throws XmpParsingException { String prefix = attr.getLocalName(); String namespace = attr.getValue(); String cprefix = clz.getAnnotation(StructuredType.class).preferedPrefix(); String cnamespace = clz.getAnnotation(StructuredType.class).namespace(); // check extension if (cprefix.equals(prefix) && !cnamespace.equals(namespace)) { throw new XmpParsingException(ErrorType.InvalidPdfaSchema, "Invalid PDF/A namespace definition"); } // else good match if (cnamespace.equals(namespace) && !cprefix.equals(prefix)) { throw new XmpParsingException(ErrorType.InvalidPdfaSchema, "Invalid PDF/A namespace definition"); } // else good match } public static void populateSchemaMapping(XMPMetadata meta) throws XmpParsingException { List schems = meta.getAllSchemas(); TypeMapping tm = meta.getTypeMapping(); StructuredType stPdfaExt = PDFAExtensionSchema.class.getAnnotation(StructuredType.class); for (XMPSchema xmpSchema : schems) { if (xmpSchema.getNamespace().equals(stPdfaExt.namespace())) { // ensure the prefix is the preferred one (cannot use other // definition) if (!xmpSchema.getPrefix().equals(stPdfaExt.preferedPrefix())) { throw new XmpParsingException(ErrorType.InvalidPrefix, "Found invalid prefix for PDF/A extension, found '" + xmpSchema.getPrefix() + "', should be '" + stPdfaExt.preferedPrefix() + "'"); } // create schema and types PDFAExtensionSchema pes = (PDFAExtensionSchema) xmpSchema; ArrayProperty sp = pes.getSchemasProperty(); for (AbstractField af : sp.getAllProperties()) { if (af instanceof PDFASchemaType) { PDFASchemaType st = (PDFASchemaType) af; String namespaceUri = st.getNamespaceURI().trim(); String prefix = st.getPrefixValue(); ArrayProperty properties = st.getProperty(); ArrayProperty valueTypes = st.getValueType(); XMPSchemaFactory xsf = tm.getSchemaFactory(namespaceUri); // retrieve namespaces if (xsf == null) { // create namespace with no field tm.addNewNameSpace(namespaceUri, prefix); xsf = tm.getSchemaFactory(namespaceUri); } // populate value type if (valueTypes != null) { for (AbstractField af2 : valueTypes.getAllProperties()) { if (af2 instanceof PDFATypeType) { PDFATypeType type = (PDFATypeType) af2; String ttype = type.getType(); String tns = type.getNamespaceURI(); String tprefix = type.getPrefixValue(); String tdescription = type.getDescription(); ArrayProperty fields = type.getFields(); if (ttype == null || tns == null || tprefix == null || tdescription == null) { // all fields are mandatory throw new XmpParsingException(ErrorType.RequiredProperty, "Missing field in type definition"); } // create the structured type DefinedStructuredType structuredType = new DefinedStructuredType(meta, tns, tprefix, null); // TODO // maybe // a name // exists if (fields != null) { List definedFields = fields.getAllProperties(); for (AbstractField af3 : definedFields) { if (af3 instanceof PDFAFieldType) { PDFAFieldType field = (PDFAFieldType) af3; String fName = field.getName(); String fDescription = field.getDescription(); String fValueType = field.getValueType(); if (fName == null || fDescription == null || fValueType == null) { throw new XmpParsingException(ErrorType.RequiredProperty, "Missing field in field definition"); } try { Types fValue = Types.valueOf(fValueType); structuredType.addProperty(fName, TypeMapping.createPropertyType(fValue, Cardinality.Simple)); } catch (IllegalArgumentException e) { throw new XmpParsingException(ErrorType.NoValueType, "Type not defined : " + fValueType, e); // TODO could fValueType be // a structured type ? } } // else TODO } } // add the structured type to list PropertiesDescription pm = new PropertiesDescription(); for (Map.Entry entry : structuredType.getDefinedProperties() .entrySet()) { pm.addNewProperty(entry.getKey(), entry.getValue()); } tm.addToDefinedStructuredTypes(ttype, tns, pm); } } } // populate properties if (properties == null) { throw new XmpParsingException(ErrorType.RequiredProperty, "Missing pdfaSchema:property in type definition"); } for (AbstractField af2 : properties.getAllProperties()) { if (af2 instanceof PDFAPropertyType) { PDFAPropertyType property = (PDFAPropertyType) af2; String pname = property.getName(); String ptype = property.getValueType(); String pdescription = property.getDescription(); String pCategory = property.getCategory(); // check all mandatory fields are OK if (pname == null || ptype == null || pdescription == null || pCategory == null) { // all fields are mandatory throw new XmpParsingException(ErrorType.RequiredProperty, "Missing field in property definition"); } // check ptype existance PropertyType pt = transformValueType(tm, ptype); if (pt.type() == null) { throw new XmpParsingException(ErrorType.NoValueType, "Type not defined : " + ptype); } else if (pt.type().isSimple() || pt.type().isStructured() || pt.type() == Types.DefinedType) { xsf.getPropertyDefinition().addNewProperty(pname, pt); } else { throw new XmpParsingException(ErrorType.NoValueType, "Type not defined : " + ptype); } } // TODO unmanaged ? } } // TODO unmanaged ? } } } } private static PropertyType transformValueType(TypeMapping tm, String valueType) throws XmpParsingException { if ("Lang Alt".equals(valueType)) { return TypeMapping.createPropertyType(Types.LangAlt, Cardinality.Simple); } // else all other cases if (valueType.startsWith(CLOSED_CHOICE)) { valueType = valueType.substring(CLOSED_CHOICE.length()); } else if (valueType.startsWith(OPEN_CHOICE)) { valueType = valueType.substring(OPEN_CHOICE.length()); } int pos = valueType.indexOf(' '); Cardinality card = Cardinality.Simple; if (pos > 0) { String scard = valueType.substring(0, pos); if ("seq".equals(scard)) { card = Cardinality.Seq; } else if ("bag".equals(scard)) { card = Cardinality.Bag; } else if ("alt".equals(scard)) { card = Cardinality.Alt; } else { return null; } } String vt = valueType.substring(pos + 1); Types type = null; try { type = pos < 0 ? Types.valueOf(valueType) : Types.valueOf(vt); } catch (IllegalArgumentException e) { if (tm.isDefinedType(vt)) { type = Types.DefinedType; } } return TypeMapping.createPropertyType(type, card); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpSerializer.java0000644000000000000000000002405612645757426025352 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.xml; import java.io.OutputStream; import java.util.List; import java.util.Map; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XmpConstants; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.type.AbstractComplexProperty; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.AbstractSimpleProperty; import org.apache.xmpbox.type.AbstractStructuredType; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Attribute; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.ProcessingInstruction; public class XmpSerializer { private DocumentBuilder documentBuilder = null; private boolean parseTypeResourceForLi = true; public XmpSerializer() throws XmpSerializationException { // xml init DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); try { documentBuilder = builderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new XmpSerializationException("Failed to init XmpSerializer", e); } } public void serialize(XMPMetadata metadata, OutputStream os, boolean withXpacket) throws TransformerException { Document doc = documentBuilder.newDocument(); // fill document Element rdf = createRdfElement(doc, metadata, withXpacket); for (XMPSchema schema : metadata.getAllSchemas()) { rdf.appendChild(serializeSchema(doc, schema)); } // save save(doc, os, "UTF-8"); } protected Element serializeSchema(Document doc, XMPSchema schema) { // prepare schema Element selem = doc.createElementNS(XmpConstants.RDF_NAMESPACE, "rdf:Description"); selem.setAttributeNS(XmpConstants.RDF_NAMESPACE, "rdf:about", schema.getAboutValue()); selem.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:" + schema.getPrefix(), schema.getNamespace()); // the other attributes fillElementWithAttributes(selem, schema); // the content List fields = schema.getAllProperties(); serializeFields(doc, selem, fields, true); // return created schema return selem; } public void serializeFields(Document doc, Element parent, List fields, boolean wrapWithProperty) { for (AbstractField field : fields) { if (field instanceof AbstractSimpleProperty) { AbstractSimpleProperty simple = (AbstractSimpleProperty) field; Element esimple = doc.createElement(simple.getPrefix() + ":" + simple.getPropertyName()); esimple.setTextContent(simple.getStringValue()); parent.appendChild(esimple); } else if (field instanceof ArrayProperty) { ArrayProperty array = (ArrayProperty) field; // property Element asimple = doc.createElement(array.getPrefix() + ":" + array.getPropertyName()); parent.appendChild(asimple); // attributes fillElementWithAttributes(asimple, array); // the array definition Element econtainer = doc.createElement(XmpConstants.DEFAULT_RDF_PREFIX + ":" + array.getArrayType()); asimple.appendChild(econtainer); // for each element of the array List innerFields = array.getAllProperties(); serializeFields(doc, econtainer, innerFields, false); } else if (field instanceof AbstractStructuredType) { AbstractStructuredType structured = (AbstractStructuredType) field; List innerFields = structured.getAllProperties(); // property name attribute Element listParent = parent; if (wrapWithProperty) { Element nstructured = doc .createElement(structured.getPrefix() + ":" + structured.getPropertyName()); parent.appendChild(nstructured); listParent = nstructured; } // element li Element estructured = doc.createElement(XmpConstants.DEFAULT_RDF_PREFIX + ":" + XmpConstants.LIST_NAME); listParent.appendChild(estructured); if (parseTypeResourceForLi) { estructured.setAttribute("rdf:parseType", "Resource"); // all properties serializeFields(doc, estructured, innerFields, true); } else { // element description Element econtainer = doc.createElement(XmpConstants.DEFAULT_RDF_PREFIX + ":" + "Description"); estructured.appendChild(econtainer); // all properties serializeFields(doc, econtainer, innerFields, true); } } else { // XXX finish serialization classes System.err.println(">> TODO >> " + field.getClass()); } } } private void fillElementWithAttributes(Element target, AbstractComplexProperty property) { List attributes = property.getAllAttributes(); for (Attribute attribute : attributes) { if (XmpConstants.RDF_NAMESPACE.equals(attribute.getNamespace())) { target.setAttribute(XmpConstants.DEFAULT_RDF_PREFIX + ":" + attribute.getName(), attribute.getValue()); } else if (target.getNamespaceURI().equals(attribute.getNamespace())) { target.setAttribute(attribute.getName(), attribute.getValue()); } else { target.setAttribute(attribute.getName(), attribute.getValue()); } } for (Map.Entry ns : property.getAllNamespacesWithPrefix().entrySet()) { target.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + ns.getValue(), ns.getKey()); } } protected Element createRdfElement(Document doc, XMPMetadata metadata, boolean withXpacket) { // starting xpacket if (withXpacket) { ProcessingInstruction beginXPacket = doc.createProcessingInstruction("xpacket", "begin=\"" + metadata.getXpacketBegin() + "\" id=\"" + metadata.getXpacketId() + "\""); doc.appendChild(beginXPacket); } // meta element Element xmpmeta = doc.createElementNS("adobe:ns:meta/", "x:xmpmeta"); xmpmeta.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:x", "adobe:ns:meta/"); doc.appendChild(xmpmeta); // ending xpacket if (withXpacket) { ProcessingInstruction endXPacket = doc.createProcessingInstruction("xpacket", "end=\"" + metadata.getEndXPacket() + "\""); doc.appendChild(endXPacket); } // rdf element Element rdf = doc.createElementNS(XmpConstants.RDF_NAMESPACE, "rdf:RDF"); // rdf.setAttributeNS(XMPSchema.NS_NAMESPACE, qualifiedName, value) xmpmeta.appendChild(rdf); // return the rdf element where all will be put return rdf; } /** * Save the XML document to an output stream. * * @param doc * The XML document to save. * @param outStream * The stream to save the document to. * @param encoding * The encoding to save the file as. * * @throws TransformerException * If there is an error while saving the XML. */ private void save(Node doc, OutputStream outStream, String encoding) throws TransformerException { Transformer transformer = TransformerFactory.newInstance().newTransformer(); // human readable transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // indent elements transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); // encoding transformer.setOutputProperty(OutputKeys.ENCODING, encoding); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); // initialize StreamResult with File object to save to file Result result = new StreamResult(outStream); DOMSource source = new DOMSource(doc); // save transformer.transform(source, result); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java0000644000000000000000000007554712645757426025150 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.xml; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.StringTokenizer; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XmpConstants; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.schema.XmpSchemaException; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.AbstractSimpleProperty; import org.apache.xmpbox.type.AbstractStructuredType; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Attribute; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.ComplexPropertyContainer; import org.apache.xmpbox.type.PropertiesDescription; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.TypeMapping; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.xml.XmpParsingException.ErrorType; import org.w3c.dom.Attr; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import org.xml.sax.SAXException; public class DomXmpParser { private DocumentBuilder dBuilder; private NamespaceFinder nsFinder; private boolean strictParsing = true; public DomXmpParser() throws XmpParsingException { try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); dbFactory.setNamespaceAware(true); dBuilder = dbFactory.newDocumentBuilder(); nsFinder = new NamespaceFinder(); } catch (ParserConfigurationException e) { throw new XmpParsingException(ErrorType.Configuration, "Failed to initilalize", e); } } public boolean isStrictParsing() { return strictParsing; } public void setStrictParsing(boolean strictParsing) { this.strictParsing = strictParsing; } public XMPMetadata parse(byte[] xmp) throws XmpParsingException { ByteArrayInputStream input = new ByteArrayInputStream(xmp); return parse(input); } public XMPMetadata parse(InputStream input) throws XmpParsingException { Document document = null; try { // prevents validation messages polluting the console dBuilder.setErrorHandler(null); document = dBuilder.parse(input); } catch (SAXException e) { throw new XmpParsingException(ErrorType.Undefined, "Failed to parse", e); } catch (IOException e) { throw new XmpParsingException(ErrorType.Undefined, "Failed to parse", e); } // document.normalizeDocument(); XMPMetadata xmp = null; // Start reading removeComments(document.getFirstChild()); Node node = document.getFirstChild(); // expect xpacket processing instruction if (!(node instanceof ProcessingInstruction)) { throw new XmpParsingException(ErrorType.XpacketBadStart, "xmp should start with a processing instruction"); } else { xmp = parseInitialXpacket((ProcessingInstruction) node); node = node.getNextSibling(); } // forget other processing instruction while (node instanceof ProcessingInstruction) { node = node.getNextSibling(); } // expect root element Element root = null; if (!(node instanceof Element)) { throw new XmpParsingException(ErrorType.NoRootElement, "xmp should contain a root element"); } else { // use this element as root root = (Element) node; node = node.getNextSibling(); } // expect xpacket end if (!(node instanceof ProcessingInstruction)) { throw new XmpParsingException(ErrorType.XpacketBadEnd, "xmp should end with a processing instruction"); } else { parseEndPacket(xmp, (ProcessingInstruction) node); node = node.getNextSibling(); } // should be null if (node != null) { throw new XmpParsingException(ErrorType.XpacketBadEnd, "xmp should end after xpacket end processing instruction"); } // xpacket is OK and the is no more nodes // Now, parse the content of root Element rdfRdf = findDescriptionsParent(root); List descriptions = DomHelper.getElementChildren(rdfRdf); List dataDescriptions = new ArrayList(descriptions.size()); for (Element description : descriptions) { Element first = DomHelper.getFirstChildElement(description); if (first != null && "pdfaExtension".equals(first.getPrefix())) { PdfaExtensionHelper.validateNaming(xmp, description); parseDescriptionRoot(xmp, description); } else { dataDescriptions.add(description); } } // find schema description PdfaExtensionHelper.populateSchemaMapping(xmp); // parse data description for (Element description : dataDescriptions) { parseDescriptionRoot(xmp, description); } return xmp; } private void parseDescriptionRoot(XMPMetadata xmp, Element description) throws XmpParsingException { nsFinder.push(description); TypeMapping tm = xmp.getTypeMapping(); try { List properties = DomHelper.getElementChildren(description); // parse attributes as properties NamedNodeMap nnm = description.getAttributes(); for (int i = 0; i < nnm.getLength(); i++) { Attr attr = (Attr) nnm.item(i); if (XMLConstants.XMLNS_ATTRIBUTE.equals(attr.getPrefix())) { // do nothing } else if (XmpConstants.DEFAULT_RDF_PREFIX.equals(attr.getPrefix()) && XmpConstants.ABOUT_NAME.equals(attr.getLocalName())) { // do nothing } else if (attr.getPrefix() == null && XmpConstants.ABOUT_NAME.equals(attr.getLocalName())) { // do nothing } else { String namespace = attr.getNamespaceURI(); XMPSchema schema = xmp.getSchema(namespace); if (schema == null) { schema = tm.getSchemaFactory(namespace).createXMPSchema(xmp, attr.getPrefix()); loadAttributes(schema, description); } ComplexPropertyContainer container = schema.getContainer(); PropertyType type = checkPropertyDefinition(xmp, new QName(attr.getNamespaceURI(), attr.getLocalName())); AbstractSimpleProperty sp = tm.instanciateSimpleProperty(namespace, schema.getPrefix(), attr.getLocalName(), attr.getValue(), type.type()); container.addProperty(sp); } } // parse children elements as properties for (Element property : properties) { String namespace = property.getNamespaceURI(); PropertyType type = checkPropertyDefinition(xmp, DomHelper.getQName(property)); // create the container if (!tm.isDefinedSchema(namespace)) { throw new XmpParsingException(ErrorType.NoSchema, "This namespace is not a schema or a structured type : " + namespace); } XMPSchema schema = xmp.getSchema(namespace); if (schema == null) { schema = tm.getSchemaFactory(namespace).createXMPSchema(xmp, property.getPrefix()); loadAttributes(schema, description); } ComplexPropertyContainer container = schema.getContainer(); // create property createProperty(xmp, property, type, container); } } catch (XmpSchemaException e) { throw new XmpParsingException(ErrorType.Undefined, "Parsing failed", e); } finally { nsFinder.pop(); } } private void createProperty(XMPMetadata xmp, Element property, PropertyType type, ComplexPropertyContainer container) throws XmpParsingException { String prefix = property.getPrefix(); String name = property.getLocalName(); String namespace = property.getNamespaceURI(); // create property nsFinder.push(property); try { if (type == null) { if (strictParsing) { throw new XmpParsingException(ErrorType.InvalidType, "No type defined for {" + namespace + "}" + name); } else { // use it as string manageSimpleType(xmp, property, Types.Text, container); } } else if (type.type() == Types.LangAlt) { manageLangAlt(xmp, property, container); } else if (type.card().isArray()) { manageArray(xmp, property, type, container); } else if (type.type().isSimple()) { manageSimpleType(xmp, property, type.type(), container); } else if (type.type().isStructured()) { if (DomHelper.isParseTypeResource(property)) { AbstractStructuredType ast = parseLiDescription(xmp, DomHelper.getQName(property), property); if (ast != null) { ast.setPrefix(prefix); container.addProperty(ast); } } else { Element inner = DomHelper.getFirstChildElement(property); if (inner != null) { AbstractStructuredType ast = parseLiDescription(xmp, DomHelper.getQName(property), inner); ast.setPrefix(prefix); container.addProperty(ast); } } } else if (type.type() == Types.DefinedType) { if (DomHelper.isParseTypeResource(property)) { AbstractStructuredType ast = parseLiDescription(xmp, DomHelper.getQName(property), property); ast.setPrefix(prefix); container.addProperty(ast); } else { Element inner = DomHelper.getFirstChildElement(property); if (inner == null) { throw new XmpParsingException(ErrorType.Format, "property should contain child element : " + property); } AbstractStructuredType ast = parseLiDescription(xmp, DomHelper.getQName(property), inner); ast.setPrefix(prefix); container.addProperty(ast); } } } finally { nsFinder.pop(); } } private void manageSimpleType(XMPMetadata xmp, Element property, Types type, ComplexPropertyContainer container) throws XmpParsingException { TypeMapping tm = xmp.getTypeMapping(); String prefix = property.getPrefix(); String name = property.getLocalName(); String namespace = property.getNamespaceURI(); AbstractSimpleProperty sp = tm.instanciateSimpleProperty(namespace, prefix, name, property.getTextContent(), type); loadAttributes(sp, property); container.addProperty(sp); } private void manageArray(XMPMetadata xmp, Element property, PropertyType type, ComplexPropertyContainer container) throws XmpParsingException { TypeMapping tm = xmp.getTypeMapping(); String prefix = property.getPrefix(); String name = property.getLocalName(); String namespace = property.getNamespaceURI(); Element bagOrSeq = DomHelper.getUniqueElementChild(property); // ensure this is the good type of array if (bagOrSeq == null) { // not an array throw new XmpParsingException(ErrorType.Format, "Invalid array definition, expecting " + type.card() + " and found nothing"); } if (!bagOrSeq.getLocalName().equals(type.card().name())) { // not the good array type throw new XmpParsingException(ErrorType.Format, "Invalid array type, expecting " + type.card() + " and found " + bagOrSeq.getLocalName()); } ArrayProperty array = tm.createArrayProperty(namespace, prefix, name, type.card()); container.addProperty(array); List lis = DomHelper.getElementChildren(bagOrSeq); for (Element element : lis) { QName propertyQName = DomHelper.getQName(property); AbstractField ast = parseLiElement(xmp, propertyQName, element); if (ast != null) { array.addProperty(ast); } } } private void manageLangAlt(XMPMetadata xmp, Element property, ComplexPropertyContainer container) throws XmpParsingException { manageArray(xmp, property, TypeMapping.createPropertyType(Types.LangAlt, Cardinality.Alt), container); } private void parseDescriptionInner(XMPMetadata xmp, Element description, ComplexPropertyContainer parentContainer) throws XmpParsingException { nsFinder.push(description); TypeMapping tm = xmp.getTypeMapping(); try { List properties = DomHelper.getElementChildren(description); for (Element property : properties) { String name = property.getLocalName(); PropertyType dtype = checkPropertyDefinition(xmp, DomHelper.getQName(property)); PropertyType ptype = tm.getStructuredPropMapping(dtype.type()).getPropertyType(name); // create property createProperty(xmp, property, ptype, parentContainer); } } finally { nsFinder.pop(); } } private AbstractField parseLiElement(XMPMetadata xmp, QName descriptor, Element liElement) throws XmpParsingException { if (DomHelper.isParseTypeResource(liElement)) { return parseLiDescription(xmp, descriptor, liElement); } // will find rdf:Description Element liChild = DomHelper.getUniqueElementChild(liElement); if (liChild != null) { return parseLiDescription(xmp, descriptor, liChild); } else { // no child, so consider as simple text String text = liElement.getTextContent(); TypeMapping tm = xmp.getTypeMapping(); AbstractSimpleProperty sp = tm.instanciateSimpleProperty(descriptor.getNamespaceURI(), descriptor.getPrefix(), descriptor.getLocalPart(), text, Types.Text); loadAttributes(sp, liElement); return sp; } } private void loadAttributes(AbstractField sp, Element element) { NamedNodeMap nnm = element.getAttributes(); for (int i = 0; i < nnm.getLength(); i++) { Attr attr = (Attr) nnm.item(i); if (XMLConstants.XMLNS_ATTRIBUTE.equals(attr.getPrefix())) { // do nothing } else if (XmpConstants.DEFAULT_RDF_PREFIX.equals(attr.getPrefix()) && XmpConstants.ABOUT_NAME.equals(attr.getLocalName())) { // set about if (sp instanceof XMPSchema) { ((XMPSchema) sp).setAboutAsSimple(attr.getValue()); } } else { Attribute attribute = new Attribute(XMLConstants.XML_NS_URI, attr.getLocalName(), attr.getValue()); sp.setAttribute(attribute); } } } private AbstractStructuredType parseLiDescription(XMPMetadata xmp, QName descriptor, Element liElement) throws XmpParsingException { TypeMapping tm = xmp.getTypeMapping(); List elements = DomHelper.getElementChildren(liElement); if (elements.size() == 0) { // The list is empty return null; } // Instantiate abstract structured type with hint from first element Element first = elements.get(0); PropertyType ctype = checkPropertyDefinition(xmp, DomHelper.getQName(first)); Types tt = ctype.type(); AbstractStructuredType ast = instanciateStructured(tm, tt, descriptor.getLocalPart(), first.getNamespaceURI()); ast.setNamespace(descriptor.getNamespaceURI()); ast.setPrefix(descriptor.getPrefix()); PropertiesDescription pm; if (tt.isStructured()) { pm = tm.getStructuredPropMapping(tt); } else { pm = tm.getDefinedDescriptionByNamespace(first.getNamespaceURI()); } for (Element element : elements) { String prefix = element.getPrefix(); String name = element.getLocalName(); String namespace = element.getNamespaceURI(); PropertyType type = pm.getPropertyType(name); if (type == null) { // not defined throw new XmpParsingException(ErrorType.NoType, "Type '" + name + "' not defined in " + element.getNamespaceURI()); } else if (type.card().isArray()) { ArrayProperty array = tm.createArrayProperty(namespace, prefix, name, type.card()); ast.getContainer().addProperty(array); Element bagOrSeq = DomHelper.getUniqueElementChild(element); List lis = DomHelper.getElementChildren(bagOrSeq); for (Element element2 : lis) { AbstractField ast2 = parseLiElement(xmp, descriptor, element2); if (ast2 != null) { array.addProperty(ast2); } } } else if (type.type().isSimple()) { AbstractSimpleProperty sp = tm.instanciateSimpleProperty(namespace, prefix, name, element.getTextContent(), type.type()); loadAttributes(sp, element); ast.getContainer().addProperty(sp); } else if (type.type().isStructured()) { // create a new structured type AbstractStructuredType inner = instanciateStructured(tm, type.type(), name, null); inner.setNamespace(namespace); inner.setPrefix(prefix); ast.getContainer().addProperty(inner); ComplexPropertyContainer cpc = inner.getContainer(); if (DomHelper.isParseTypeResource(element)) { parseDescriptionInner(xmp, element, cpc); } else { Element descElement = DomHelper.getFirstChildElement(element); if (descElement != null) { parseDescriptionInner(xmp, descElement, cpc); } } } else { throw new XmpParsingException(ErrorType.NoType, "Unidentified element to parse " + element + " (type=" + type + ")"); } } return ast; } private XMPMetadata parseInitialXpacket(ProcessingInstruction pi) throws XmpParsingException { if (!"xpacket".equals(pi.getNodeName())) { throw new XmpParsingException(ErrorType.XpacketBadStart, "Bad processing instruction name : " + pi.getNodeName()); } String data = pi.getData(); StringTokenizer tokens = new StringTokenizer(data, " "); String id = null; String begin = null; String bytes = null; String encoding = null; while (tokens.hasMoreTokens()) { String token = tokens.nextToken(); if (!token.endsWith("\"") && !token.endsWith("\'")) { throw new XmpParsingException(ErrorType.XpacketBadStart, "Cannot understand PI data part : '" + token + "'"); } String quote = token.substring(token.length() - 1); int pos = token.indexOf("=" + quote); if (pos <= 0) { throw new XmpParsingException(ErrorType.XpacketBadStart, "Cannot understand PI data part : '" + token + "'"); } String name = token.substring(0, pos); String value = token.substring(pos + 2, token.length() - 1); if ("id".equals(name)) { id = value; } else if ("begin".equals(name)) { begin = value; } else if ("bytes".equals(name)) { bytes = value; } else if ("encoding".equals(name)) { encoding = value; } else { throw new XmpParsingException(ErrorType.XpacketBadStart, "Unknown attribute in xpacket PI : '" + token + "'"); } } return XMPMetadata.createXMPMetadata(begin, id, bytes, encoding); } private void parseEndPacket(XMPMetadata metadata, ProcessingInstruction pi) throws XmpParsingException { String xpackData = pi.getData(); // end attribute must be present and placed in first // xmp spec says Other unrecognized attributes can follow, but // should be ignored if (xpackData.startsWith("end=")) { char end = xpackData.charAt(5); // check value (5 for end='X') if (end != 'r' && end != 'w') { throw new XmpParsingException(ErrorType.XpacketBadEnd, "Excepted xpacket 'end' attribute with value 'r' or 'w' "); } else { metadata.setEndXPacket(Character.toString(end)); } } else { // should find end='r/w' throw new XmpParsingException(ErrorType.XpacketBadEnd, "Excepted xpacket 'end' attribute (must be present and placed in first)"); } } private Element findDescriptionsParent(Element root) throws XmpParsingException { // always expectNaming(root, "adobe:ns:meta/", "x", "xmpmeta"); // should only have one child NodeList nl = root.getChildNodes(); if (nl.getLength() == 0) { // empty description throw new XmpParsingException(ErrorType.Format, "No rdf description found in xmp"); } else if (nl.getLength() > 1) { // only expect one element throw new XmpParsingException(ErrorType.Format, "More than one element found in x:xmpmeta"); } else if (!(root.getFirstChild() instanceof Element)) { // should be an element throw new XmpParsingException(ErrorType.Format, "x:xmpmeta does not contains rdf:RDF element"); } // else let's parse Element rdfRdf = (Element) root.getFirstChild(); // always expectNaming(rdfRdf, XmpConstants.RDF_NAMESPACE, XmpConstants.DEFAULT_RDF_PREFIX, XmpConstants.DEFAULT_RDF_LOCAL_NAME); // return description parent return rdfRdf; } private void expectNaming(Element element, String ns, String prefix, String ln) throws XmpParsingException { if ((ns != null) && !(ns.equals(element.getNamespaceURI()))) { throw new XmpParsingException(ErrorType.Format, "Expecting namespace '" + ns + "' and found '" + element.getNamespaceURI() + "'"); } else if ((prefix != null) && !(prefix.equals(element.getPrefix()))) { throw new XmpParsingException(ErrorType.Format, "Expecting prefix '" + prefix + "' and found '" + element.getPrefix() + "'"); } else if ((ln != null) && !(ln.equals(element.getLocalName()))) { throw new XmpParsingException(ErrorType.Format, "Expecting local name '" + ln + "' and found '" + element.getLocalName() + "'"); } // else OK } /** * Remove all the comments node in the parent element of the parameter * * @param node * the first node of an element or document to clear */ private void removeComments(Node root) { Node node = root; while (node != null) { Node next = node.getNextSibling(); if (node instanceof Comment) { // remove the comment node.getParentNode().removeChild(node); } else if (node instanceof Text) { Text t = (Text) node; if (t.getTextContent().trim().length() == 0) { // XXX is there a better way to remove useless Text ? node.getParentNode().removeChild(node); } } else if (node instanceof Element) { // clean child removeComments(node.getFirstChild()); } // else do nothing node = next; } // end of document } private AbstractStructuredType instanciateStructured(TypeMapping tm, Types type, String name, String structuredNamespace) throws XmpParsingException { try { if (type.isStructured()) { return tm.instanciateStructuredType(type, name); } else if (type.isDefined()) { return tm.instanciateDefinedType(name, structuredNamespace); } else { throw new XmpParsingException(ErrorType.InvalidType, "Type not structured : " + type); } } catch (BadFieldValueException e) { throw new XmpParsingException(ErrorType.InvalidType, "Parsing failed", e); } } private PropertyType checkPropertyDefinition(XMPMetadata xmp, QName prop) throws XmpParsingException { TypeMapping tm = xmp.getTypeMapping(); // test if namespace is set in xml if (!nsFinder.containsNamespace(prop.getNamespaceURI())) { throw new XmpParsingException(ErrorType.NoSchema, "Schema is not set in this document : " + prop.getNamespaceURI()); } // test if namespace is defined String nsuri = prop.getNamespaceURI(); if (!tm.isDefinedNamespace(nsuri)) { throw new XmpParsingException(ErrorType.NoSchema, "Cannot find a definition for the namespace " + prop.getNamespaceURI()); } try { return tm.getSpecifiedPropertyType(prop); } catch (BadFieldValueException e) { throw new XmpParsingException(ErrorType.InvalidType, "Failed to retreive property definition", e); } } protected class NamespaceFinder { private Stack> stack = new Stack>(); protected void push(Element description) { NamedNodeMap nnm = description.getAttributes(); Map map = new HashMap(nnm.getLength()); for (int j = 0; j < nnm.getLength(); j++) { Attr no = (Attr) nnm.item(j); // if ns definition add it if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(no.getNamespaceURI())) { map.put(no.getLocalName(), no.getValue()); } } stack.push(map); } protected Map pop() { return stack.pop(); } protected boolean containsNamespace(String namespace) { for (int i = stack.size() - 1; i >= 0; i--) { Map map = stack.get(i); if (map.containsValue(namespace)) { return true; } } // else namespace not found return false; } } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/0000755000000000000000000000000012645757426022063 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ChoiceType.java0000644000000000000000000000240212645757426024760 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class ChoiceType extends TextType { public ChoiceType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ResourceEventType.java0000644000000000000000000000671112645757426026366 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.Calendar; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "stEvt", namespace = "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#") public class ResourceEventType extends AbstractStructuredType { @PropertyType(type = Types.Choice, card = Cardinality.Simple) public static final String ACTION = "action"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String CHANGED = "changed"; @PropertyType(type = Types.GUID, card = Cardinality.Simple) public static final String INSTANCE_ID = "instanceID"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String PARAMETERS = "parameters"; @PropertyType(type = Types.AgentName, card = Cardinality.Simple) public static final String SOFTWARE_AGENT = "softwareAgent"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String WHEN = "when"; /** * * @param metadata * The metadata to attach to this property */ public ResourceEventType(XMPMetadata metadata) { super(metadata); addNamespace(getNamespace(), getPreferedPrefix()); } public String getInstanceID() { return getPropertyValueAsString(INSTANCE_ID); } public void setInstanceID(String value) { addSimpleProperty(INSTANCE_ID, value); } public String getSoftwareAgent() { return getPropertyValueAsString(SOFTWARE_AGENT); } public void setSoftwareAgent(String value) { addSimpleProperty(SOFTWARE_AGENT, value); } public Calendar getWhen() { return getDatePropertyAsCalendar(WHEN); } public void setWhen(Calendar value) { addSimpleProperty(WHEN, value); } public String getAction() { return getPropertyValueAsString(ACTION); } public void setAction(String value) { addSimpleProperty(ACTION, value); } public String getChanged() { return getPropertyValueAsString(CHANGED); } public void setChanged(String value) { addSimpleProperty(CHANGED, value); } public String getParameters() { return getPropertyValueAsString(PARAMETERS); } public void setParameters(String value) { addSimpleProperty(PARAMETERS, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/IntegerType.java0000644000000000000000000000536412645757426025175 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; /** * Object representation of an Integer XMP type * * @author a183132 * */ public class IntegerType extends AbstractSimpleProperty { private int integerValue; /** * Property Integer type constructor (namespaceURI is given) * * @param metadata * The metadata to attach to this property * @param namespaceURI * the namespace URI to associate to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param value * The value to set */ public IntegerType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } /** * return the property value * * @return the property value */ public Integer getValue() { return integerValue; } /** * Set the property value * * @param value * The value to set */ public void setValue(Object value) { if (value instanceof Integer) { integerValue = ((Integer) value).intValue(); } else if (value instanceof String) { integerValue = Integer.valueOf((String) value); // NumberFormatException is thrown (sub of InvalidArgumentException) } else { // invalid type of value throw new IllegalArgumentException("Value given is not allowed for the Integer type."); } } @Override public String getStringValue() { return Integer.toString(integerValue); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ThumbnailType.java0000644000000000000000000001015112645757426025511 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XmpConstants; /** * Object representation of an Thumbnail XMP type * * @author eric */ @StructuredType(preferedPrefix = "xmpGImg", namespace = "http://ns.adobe.com/xap/1.0/g/img/") public class ThumbnailType extends AbstractStructuredType { @PropertyType(type = Types.Choice, card = Cardinality.Simple) public static final String FORMAT = "format"; @PropertyType(type = Types.Integer, card = Cardinality.Simple) public static final String HEIGHT = "height"; @PropertyType(type = Types.Integer, card = Cardinality.Simple) public static final String WIDTH = "width"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String IMAGE = "image"; /** * * @param metadata * The metadata to attach to this property */ public ThumbnailType(XMPMetadata metadata) { super(metadata); setAttribute(new Attribute(XmpConstants.RDF_NAMESPACE, "parseType", "Resource")); } /** * Get Height * * @return the height */ public Integer getHeight() { AbstractField absProp = getFirstEquivalentProperty(HEIGHT, IntegerType.class); if (absProp != null) { return ((IntegerType) absProp).getValue(); } return null; } /** * Set Height * * @param height * the value of Height property to set */ public void setHeight(Integer height) { addSimpleProperty(HEIGHT, height); } /** * Get Width * * @return the width */ public Integer getWidth() { AbstractField absProp = getFirstEquivalentProperty(WIDTH, IntegerType.class); if (absProp != null) { return ((IntegerType) absProp).getValue(); } return null; } /** * Set Width * * @param width * the value of width property to set */ public void setWidth(Integer width) { addSimpleProperty(WIDTH, width); } /** * Get The img data * * @return the img */ public String getImage() { AbstractField absProp = getFirstEquivalentProperty(IMAGE, TextType.class); if (absProp != null) { return ((TextType) absProp).getStringValue(); } return null; } /** * Set Image data * * @param image * the value of image property to set */ public void setImage(String image) { addSimpleProperty(IMAGE, image); } /** * Get Format * * @return the format */ public String getFormat() { AbstractField absProp = getFirstEquivalentProperty(FORMAT, ChoiceType.class); if (absProp != null) { return ((TextType) absProp).getStringValue(); } return null; } /** * Set Format * * @param format * the value of format property to set */ public void setFormat(String format) { addSimpleProperty(FORMAT, format); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/RealType.java0000644000000000000000000000532512645757426024460 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; /** * Object representation of a Real XMP type * * @author a183132 * */ public class RealType extends AbstractSimpleProperty { private float realValue; /** * Property Real type constructor (namespaceURI is given) * * @param metadata * The metadata to attach to this property * @param namespaceURI * the namespace URI to associate to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param value * The value to set */ public RealType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } /** * return the property value * * @return float the property value */ public Float getValue() { return realValue; } /** * Set the property value * * @param value * The value to set */ public void setValue(Object value) { if (value instanceof Float) { realValue = ((Float) value).floatValue(); } else if (value instanceof String) { // NumberFormatException is thrown (sub of InvalidArgumentException) realValue = Float.valueOf((String) value); } else { // invalid type of value throw new IllegalArgumentException("Value given is not allowed for the Real type."); } } @Override public String getStringValue() { return Float.toString(realValue); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/StructuredType.java0000644000000000000000000000244612645757426025742 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface StructuredType { String namespace(); String preferedPrefix(); } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PDFAFieldType.java0000644000000000000000000000410212645757426025243 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "pdfaField", namespace = "http://www.aiim.org/pdfa/ns/field#") public class PDFAFieldType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String NAME = "name"; @PropertyType(type = Types.Choice, card = Cardinality.Simple) public static final String VALUETYPE = "valueType"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String DESCRIPTION = "description"; public PDFAFieldType(XMPMetadata metadata) { super(metadata); } public String getName() { TextType tt = (TextType) getProperty(NAME); return tt == null ? null : tt.getStringValue(); } public String getValueType() { TextType tt = (TextType) getProperty(VALUETYPE); return tt == null ? null : tt.getStringValue(); } public String getDescription() { TextType tt = (TextType) getProperty(DESCRIPTION); return tt == null ? null : tt.getStringValue(); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PDFAPropertyType.java0000644000000000000000000000455412645757426026057 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "pdfaProperty", namespace = "http://www.aiim.org/pdfa/ns/property#") public class PDFAPropertyType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String NAME = "name"; @PropertyType(type = Types.Choice, card = Cardinality.Simple) public static final String VALUETYPE = "valueType"; @PropertyType(type = Types.Choice, card = Cardinality.Simple) public static final String CATEGORY = "category"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String DESCRIPTION = "description"; public PDFAPropertyType(XMPMetadata metadata) { super(metadata); } public String getName() { TextType tt = (TextType) getProperty(NAME); return tt == null ? null : tt.getStringValue(); } public String getValueType() { ChoiceType tt = (ChoiceType) getProperty(VALUETYPE); return tt == null ? null : tt.getStringValue(); } public String getDescription() { TextType tt = (TextType) getProperty(DESCRIPTION); return tt == null ? null : tt.getStringValue(); } public String getCategory() { ChoiceType tt = (ChoiceType) getProperty(CATEGORY); return tt == null ? null : tt.getStringValue(); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ResourceRefType.java0000644000000000000000000002554212645757426026024 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.Calendar; import java.util.List; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "stRef", namespace = "http://ns.adobe.com/xap/1.0/sType/ResourceRef#") public class ResourceRefType extends AbstractStructuredType { @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String DOCUMENT_ID = "documentID"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String FILE_PATH = "filePath"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String INSTANCE_ID = "instanceID"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String LAST_MODIFY_DATE = "lastModifyDate"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String MANAGE_TO = "manageTo"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String MANAGE_UI = "manageUI"; @PropertyType(type = Types.AgentName, card = Cardinality.Simple) public static final String MANAGER = "manager"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String MANAGER_VARIANT = "managerVariant"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String PART_MAPPING = "partMapping"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String RENDITION_PARAMS = "renditionParams"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String VERSION_ID = "versionID"; @PropertyType(type = Types.Choice, card = Cardinality.Simple) public static final String MASK_MARKERS = "maskMarkers"; @PropertyType(type = Types.RenditionClass, card = Cardinality.Simple) public static final String RENDITION_CLASS = "renditionClass"; @PropertyType(type = Types.Part, card = Cardinality.Simple) public static final String FROM_PART = "fromPart"; @PropertyType(type = Types.Part, card = Cardinality.Simple) public static final String TO_PART = "toPart"; public static final String ALTERNATE_PATHS = "alternatePaths"; /** * * @param metadata * The metadata to attach to this property */ public ResourceRefType(XMPMetadata metadata) { super(metadata); addNamespace(getNamespace(), getPreferedPrefix()); } public String getDocumentID() { TextType absProp = (TextType) getFirstEquivalentProperty(DOCUMENT_ID, URIType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setDocumentID(String value) { addSimpleProperty(DOCUMENT_ID, value); } public String getFilePath() { TextType absProp = (TextType) getFirstEquivalentProperty(FILE_PATH, URIType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setFilePath(String value) { addSimpleProperty(FILE_PATH, value); } public String getInstanceID() { TextType absProp = (TextType) getFirstEquivalentProperty(INSTANCE_ID, URIType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setInstanceID(String value) { addSimpleProperty(INSTANCE_ID, value); } public Calendar getLastModifyDate() { DateType absProp = (DateType) getFirstEquivalentProperty(LAST_MODIFY_DATE, DateType.class); if (absProp != null) { return absProp.getValue(); } else { return null; } } public void setLastModifyDate(Calendar value) { addSimpleProperty(LAST_MODIFY_DATE, value); } public String getManageUI() { TextType absProp = (TextType) getFirstEquivalentProperty(MANAGE_UI, URIType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setManageUI(String value) { addSimpleProperty(MANAGE_UI, value); } public String getManageTo() { TextType absProp = (TextType) getFirstEquivalentProperty(MANAGE_TO, URIType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setManageTo(String value) { addSimpleProperty(MANAGE_TO, value); } public String getManager() { TextType absProp = (TextType) getFirstEquivalentProperty(MANAGER, AgentNameType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setManager(String value) { addSimpleProperty(MANAGER, value); } public String getManagerVariant() { TextType absProp = (TextType) getFirstEquivalentProperty(MANAGER_VARIANT, TextType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setManagerVariant(String value) { addSimpleProperty(MANAGER_VARIANT, value); } public String getPartMapping() { TextType absProp = (TextType) getFirstEquivalentProperty(PART_MAPPING, TextType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setPartMapping(String value) { addSimpleProperty(PART_MAPPING, value); } public String getRenditionParams() { TextType absProp = (TextType) getFirstEquivalentProperty(RENDITION_PARAMS, TextType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setRenditionParams(String value) { addSimpleProperty(RENDITION_PARAMS, value); } public String getVersionID() { TextType absProp = (TextType) getFirstEquivalentProperty(VERSION_ID, TextType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setVersionID(String value) { addSimpleProperty(VERSION_ID, value); } public String getMaskMarkers() { TextType absProp = (TextType) getFirstEquivalentProperty(MASK_MARKERS, ChoiceType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setMaskMarkers(String value) { addSimpleProperty(MASK_MARKERS, value); } public String getRenditionClass() { TextType absProp = (TextType) getFirstEquivalentProperty(RENDITION_CLASS, RenditionClassType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setRenditionClass(String value) { addSimpleProperty(RENDITION_CLASS, value); } public String getFromPart() { TextType absProp = (TextType) getFirstEquivalentProperty(FROM_PART, PartType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setFromPart(String value) { addSimpleProperty(FROM_PART, value); } public String getToPart() { TextType absProp = (TextType) getFirstEquivalentProperty(TO_PART, PartType.class); if (absProp != null) { return absProp.getStringValue(); } else { return null; } } public void setToPart(String value) { addSimpleProperty(TO_PART, value); } public void addAlternatePath(String value) { ArrayProperty seq = (ArrayProperty) getFirstEquivalentProperty(ALTERNATE_PATHS, ArrayProperty.class); if (seq == null) { seq = getMetadata().getTypeMapping().createArrayProperty(null, getPreferedPrefix(), ALTERNATE_PATHS, Cardinality.Seq); addProperty(seq); } TypeMapping tm = getMetadata().getTypeMapping(); TextType tt = (TextType) tm.instanciateSimpleProperty(null, "rdf", "li", value, Types.Text); seq.addProperty(tt); } /** * Get Versions property * * @return version property to set */ public ArrayProperty getAlternatePathsProperty() { return (ArrayProperty) getFirstEquivalentProperty(ALTERNATE_PATHS, ArrayProperty.class); } /** * Get List of Versions values * * @return List of Versions values */ public List getAlternatePaths() { ArrayProperty seq = (ArrayProperty) getFirstEquivalentProperty(ALTERNATE_PATHS, ArrayProperty.class); if (seq != null) { return seq.getElementsAsString(); } else { return null; } } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/JobType.java0000644000000000000000000000435112645757426024305 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "stJob", namespace = "http://ns.adobe.com/xap/1.0/sType/Job#") public class JobType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String ID = "id"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String NAME = "name"; @PropertyType(type = Types.URL, card = Cardinality.Simple) public static final String URL = "url"; public JobType(XMPMetadata metadata) { this(metadata, null); } public JobType(XMPMetadata metadata, String fieldPrefix) { super(metadata, fieldPrefix); addNamespace(getNamespace(), getPrefix()); } public void setId(String id) { addSimpleProperty(ID, id); } public void setName(String name) { addSimpleProperty(NAME, name); } public void setUrl(String name) { addSimpleProperty(URL, name); } public String getId() { return getPropertyValueAsString(ID); } public String getName() { return getPropertyValueAsString(NAME); } public String getUrl() { return getPropertyValueAsString(URL); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/URLType.java0000644000000000000000000000237412645757426024240 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class URLType extends TextType { public URLType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PartType.java0000644000000000000000000000237612645757426024506 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class PartType extends TextType { public PartType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/BadFieldValueException.java0000644000000000000000000000373212645757426027241 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; /** * Exception thrown when Value found to set/get property content is not compatible with object specifications (typically * when trying to have a property in a type that is not compatible with specified original type of property concerned) * * @author a183132 * */ public class BadFieldValueException extends Exception { /** * */ private static final long serialVersionUID = 8100277682314632644L; /** * Create an instance of BadFieldValueException * * @param message * a description of the encountered problem */ public BadFieldValueException(String message) { super(message); } /** * Create an instance of BadFieldValueException * * @param message * a description of the encountered problem * @param cause * the cause of the exception */ public BadFieldValueException(String message, Throwable cause) { super(message, cause); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/RenditionClassType.java0000644000000000000000000000243612645757426026516 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class RenditionClassType extends TextType { public RenditionClassType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/GUIDType.java0000644000000000000000000000237612645757426024330 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class GUIDType extends TextType { public GUIDType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractComplexProperty.java0000644000000000000000000000707012645757426027572 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.xmpbox.XMPMetadata; public abstract class AbstractComplexProperty extends AbstractField { private ComplexPropertyContainer container; private Map namespaceToPrefix; public AbstractComplexProperty(XMPMetadata metadata, String propertyName) { super(metadata, propertyName); container = new ComplexPropertyContainer(); this.namespaceToPrefix = new HashMap(); } public void addNamespace(String namespace, String prefix) { this.namespaceToPrefix.put(namespace, prefix); } public String getNamespacePrefix(String namespace) { return this.namespaceToPrefix.get(namespace); } public Map getAllNamespacesWithPrefix() { return this.namespaceToPrefix; } /** * Add a property to the current structure * * @param obj * the property to add */ public final void addProperty(AbstractField obj) { container.addProperty(obj); } /** * Remove a property * * @param property * The property to remove */ public final void removeProperty(AbstractField property) { container.removeProperty(property); } // /** // * Return the container of this Array // * // * @return The complex property container that represents content of this // * property // */ public final ComplexPropertyContainer getContainer() { return container; } public final List getAllProperties() { return container.getAllProperties(); } public final AbstractField getProperty(String fieldName) { List list = container.getPropertiesByLocalName(fieldName); // return null if no property if (list == null) { return null; } // return the first element of the list return list.get(0); } public final ArrayProperty getArrayProperty(String fieldName) { List list = container.getPropertiesByLocalName(fieldName); // return null if no property if (list == null) { return null; } // return the first element of the list return (ArrayProperty) list.get(0); } protected final AbstractField getFirstEquivalentProperty(String localName, Class type) { return container.getFirstEquivalentProperty(localName, type); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/VersionType.java0000644000000000000000000000623212645757426025220 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.Calendar; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "stVer", namespace = "http://ns.adobe.com/xap/1.0/sType/Version#") public class VersionType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String COMMENTS = "comments"; @PropertyType(type = Types.ResourceEvent, card = Cardinality.Simple) public static final String EVENT = "event"; @PropertyType(type = Types.ProperName, card = Cardinality.Simple) public static final String MODIFIER = "modifier"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String MODIFY_DATE = "modifyDate"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String VERSION = "version"; /** * * @param metadata * The metadata to attach to this property */ public VersionType(XMPMetadata metadata) { super(metadata); addNamespace(getNamespace(), getPreferedPrefix()); } public String getComments() { return getPropertyValueAsString(COMMENTS); } public void setComments(String value) { addSimpleProperty(COMMENTS, value); } public ResourceEventType getEvent() { return (ResourceEventType) getFirstEquivalentProperty(EVENT, ResourceEventType.class); } public void setEvent(ResourceEventType value) { this.addProperty(value); } public Calendar getModifyDate() { return getDatePropertyAsCalendar(MODIFY_DATE); } public void setModifyDate(Calendar value) { addSimpleProperty(MODIFY_DATE, value); } public String getVersion() { return getPropertyValueAsString(VERSION); } public void setVersion(String value) { addSimpleProperty(VERSION, value); } public String getModifier() { return getPropertyValueAsString(MODIFIER); } public void setModifier(String value) { addSimpleProperty(MODIFIER, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/LocaleType.java0000644000000000000000000000240212645757426024765 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class LocaleType extends TextType { public LocaleType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/TextType.java0000644000000000000000000000462112645757426024517 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; /** * Object representation of a Text XMP type * * @author a183132 * */ public class TextType extends AbstractSimpleProperty { private String textValue; /** * Property Text type constructor (namespaceURI is given) * * @param metadata * The metadata to attach to this property * @param namespaceURI * the namespace URI to associate to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param value * The value to set */ public TextType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } /** * Set the property value * * @param value * The value to set */ public void setValue(Object value) { if (!(value instanceof String)) { throw new IllegalArgumentException("Value given is not allowed for the Text type : '" + value + "'"); } else { textValue = (String) value; } } @Override public String getStringValue() { return textValue; } @Override public Object getValue() { return textValue; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/AgentNameType.java0000644000000000000000000000241012645757426025424 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class AgentNameType extends TextType { public AgentNameType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractField.java0000644000000000000000000001022412645757426025434 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.xmpbox.XMPMetadata; /** * Astract Object representation of a XMP 'field' (-> Properties and specific Schemas) * * @author a183132 * */ public abstract class AbstractField { private XMPMetadata metadata; private String propertyName; private Map attributes; /** * Constructor of a XMP Field * * @param metadata * The metadata to attach to this field * @param propertyName * the local name to set for this field */ public AbstractField(XMPMetadata metadata, String propertyName) { this.metadata = metadata; this.propertyName = propertyName; attributes = new HashMap(); } /** * Get the propertyName (or localName) * * @return the local Name */ public final String getPropertyName() { return propertyName; } public final void setPropertyName(String value) { this.propertyName = value; } /** * Set a new attribute for this entity * * @param value * The Attribute property to add */ public final void setAttribute(Attribute value) { if (attributes.containsKey(value.getName())) { // if same name in element, attribute will be replaced attributes.remove(value.getName()); } if (value.getNamespace() == null) { attributes.put(value.getName(), value); } else { attributes.put(value.getName(), value); } } /** * Check if an attribute is declared for this entity * * @param qualifiedName * the full qualified name of the attribute concerned * @return true if attribute is present */ public final boolean containsAttribute(String qualifiedName) { return attributes.containsKey(qualifiedName); } /** * Get an attribute with its name in this entity * * @param qualifiedName * the full qualified name of the attribute wanted * @return The attribute property */ public final Attribute getAttribute(String qualifiedName) { return attributes.get(qualifiedName); } /** * Get attributes list defined for this entity * * @return Attributes list */ public final List getAllAttributes() { return new ArrayList(attributes.values()); } /** * Remove an attribute of this entity * * @param qualifiedName * the full qualified name of the attribute wanted */ public final void removeAttribute(String qualifiedName) { if (containsAttribute(qualifiedName)) { attributes.remove(qualifiedName); } } public final XMPMetadata getMetadata() { return metadata; } public abstract String getNamespace(); /** * Get the prefix of this entity * * @return the prefix specified */ public abstract String getPrefix(); } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/MIMEType.java0000644000000000000000000000237612645757426024327 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class MIMEType extends TextType { public MIMEType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/Attribute.java0000644000000000000000000000574512645757426024704 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; /** * Simple representation of an attribute * * @author a183132 * */ public class Attribute { private String nsURI; private String name; private String value; /** * Constructor of a new Attribute * * @param nsURI * namespaceURI of this attribute (could be null) * @param localName * localName of this attribute * @param value * value given to this attribute */ public Attribute(String nsURI, String localName, String value) { this.nsURI = nsURI; this.name = localName; this.value = value; } /** * Get the localName of this attribute * * @return local name of this attribute */ public String getName() { return name; } /** * Set the localName of this attribute * * @param lname * the local name to set */ public void setName(String lname) { name = lname; } /** * Get the namespace URI of this attribute * * @return the namespace URI associated to this attribute (could be null) */ public String getNamespace() { return nsURI; } /** * Set the namespace URI of this attribute * * @param nsURI * the namespace URI to set */ public void setNsURI(String nsURI) { this.nsURI = nsURI; } /** * Get value of this attribute * * @return value of this attribute */ public String getValue() { return value; } /** * Set value of this attribute * * @param value * the value to set for this attribute */ public void setValue(String value) { this.value = value; } public String toString() { StringBuilder sb = new StringBuilder(80); sb.append("[attr:{").append(nsURI).append("}").append(name).append("=").append(value).append("]"); return sb.toString(); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/XPathType.java0000644000000000000000000000240012645757426024610 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class XPathType extends TextType { public XPathType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/Cardinality.java0000644000000000000000000000234412645757426025174 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; public enum Cardinality { Simple(false), Bag(true), Seq(true), Alt(true); private boolean array; private Cardinality(boolean a) { this.array = a; } public boolean isArray() { return this.array; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractStructuredType.java0000644000000000000000000001127712645757426027430 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.Calendar; import org.apache.xmpbox.XMPMetadata; public abstract class AbstractStructuredType extends AbstractComplexProperty { protected static final String STRUCTURE_ARRAY_NAME = "li"; private String namespace; private String preferedPrefix; private String prefix; public AbstractStructuredType(XMPMetadata metadata) { this(metadata, null, null, null); } public AbstractStructuredType(XMPMetadata metadata, String namespaceURI) { this(metadata, namespaceURI, null, null); StructuredType st = this.getClass().getAnnotation(StructuredType.class); if (st != null) { // init with annotation this.namespace = st.namespace(); this.preferedPrefix = st.preferedPrefix(); } else { throw new IllegalArgumentException(" StructuredType annotation cannot be null"); } this.prefix = this.preferedPrefix; } public AbstractStructuredType(XMPMetadata metadata, String namespaceURI, String fieldPrefix, String propertyName) { super(metadata, propertyName); StructuredType st = this.getClass().getAnnotation(StructuredType.class); if (st != null) { // init with annotation this.namespace = st.namespace(); this.preferedPrefix = st.preferedPrefix(); } else { // init with parameters if (namespaceURI == null) { throw new IllegalArgumentException( "Both StructuredType annotation and namespace parameter cannot be null"); } this.namespace = namespaceURI; this.preferedPrefix = fieldPrefix; } this.prefix = fieldPrefix == null ? this.preferedPrefix : fieldPrefix; } /** * Get the namespace URI of this entity * * @return the namespace URI */ public final String getNamespace() { return namespace; } public final void setNamespace(String ns) { this.namespace = ns; } /** * Get the prefix of this entity * * @return the prefix specified */ public final String getPrefix() { return prefix; } public final void setPrefix(String pf) { this.prefix = pf; } public final String getPreferedPrefix() { return prefix; } protected void addSimpleProperty(String propertyName, Object value) { TypeMapping tm = getMetadata().getTypeMapping(); AbstractSimpleProperty asp = tm.instanciateSimpleField(getClass(), null, getPrefix(), propertyName, value); addProperty(asp); } protected String getPropertyValueAsString(String fieldName) { AbstractSimpleProperty absProp = (AbstractSimpleProperty) getProperty(fieldName); if (absProp == null) { return null; } else { return absProp.getStringValue(); } } protected Calendar getDatePropertyAsCalendar(String fieldName) { DateType absProp = (DateType) getFirstEquivalentProperty(fieldName, DateType.class); if (absProp != null) { return absProp.getValue(); } else { return null; } } public TextType createTextType(String propertyName, String value) { return getMetadata().getTypeMapping().createText(getNamespace(), getPrefix(), propertyName, value); } public ArrayProperty createArrayProperty(String propertyName, Cardinality type) { return getMetadata().getTypeMapping().createArrayProperty(getNamespace(), getPrefix(), propertyName, type); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/DefinedStructuredType.java0000644000000000000000000000352512645757426027220 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.HashMap; import java.util.Map; import org.apache.xmpbox.XMPMetadata; public class DefinedStructuredType extends AbstractStructuredType { private Map definedProperties = null; public DefinedStructuredType(XMPMetadata metadata, String namespaceURI, String fieldPrefix, String propertyName) { super(metadata, namespaceURI, fieldPrefix, propertyName); this.definedProperties = new HashMap(); } public DefinedStructuredType(XMPMetadata metadata) { super(metadata); this.definedProperties = new HashMap(); } public void addProperty(String name, PropertyType type) { definedProperties.put(name, type); } public Map getDefinedProperties() { return definedProperties; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/LayerType.java0000644000000000000000000000540112645757426024644 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XmpConstants; @StructuredType(preferedPrefix = "photoshop", namespace = "http://ns.adobe.com/photoshop/1.0/") public class LayerType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String LAYER_NAME = "LayerName"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String LAYER_TEXT = "LayerText"; public LayerType(XMPMetadata metadata) { super(metadata); setAttribute(new Attribute(XmpConstants.RDF_NAMESPACE, "parseType", "Resource")); } /** * Get The LayerName data * * @return the LayerName */ public String getLayerName() { AbstractField absProp = getFirstEquivalentProperty(LAYER_NAME, TextType.class); if (absProp != null) { return ((TextType) absProp).getStringValue(); } return null; } /** * Set LayerName * * @param image * the value of LayerName property to set */ public void setLayerName(String image) { this.addProperty(createTextType(LAYER_NAME, image)); } /** * Get The LayerText data * * @return the LayerText */ public String getLayerText() { AbstractField absProp = getFirstEquivalentProperty(LAYER_TEXT, TextType.class); if (absProp != null) { return ((TextType) absProp).getStringValue(); } return null; } /** * Set LayerText * * @param image * the value of LayerText property to set */ public void setLayerText(String image) { this.addProperty(createTextType(LAYER_TEXT, image)); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PDFATypeType.java0000644000000000000000000000504712645757426025152 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "pdfaType", namespace = "http://www.aiim.org/pdfa/ns/type#") public class PDFATypeType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String TYPE = "type"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String NS_URI = "namespaceURI"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String PREFIX = "prefix"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String DESCRIPTION = "description"; @PropertyType(type = Types.PDFAField, card = Cardinality.Seq) public static final String FIELD = "field"; public PDFATypeType(XMPMetadata metadata) { super(metadata); } public String getNamespaceURI() { URIType tt = (URIType) getProperty(NS_URI); return tt == null ? null : tt.getStringValue(); } public String getType() { TextType tt = (TextType) getProperty(TYPE); return tt == null ? null : tt.getStringValue(); } public String getPrefixValue() { TextType tt = (TextType) getProperty(PREFIX); return tt == null ? null : tt.getStringValue(); } public String getDescription() { TextType tt = (TextType) getProperty(DESCRIPTION); return tt == null ? null : tt.getStringValue(); } public ArrayProperty getFields() { return (ArrayProperty) getArrayProperty(FIELD); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractSimpleProperty.java0000644000000000000000000000650512645757426027416 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; /** * Abstract Class of an Simple XMP Property * * @author a183132 * */ public abstract class AbstractSimpleProperty extends AbstractField { private String namespace; private String prefix; private Object rawValue; /** * Property specific type constructor (namespaceURI is given) * * @param metadata * The metadata to attach to this property * @param namespaceURI * the specified namespace URI associated to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param value * the value to give */ public AbstractSimpleProperty(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, propertyName); setValue(value); this.namespace = namespaceURI; this.prefix = prefix; this.rawValue = value; } /** * Check and set new property value (in Element and in its Object Representation) * * @param value * Object value to set */ public abstract void setValue(Object value); /** * Return the property value * * @return a string */ public abstract String getStringValue(); public abstract Object getValue(); /** * Return the properties raw value. *

* The properties raw value is how it has been * serialized into the XML. Allows to retrieve the * low level date for validation purposes. *

* * @return the raw value. */ public Object getRawValue() { return rawValue; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[").append(this.getClass().getSimpleName()).append(":"); sb.append(getStringValue()).append("]"); return sb.toString(); } /** * Get the namespace URI of this entity * * @return the namespace URI */ public final String getNamespace() { return namespace; } /** * Get the prefix of this entity * * @return the prefix specified */ public String getPrefix() { return prefix; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/DateType.java0000644000000000000000000001024412645757426024446 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.io.IOException; import java.util.Calendar; import org.apache.xmpbox.DateConverter; import org.apache.xmpbox.XMPMetadata; /** * Object representation of a Date XMP type * * @author a183132 * */ public class DateType extends AbstractSimpleProperty { private Calendar dateValue; /** * Property Date type constructor (namespaceURI is given) * * @param metadata * The metadata to attach to this property * @param namespaceURI * the namespace URI to associate to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param value * The value to set for this property */ public DateType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } /** * Set property value * * @param value * the new Calendar element value * @throws InappropriateTypeException */ private void setValueFromCalendar(Calendar value) { dateValue = value; } /** * return the property value * * @return boolean */ public Calendar getValue() { return dateValue; } /** * Check if the value has a type which can be understood * * @param value * Object value to check * @return True if types are compatibles */ private boolean isGoodType(Object value) { if (value instanceof Calendar) { return true; } else if (value instanceof String) { try { DateConverter.toCalendar((String) value); return true; } catch (IOException e) { return false; } } return false; } /** * Set value of this property * * @param value * The value to set */ public void setValue(Object value) { if (!isGoodType(value)) { throw new IllegalArgumentException("Value given is not allowed for the Date type : " + value.getClass()); } else { // if string object if (value instanceof String) { setValueFromString((String) value); } else { // if Calendar setValueFromCalendar((Calendar) value); } } } public String getStringValue() { return DateConverter.toISO8601(dateValue); } /** * Set the property value with a String * * @param value * The String value */ private void setValueFromString(String value) { try { setValueFromCalendar(DateConverter.toCalendar((String) value)); } catch (IOException e) { // SHOULD NEVER HAPPEN // STRING HAS BEEN CHECKED BEFORE throw new IllegalArgumentException(e); } } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/BooleanType.java0000644000000000000000000000644012645757426025153 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; /** * Object representation of an Boolean XMP type * * @author a183132 * */ public class BooleanType extends AbstractSimpleProperty { public static final String TRUE = "True"; public static final String FALSE = "False"; private boolean booleanValue; /** * Property Boolean type constructor (namespaceURI is given) * * @param metadata * The metadata to attach to this property * @param namespaceURI * the namespace URI to associate to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param value * the value to give */ public BooleanType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } /** * return the property value * * @return boolean the property value */ public Boolean getValue() { return booleanValue; } /** * Set value of this property BooleanTypeObject accept String value or a boolean * * @param value * The value to set * */ public void setValue(Object value) { if (value instanceof Boolean) { booleanValue = ((Boolean) value).booleanValue(); } else if (value instanceof String) { // NumberFormatException is thrown (sub of InvalidArgumentException) String s = value.toString().trim().toUpperCase(); if ("TRUE".equals(s)) { booleanValue = true; } else if ("FALSE".equals(s)) { booleanValue = false; } else { // unknown value throw new IllegalArgumentException("Not a valid boolean value : '" + value + "'"); } } else { // invalid type of value throw new IllegalArgumentException("Value given is not allowed for the Boolean type."); } } @Override public String getStringValue() { return booleanValue ? TRUE : FALSE; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PropertiesDescription.java0000644000000000000000000000474512645757426027300 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Represents all properties known for a specific namespace Type and attributes associated to each properties are saved * If a specific type well declared is used, this class map it to a basic type * * @author a183132 * * Attribute management pre-implemented in order to give clues to make an attribute management system */ public class PropertiesDescription { private Map types; /** * PropertiesDescritption constructor * */ public PropertiesDescription() { types = new HashMap(); } /** * Get All Properties Name * * @return a list of properties qualifiedName */ public List getPropertiesName() { return new ArrayList(types.keySet()); } /** * Add a new property, an attributes list can be given or can be null * * @param name * new property name * @param type * Valuetype of the new property */ public void addNewProperty(String name, PropertyType type) { types.put(name, type); } /** * Return a type of a property from its qualifiedName * * @param name * The name of the property concerned * @return Type of property or null */ public PropertyType getPropertyType(String name) { return types.get(name); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PDFASchemaType.java0000644000000000000000000000460712645757426025432 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; @StructuredType(preferedPrefix = "pdfaSchema", namespace = "http://www.aiim.org/pdfa/ns/schema#") public class PDFASchemaType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String SCHEMA = "schema"; @PropertyType(type = Types.URI, card = Cardinality.Simple) public static final String NAMESPACE_URI = "namespaceURI"; @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String PREFIX = "prefix"; @PropertyType(type = Types.PDFAProperty, card = Cardinality.Seq) public static final String PROPERTY = "property"; @PropertyType(type = Types.PDFAType, card = Cardinality.Seq) public static final String VALUE_TYPE = "valueType"; public PDFASchemaType(XMPMetadata metadata) { super(metadata); } public String getNamespaceURI() { URIType tt = (URIType) getProperty(NAMESPACE_URI); return tt == null ? null : tt.getStringValue(); } public String getPrefixValue() { TextType tt = (TextType) getProperty(PREFIX); return tt == null ? null : tt.getStringValue(); } public ArrayProperty getProperty() { return (ArrayProperty) getArrayProperty(PROPERTY); } public ArrayProperty getValueType() { return (ArrayProperty) getArrayProperty(VALUE_TYPE); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/TypeMapping.java0000644000000000000000000004255212645757426025173 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.Calendar; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.QName; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.AdobePDFSchema; import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.PDFAExtensionSchema; import org.apache.xmpbox.schema.PDFAIdentificationSchema; import org.apache.xmpbox.schema.PhotoshopSchema; import org.apache.xmpbox.schema.XMPBasicJobTicketSchema; import org.apache.xmpbox.schema.XMPBasicSchema; import org.apache.xmpbox.schema.XMPMediaManagementSchema; import org.apache.xmpbox.schema.XMPRightsManagementSchema; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.schema.XMPSchemaFactory; import org.apache.xmpbox.schema.XmpSchemaException; public final class TypeMapping { private Map structuredMappings; // ns -> type private Map structuredNamespaces; // ns -> type private Map definedStructuredNamespaces; private Map definedStructuredMappings; private XMPMetadata metadata; private Map schemaMap; public TypeMapping(XMPMetadata metadata) { this.metadata = metadata; initialize(); } private static Class[] simplePropertyConstParams = new Class[] { XMPMetadata.class, String.class, String.class, String.class, Object.class }; private void initialize() { // structured types structuredMappings = new HashMap(); structuredNamespaces = new HashMap(); for (Types type : Types.values()) { if (type.isStructured()) { Class clz = type.getImplementingClass().asSubclass( AbstractStructuredType.class); StructuredType st = clz.getAnnotation(StructuredType.class); String ns = st.namespace(); PropertiesDescription pm = initializePropMapping(clz); structuredNamespaces.put(ns, type); structuredMappings.put(type, pm); } } // define structured types definedStructuredNamespaces = new HashMap(); definedStructuredMappings = new HashMap(); // schema schemaMap = new HashMap(); addNameSpace(XMPBasicSchema.class); addNameSpace(DublinCoreSchema.class); addNameSpace(PDFAExtensionSchema.class); addNameSpace(XMPMediaManagementSchema.class); addNameSpace(AdobePDFSchema.class); addNameSpace(PDFAIdentificationSchema.class); addNameSpace(XMPRightsManagementSchema.class); addNameSpace(PhotoshopSchema.class); addNameSpace(XMPBasicJobTicketSchema.class); } public void addToDefinedStructuredTypes(String typeName, String ns, PropertiesDescription pm) { definedStructuredNamespaces.put(ns, typeName); definedStructuredMappings.put(typeName, pm); } public PropertiesDescription getDefinedDescriptionByNamespace(String namespace) { String dt = definedStructuredNamespaces.get(namespace); return this.definedStructuredMappings.get(dt); } public AbstractStructuredType instanciateStructuredType(Types type, String propertyName) throws BadFieldValueException { try { Class propertyTypeClass = type.getImplementingClass().asSubclass( AbstractStructuredType.class); Constructor construct = propertyTypeClass .getConstructor(new Class[] { XMPMetadata.class }); AbstractStructuredType tmp = construct.newInstance(metadata); tmp.setPropertyName(propertyName); return tmp; } catch (InvocationTargetException e) { throw new BadFieldValueException("Failed to instanciate structured type : " + type, e); } catch (IllegalArgumentException e) { throw new BadFieldValueException("Failed to instanciate structured type : " + type, e); } catch (InstantiationException e) { throw new BadFieldValueException("Failed to instanciate structured type : " + type, e); } catch (IllegalAccessException e) { throw new BadFieldValueException("Failed to instanciate structured type : " + type, e); } catch (SecurityException e) { throw new BadFieldValueException("Failed to instanciate structured type : " + type, e); } catch (NoSuchMethodException e) { throw new BadFieldValueException("Failed to instanciate structured type : " + type, e); } } public AbstractStructuredType instanciateDefinedType(String propertyName, String namespace) { return new DefinedStructuredType(metadata, namespace, null, propertyName); } public AbstractSimpleProperty instanciateSimpleProperty(String nsuri, String prefix, String name, Object value, Types type) { // constructor parameters Object[] params = new Object[] { metadata, nsuri, prefix, name, value }; // type try { Class clz = type.getImplementingClass().asSubclass( AbstractSimpleProperty.class); Constructor cons = clz.getConstructor(simplePropertyConstParams); return cons.newInstance(params); } catch (NoSuchMethodError e) { throw new IllegalArgumentException("Failed to instanciate property", e); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Failed to instanciate property", e); } catch (InstantiationException e) { throw new IllegalArgumentException("Failed to instanciate property", e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Failed to instanciate property", e); } catch (InvocationTargetException e) { throw new IllegalArgumentException("Failed to instanciate property", e); } catch (SecurityException e) { throw new IllegalArgumentException("Failed to instanciate property", e); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Failed to instanciate property", e); } } public AbstractSimpleProperty instanciateSimpleField(Class clz, String nsuri, String prefix, String propertyName, Object value) { PropertiesDescription pm = initializePropMapping(clz); PropertyType simpleType = pm.getPropertyType(propertyName); Types type = simpleType.type(); return instanciateSimpleProperty(nsuri, prefix, propertyName, value, type); } /** * Check if a namespace used reference a complex basic types (like Thumbnails) * * @param namespace * The namespace URI to check * @return True if namespace URI is a reference for a complex basic type */ public boolean isStructuredTypeNamespace(String namespace) { return structuredNamespaces.containsKey(namespace); } public boolean isDefinedTypeNamespace(String namespace) { return definedStructuredNamespaces.containsKey(namespace); } // public String getTypeInArray (String type) { // int pos = type.indexOf(' '); // if (pos<0) { // // not array // return null; // } else { // return type.substring(pos+1); // } // } public boolean isDefinedType(String name) { return this.definedStructuredMappings.containsKey(name); } private void addNameSpace(Class classSchem) { StructuredType st = classSchem.getAnnotation(StructuredType.class); String ns = st.namespace(); schemaMap.put(ns, new XMPSchemaFactory(ns, classSchem, initializePropMapping(classSchem))); } public void addNewNameSpace(String ns, String prefered) { PropertiesDescription mapping = new PropertiesDescription(); schemaMap.put(ns, new XMPSchemaFactory(ns, XMPSchema.class, mapping)); } public PropertiesDescription getStructuredPropMapping(Types type) { return structuredMappings.get(type); } /** * Return the specialized schema class representation if it's known (create and add it to metadata). In other cases, * return null * * @param metadata * Metadata to link the new schema * @param namespace * The namespace URI * @return Schema representation * @throws XmpSchemaException * When Instancing specified Object Schema failed */ public XMPSchema getAssociatedSchemaObject(XMPMetadata metadata, String namespace, String prefix) throws XmpSchemaException { if (schemaMap.containsKey(namespace)) { XMPSchemaFactory factory = schemaMap.get(namespace); return factory.createXMPSchema(metadata, prefix); } else { XMPSchemaFactory factory = getSchemaFactory(namespace); return factory != null ? factory.createXMPSchema(metadata, prefix) : null; } } public XMPSchemaFactory getSchemaFactory(String namespace) { return schemaMap.get(namespace); } /** * Say if a specific namespace is known * * @param namespace * The namespace URI checked * @return True if namespace URI is known */ public boolean isDefinedSchema(String namespace) { return schemaMap.containsKey(namespace); } public boolean isDefinedNamespace(String namespace) { return isDefinedSchema(namespace) || isStructuredTypeNamespace(namespace) || isDefinedTypeNamespace(namespace); } /** * Give type of specified property in specified schema (given by its namespaceURI) * * @param name * the property Qualified Name * @return Property type declared for namespace specified, null if unknown */ public PropertyType getSpecifiedPropertyType(QName name) throws BadFieldValueException { XMPSchemaFactory factory = getSchemaFactory(name.getNamespaceURI()); if (factory != null) { // found in schema return factory.getPropertyType(name.getLocalPart()); } else { // try in structured Types st = structuredNamespaces.get(name.getNamespaceURI()); if (st != null) { return createPropertyType(st, Cardinality.Simple); } else { // try in defined String dt = definedStructuredNamespaces.get(name.getNamespaceURI()); if (dt == null) { // not found throw new BadFieldValueException("No descriptor found for " + name); } else { return createPropertyType(Types.DefinedType, Cardinality.Simple); } } } } public PropertiesDescription initializePropMapping(Class classSchem) { PropertiesDescription propMap = new PropertiesDescription(); Field[] fields = classSchem.getFields(); String propName = null; for (Field field : fields) { if (field.isAnnotationPresent(PropertyType.class)) { try { propName = (String) field.get(propName); } catch (Exception e) { throw new IllegalArgumentException( "couldn't read one type declaration, please check accessibility and declaration of fields annoted in " + classSchem.getName(), e); } PropertyType propType = field.getAnnotation(PropertyType.class); propMap.addNewProperty(propName, propType); } } return propMap; } public BooleanType createBoolean(String namespaceURI, String prefix, String propertyName, boolean value) { return new BooleanType(metadata, namespaceURI, prefix, propertyName, value); } public DateType createDate(String namespaceURI, String prefix, String propertyName, Calendar value) { return new DateType(metadata, namespaceURI, prefix, propertyName, value); } public IntegerType createInteger(String namespaceURI, String prefix, String propertyName, int value) { return new IntegerType(metadata, namespaceURI, prefix, propertyName, value); } public RealType createReal(String namespaceURI, String prefix, String propertyName, float value) { return new RealType(metadata, namespaceURI, prefix, propertyName, value); } public TextType createText(String namespaceURI, String prefix, String propertyName, String value) { return new TextType(metadata, namespaceURI, prefix, propertyName, value); } public ProperNameType createProperName(String namespaceURI, String prefix, String propertyName, String value) { return new ProperNameType(metadata, namespaceURI, prefix, propertyName, value); } public URIType createURI(String namespaceURI, String prefix, String propertyName, String value) { return new URIType(metadata, namespaceURI, prefix, propertyName, value); } public URLType createURL(String namespaceURI, String prefix, String propertyName, String value) { return new URLType(metadata, namespaceURI, prefix, propertyName, value); } public RenditionClassType createRenditionClass(String namespaceURI, String prefix, String propertyName, String value) { return new RenditionClassType(metadata, namespaceURI, prefix, propertyName, value); } public PartType createPart(String namespaceURI, String prefix, String propertyName, String value) { return new PartType(metadata, namespaceURI, prefix, propertyName, value); } public MIMEType createMIMEType(String namespaceURI, String prefix, String propertyName, String value) { return new MIMEType(metadata, namespaceURI, prefix, propertyName, value); } public LocaleType createLocale(String namespaceURI, String prefix, String propertyName, String value) { return new LocaleType(metadata, namespaceURI, prefix, propertyName, value); } public GUIDType createGUID(String namespaceURI, String prefix, String propertyName, String value) { return new GUIDType(metadata, namespaceURI, prefix, propertyName, value); } public ChoiceType createChoice(String namespaceURI, String prefix, String propertyName, String value) { return new ChoiceType(metadata, namespaceURI, prefix, propertyName, value); } public AgentNameType createAgentName(String namespaceURI, String prefix, String propertyName, String value) { return new AgentNameType(metadata, namespaceURI, prefix, propertyName, value); } public XPathType createXPath(String namespaceURI, String prefix, String propertyName, String value) { return new XPathType(metadata, namespaceURI, prefix, propertyName, value); } public ArrayProperty createArrayProperty(String namespace, String prefix, String propertyName, Cardinality type) { return new ArrayProperty(metadata, namespace, prefix, propertyName, type); } public static PropertyType createPropertyType(final Types type, final Cardinality card) { return new PropertyType() { public Class annotationType() { return null; } public Types type() { return type; } public Cardinality card() { return card; } }; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/Types.java0000644000000000000000000000606712645757426024043 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; public enum Types { Structured(false, null, null), DefinedType(false, null, null), // basic Text(true, null, TextType.class), Date(true, null, DateType.class), Boolean(true, null, BooleanType.class), Integer( true, null, IntegerType.class), Real(true, null, RealType.class), ProperName(true, Text, ProperNameType.class), Locale(true, Text, LocaleType.class), AgentName(true, Text, AgentNameType.class), GUID(true, Text, GUIDType.class), XPath(true, Text, XPathType.class), Part(true, Text, PartType.class), URL(true, Text, URLType.class), URI(true, Text, URIType.class), Choice(true, Text, ChoiceType.class), MIMEType(true, Text, MIMEType.class), LangAlt(true, Text, TextType.class), RenditionClass( true, Text, RenditionClassType.class), Layer(false, Structured, LayerType.class), Thumbnail(false, Structured, ThumbnailType.class), ResourceEvent(false, Structured, ResourceEventType.class), ResourceRef(false, Structured, ResourceRefType.class), Version(false, Structured, VersionType.class), PDFASchema(false, Structured, PDFASchemaType.class), PDFAField(false, Structured, PDFAFieldType.class), PDFAProperty(false, Structured, PDFAPropertyType.class), PDFAType(false, Structured, PDFATypeType.class), Job(false, Structured, JobType.class); // For defined types private boolean simple; private Types basic; private Class clz; private Types(boolean s, Types b, Class c) { this.simple = s; this.basic = b; this.clz = c; } public boolean isSimple() { return simple; } public boolean isBasic() { return basic == null; } public boolean isStructured() { return basic == Structured; } public boolean isDefined() { return this == DefinedType; } public Types getBasic() { return basic; } public Class getImplementingClass() { return clz; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ArrayProperty.java0000644000000000000000000000602312645757426025552 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.apache.xmpbox.XMPMetadata; /** * Object representation of a Complex XMP Property (Represents Ordered, Unordered and Alternative Arrays builder) * * @author a183132 * */ public class ArrayProperty extends AbstractComplexProperty { private Cardinality arrayType; private String namespace; private String prefix; /** * Contructor of a complex property * * @param metadata * The metadata to attach to this property * @param namespace * The namespace URI to associate to this property * @param prefix * The prefix to set for this property * @param propertyName * The local Name of this property * @param type * type of complexProperty (Bag, Seq, Alt) */ public ArrayProperty(XMPMetadata metadata, String namespace, String prefix, String propertyName, Cardinality type) { super(metadata, propertyName); this.arrayType = type; this.namespace = namespace; this.prefix = prefix; } public Cardinality getArrayType() { return arrayType; } public List getElementsAsString() { List retval = null; retval = new ArrayList(); Iterator it = getContainer().getAllProperties().iterator(); AbstractSimpleProperty tmp; while (it.hasNext()) { tmp = (AbstractSimpleProperty) it.next(); retval.add(tmp.getStringValue()); } retval = Collections.unmodifiableList(retval); return retval; } /** * Get the namespace URI of this entity * * @return the namespace URI */ public final String getNamespace() { return namespace; } /** * Get the prefix of this entity * * @return the prefix specified */ public String getPrefix() { return prefix; } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ComplexPropertyContainer.java0000644000000000000000000001627212645757426027755 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Object representation for arrays content This Class could be used to define directly a property with more than one * field (structure) and also schemas * * @author a183132 * */ public class ComplexPropertyContainer /* extends AbstractField */ { private List properties; // private Map attributes; /** * Complex Property type constructor (namespaceURI is given) */ public ComplexPropertyContainer() { properties = new ArrayList(); // attributes = new HashMap(); } // /** // * Get an attribute with its name in this entity // * // * @param qualifiedName // * the full qualified name of the attribute wanted // * @return The attribute property // */ // public Attribute getAttribute(String qualifiedName) { // return attributes.get(qualifiedName); // } // /** // * Get attributes list defined for this entity // * // * @return Attributes list // */ // public List getAllAttributes() { // return new ArrayList(attributes.values()); // } // /** // * Set a new attribute for this entity // * // * @param value // * The Attribute property to add // */ // public void setAttribute(Attribute value) { // if (attributes.containsKey(value.getQualifiedName())) { // // if same name in element, attribute will be replaced // attributes.remove(value.getQualifiedName()); // } // if (value.getNamespace() == null) { // attributes.put(value.getQualifiedName(), value); // } else { // attributes.put(value.getQualifiedName(), value); // } // } // /** // * Remove an attribute of this entity // * // * @param qualifiedName // * the full qualified name of the attribute wanted // */ // public void removeAttribute(String qualifiedName) { // if (containsAttribute(qualifiedName)) { // attributes.remove(qualifiedName); // } // // } // /** // * Check if an attribute is declared for this entity // * // * @param qualifiedName // * the full qualified name of the attribute concerned // * @return true if attribute is present // */ // public boolean containsAttribute(String qualifiedName) { // return attributes.containsKey(qualifiedName); // } /** * Give the first property found in this container with type and localname expected * * @param localName * the localname of property wanted * @param type * the property type of property wanted * @return the property wanted */ protected AbstractField getFirstEquivalentProperty(String localName, Class type) { List list = getPropertiesByLocalName(localName); if (list != null) { for (AbstractField abstractField : list) { if (abstractField.getClass().equals(type)) { return abstractField; } } } return null; } /** * Add a property to the current structure * * @param obj * the property to add */ public void addProperty(AbstractField obj) { if (containsProperty(obj)) { removeProperty(obj); } properties.add(obj); } /** * Return all children associated to this property * * @return All Properties contained in this container */ public List getAllProperties() { return properties; } /** * Return all properties with this specified localName * * @param localName * the local name wanted * @return All properties with local name which match with localName given */ public List getPropertiesByLocalName(String localName) { List absFields = getAllProperties(); if (absFields != null) { List list = new ArrayList(); for (AbstractField abstractField : absFields) { if (abstractField.getPropertyName().equals(localName)) { list.add(abstractField); } } if (list.size() == 0) { return null; } else { return list; } } return null; } /** * Check if two property are similar * * @param prop1 * First property * @param prop2 * Second property * @return True if these properties are equals */ public boolean isSameProperty(AbstractField prop1, AbstractField prop2) { if (prop1.getClass().equals(prop2.getClass())) { String pn1 = prop1.getPropertyName(); String pn2 = prop2.getPropertyName(); if (pn1 == null) { return pn2 == null; } else { if (pn1.equals(pn2)) { return prop1.equals(prop2); } } } return false; } /** * Check if a XMPFieldObject is in the complex property * * @param property * The property to check * @return True if property is present in this container */ public boolean containsProperty(AbstractField property) { Iterator it = getAllProperties().iterator(); AbstractField tmp; while (it.hasNext()) { tmp = it.next(); if (isSameProperty(tmp, property)) { return true; } } return false; } /** * Remove a property * * @param property * The property to remove */ public void removeProperty(AbstractField property) { if (containsProperty(property)) { properties.remove(property); } } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/ProperNameType.java0000644000000000000000000000241212645757426025637 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class ProperNameType extends TextType { public ProperNameType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/URIType.java0000644000000000000000000000237312645757426024234 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import org.apache.xmpbox.XMPMetadata; public class URIType extends TextType { public URIType(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) { super(metadata, namespaceURI, prefix, propertyName, value); } } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/type/PropertyType.java0000644000000000000000000000307212645757426025416 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * to be used at runtime */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) /** * Annotation to specify type expected for a property */ public @interface PropertyType { /** * get valuetype defined in this description that must be used to build properties descriptions in schema * descriptions * * */ // String propertyType(); Types type(); Cardinality card(); } pdfbox-1.8.11/xmpbox/src/main/java/org/apache/xmpbox/XMPMetadata.java0000644000000000000000000003741712645757426024066 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.xmpbox.schema.AdobePDFSchema; import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.PDFAExtensionSchema; import org.apache.xmpbox.schema.PDFAIdentificationSchema; import org.apache.xmpbox.schema.PhotoshopSchema; import org.apache.xmpbox.schema.XMPBasicJobTicketSchema; import org.apache.xmpbox.schema.XMPBasicSchema; import org.apache.xmpbox.schema.XMPMediaManagementSchema; import org.apache.xmpbox.schema.XMPRightsManagementSchema; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.schema.XmpSchemaException; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.type.TypeMapping; /** * Object representation of XMPMetaData Be CAREFUL: typically, metadata should contain only one schema for each type * (each NSURI). Retrieval of common schemas (like DublinCore) is based on this fact and take the first schema of this * type encountered. However, XmpBox allow you to place schemas of same type with different prefix. If you do that, you * must retrieve all schemas by yourself with getAllSchemas or with getSchema which use prefix parameter. * * @author a183132 * */ public class XMPMetadata { private String xpacketId = null; private String xpacketBegin = null; private String xpacketBytes = null; private String xpacketEncoding = null; private String xpacketEndData = XmpConstants.DEFAULT_XPACKET_END; private List schemas; private TypeMapping typeMapping; /** * Contructor of an empty default XMPMetaData * * @throws CreateXMPMetadataException * If DOM Document associated could not be created */ protected XMPMetadata() { this(XmpConstants.DEFAULT_XPACKET_BEGIN, XmpConstants.DEFAULT_XPACKET_ID, XmpConstants.DEFAULT_XPACKET_BYTES, XmpConstants.DEFAULT_XPACKET_ENCODING); } /** * creates blank XMP doc with specified parameters * * @throws CreateXMPMetadataException * @param xpacketBegin * Value of xpacketBegin * @param xpacketId * Value of xpacketId * @param xpacketBytes * Value of xpacketBytes * @param xpacketEncoding * Value of xpacket encoding * @throws CreateXMPMetadataException * If DOM Document associated could not be created */ protected XMPMetadata(String xpacketBegin, String xpacketId, String xpacketBytes, String xpacketEncoding) { this.schemas = new ArrayList(); this.typeMapping = new TypeMapping(this); this.xpacketBegin = xpacketBegin; this.xpacketId = xpacketId; this.xpacketBytes = xpacketBytes; this.xpacketEncoding = xpacketEncoding; } public static XMPMetadata createXMPMetadata() { return new XMPMetadata(); } public static XMPMetadata createXMPMetadata(String xpacketBegin, String xpacketId, String xpacketBytes, String xpacketEncoding) { return new XMPMetadata(xpacketBegin, xpacketId, xpacketBytes, xpacketEncoding); } public TypeMapping getTypeMapping() { return this.typeMapping; } /** * Get xpacketBytes * * @return value of xpacketBytes field */ public String getXpacketBytes() { return xpacketBytes; } /** * Get xpacket encoding * * @return value of xpacket Encoding field */ public String getXpacketEncoding() { return xpacketEncoding; } /** * Get xpacket Begin * * @return value of xpacket Begin field */ public String getXpacketBegin() { return xpacketBegin; } /** * Get xpacket Id * * @return value of xpacket Id field */ public String getXpacketId() { return xpacketId; } /** * Get All Schemas declared in this metadata representation * * @return List of declared schemas */ public List getAllSchemas() { ArrayList schem = new ArrayList(); Iterator it = schemas.iterator(); while (it.hasNext()) { schem.add((XMPSchema) it.next()); } return schem; } /** * Set special XPACKET END PI * * @param data * The XPacket End value */ public void setEndXPacket(String data) { xpacketEndData = data; } /** * get XPACKET END PI * * @return XPACKET END Value */ public String getEndXPacket() { return xpacketEndData; } /** * Return the schema corresponding to this nsURI BE CAREFUL: typically, Metadata should contains one schema for each * type this method return the first schema encountered corresponding to this NSURI Return null if unknown * * @param nsURI * The namespace URI corresponding to the schema wanted * @return The Class Schema representation */ public XMPSchema getSchema(String nsURI) { Iterator it = schemas.iterator(); XMPSchema tmp; while (it.hasNext()) { tmp = it.next(); if (tmp.getNamespace().equals(nsURI)) { return tmp; } } return null; } public XMPSchema getSchema(Class clz) { StructuredType st = clz.getAnnotation(StructuredType.class); return getSchema(st.namespace()); } public void clearSchemas() { schemas.clear(); } /** * Return the schema corresponding to this nsURI and a prefix This method is here to treat metadata which embed more * than one time the same schema It permit to retrieve a specific schema with its prefix * * @param prefix * The prefix fixed in the schema wanted * @param nsURI * The namespace URI corresponding to the schema wanted * @return The Class Schema representation */ public XMPSchema getSchema(String prefix, String nsURI) { Iterator it = getAllSchemas().iterator(); XMPSchema tmp; while (it.hasNext()) { tmp = it.next(); if (tmp.getNamespace().equals(nsURI) && tmp.getPrefix().equals(prefix)) { return tmp; } } return null; } /** * Set a unspecialized schema * * @param nsPrefix * The prefix wanted for the schema * @param nsURI * The namespace URI wanted for the schema * @return The schema added in order to work on it */ public XMPSchema createAndAddDefaultSchema(String nsPrefix, String nsURI) { XMPSchema schem = new XMPSchema(this, nsURI, nsPrefix); schem.setAboutAsSimple(""); addSchema(schem); return schem; } /** * Create and add a default PDFA Extension schema to this metadata This method return the created schema to enter * information This PDFAExtension is created with all default namespaces used in PDFAExtensionSchema * * @return PDFAExtension schema added in order to work on it */ public PDFAExtensionSchema createAndAddPDFAExtensionSchemaWithDefaultNS() { PDFAExtensionSchema pdfAExt = new PDFAExtensionSchema(this); pdfAExt.setAboutAsSimple(""); addSchema(pdfAExt); return pdfAExt; } /** * Create and add a default XMPRights schema to this metadata This method return the created schema to enter * information * * @return schema added in order to work on it */ public XMPRightsManagementSchema createAndAddXMPRightsManagementSchema() { XMPRightsManagementSchema rights = new XMPRightsManagementSchema(this); rights.setAboutAsSimple(""); addSchema(rights); return rights; } /** * Create and add a default PDFA Extension schema to this metadata This method return the created schema to enter * information This PDFAExtension is created with specified list of namespaces * * @param namespaces * Special namespaces list to use * @return schema added in order to work on it * @throws XmpSchemaException * If namespaces list not contains PDF/A Extension namespace URI */ public PDFAExtensionSchema createAndAddPDFAExtensionSchemaWithNS(Map namespaces) throws XmpSchemaException { PDFAExtensionSchema pdfAExt = new PDFAExtensionSchema(this); pdfAExt.setAboutAsSimple(""); addSchema(pdfAExt); return pdfAExt; } /** * Get the PDFA Extension schema This method return null if not found * * @return The PDFAExtension schema or null if not declared */ public PDFAExtensionSchema getPDFExtensionSchema() { return (PDFAExtensionSchema) getSchema(PDFAExtensionSchema.class); } /** * Create and add a default PDFA Identification schema to this metadata This method return the created schema to * enter information * * @return schema added in order to work on it */ public PDFAIdentificationSchema createAndAddPFAIdentificationSchema() { PDFAIdentificationSchema pdfAId = new PDFAIdentificationSchema(this); pdfAId.setAboutAsSimple(""); addSchema(pdfAId); return pdfAId; } /** * Get the PDFA Identification schema This method return null if not found * * @return The PDFAIdentificationSchema schema or null if not declared */ public PDFAIdentificationSchema getPDFIdentificationSchema() { return (PDFAIdentificationSchema) getSchema(PDFAIdentificationSchema.class); } /** * Create and add a default Dublin Core schema to this metadata This method return the created schema to enter * information * * @return schema added in order to work on it */ public DublinCoreSchema createAndAddDublinCoreSchema() { DublinCoreSchema dc = new DublinCoreSchema(this); dc.setAboutAsSimple(""); addSchema(dc); return dc; } /** * Create and add a default Basic Job Ticket schema to this metadata This method return the created schema to enter * information * * @return schema added in order to work on it */ public XMPBasicJobTicketSchema createAndAddBasicJobTicketSchema() { XMPBasicJobTicketSchema sc = new XMPBasicJobTicketSchema(this); sc.setAboutAsSimple(""); addSchema(sc); return sc; } /** * Get the Dublin Core schema This method return null if not found * * @return The DublinCoreSchema schema or null if not declared */ public DublinCoreSchema getDublinCoreSchema() { return (DublinCoreSchema) getSchema(DublinCoreSchema.class); } /** * Get the Basic JOb Ticket Schema schema This method return null if not found * * @return The XMPBasicJobTicketSchema schema or null if not declared */ public XMPBasicJobTicketSchema getBasicJobTicketSchema() { return (XMPBasicJobTicketSchema) getSchema(XMPBasicJobTicketSchema.class); } /** * Get the XMPRights schema This method return null if not found * * @return The XMPRightsManagementSchema schema or null if not declared */ public XMPRightsManagementSchema getXMPRightsManagementSchema() { return (XMPRightsManagementSchema) getSchema(XMPRightsManagementSchema.class); } /** * Get the Photoshop schema This method return null if not found * * @return The PhotoshopSchema schema or null if not declared */ public PhotoshopSchema getPhotoshopSchema() { return (PhotoshopSchema) getSchema(PhotoshopSchema.PHOTOSHOPURI); } /** * Create and add a XMP Basic schema to this metadata This method return the created schema to enter information * * @return schema added in order to work on it */ public XMPBasicSchema createAndAddXMPBasicSchema() { XMPBasicSchema xmpB = new XMPBasicSchema(this); xmpB.setAboutAsSimple(""); addSchema(xmpB); return xmpB; } /** * Get the XMP Basic schema This method return null if not found * * @return The XMPBasicSchema schema or null if not declared */ public XMPBasicSchema getXMPBasicSchema() { return (XMPBasicSchema) getSchema(XMPBasicSchema.class); } /** * Create and add a XMP Media Management schema to this metadata This method return the created schema to enter * information * * @return schema added in order to work on it */ public XMPMediaManagementSchema createAndAddXMPMediaManagementSchema() { XMPMediaManagementSchema xmpMM = new XMPMediaManagementSchema(this); xmpMM.setAboutAsSimple(""); addSchema(xmpMM); return xmpMM; } /*** * create and add Photoshop Schema to this metadata. This method return the created schema to enter information * * @return schema added in order to work on it */ public PhotoshopSchema createAndAddPhotoshopSchema() { PhotoshopSchema photoshop = new PhotoshopSchema(this); photoshop.setAboutAsSimple(""); addSchema(photoshop); return photoshop; } /** * Get the XMP Media Management schema This method return null if not found * * @return The XMPMediaManagementSchema schema or null if not declared */ public XMPMediaManagementSchema getXMPMediaManagementSchema() { return (XMPMediaManagementSchema) getSchema(XMPMediaManagementSchema.class); } /** * Create and add an Adobe PDF schema to this metadata This method return the created schema to enter information * * @return schema added in order to work on it */ public AdobePDFSchema createAndAddAdobePDFSchema() { AdobePDFSchema pdf = new AdobePDFSchema(this); pdf.setAboutAsSimple(""); addSchema(pdf); return pdf; } /** * Get the Adobe PDF schema This method return null if not found * * @return The AdobePDFSchema schema or null if not declared */ public AdobePDFSchema getAdobePDFSchema() { return (AdobePDFSchema) getSchema(AdobePDFSchema.class); } /** * Add a schema to the current structure * * @param obj * the schema to add */ public void addSchema(XMPSchema obj) { schemas.add(obj); } /** * Remove a schema * * @param schema * The schema to remove */ public void removeSchema(XMPSchema schema) { schemas.remove(schema); } } pdfbox-1.8.11/xmpbox/src/main/appended-resources/0000755000000000000000000000000012645757426020424 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/appended-resources/META-INF/0000755000000000000000000000000012645757426021564 5ustar rootrootpdfbox-1.8.11/xmpbox/src/main/appended-resources/META-INF/LICENSE.txt0000644000000000000000000000163712645757426023416 0ustar rootrootCONTRIBUTIONS TO THE ORIGINAL CODEBASE Apache xmpbox is based contributions made to the original PaDaF project Copyright 2010 Atos Worldline SAS Licensed by Atos Worldline SAS under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. Atos Worldline SAS licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pdfbox-1.8.11/xmpbox/src/main/appended-resources/META-INF/NOTICE.txt0000644000000000000000000000014712645757426023310 0ustar rootrootBased on source code originally developed in the PaDaF project. Copyright (c) 2010 Atos Worldline SAS pdfbox-1.8.11/xmpbox/src/test/0000755000000000000000000000000012645757426014667 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/0000755000000000000000000000000012645757426016701 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/validxmp/0000755000000000000000000000000012645757426020525 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/validxmp/ghost2.xmp0000644000000000000000000002360012645757426022462 0ustar rootroot application/pdf 2009-04-26T16:56:29-06:00 LaTeX with hyperref package 2012-07-26T07:23:35-04:00 2012-07-26T07:23:35-04:00 pdfTeX-1.40.3 False uuid:bbc5e922-8a33-4f23-803a-96bc4f7d99fb uuid:cd6bd7b5-aaa8-4bb7-a216-6a8900317f2c default 1 1 B http://ns.adobe.com/pdf/1.3/ pdf Adobe PDF Schema internal A name object indicating whether the document has been modified to include trapping information Trapped Text http://ns.adobe.com/xap/1.0/mm/ xmpMM XMP Media Management Schema internal UUID based identifier for specific incarnation of a document InstanceID URI internal The common identifier for all versions and renditions of a document. OriginalDocumentID URI pdfbox-1.8.11/xmpbox/src/test/resources/validxmp/attr_as_props.xml0000644000000000000000000000406312645757426024132 0ustar rootroot 2010-01-28T14:07:18-05:00 2010-01-28T14:07:18-05:00 UnknownApplication Untitled pdfbox-1.8.11/xmpbox/src/test/resources/validxmp/override_ns.rdf0000644000000000000000000003164612645757426023553 0ustar rootroot FrameMaker 7.0 2009-11-08T19:16:29+01:00 2001-02-05T12:32:48Z 2009-11-08T19:16:29+01:00 Copyright 2006-2008 PDF/A Competence Center Acrobat Distiller 8.1.0 (Windows) application/pdf TechNote 0001: PDF/A-1 and Namespaces PDF/A Competence Center Copyright 2006-2008 PDF/A Competence Center uuid:586d5239-0535-e540-99ba-d4cfaa3b9c0e uuid:417197b4-283d-3147-b689-63d2be1e4f45 default 1 1 A http://ns.adobe.com/pdf/1.3/ pdf Adobe PDF Schema internal A name object indicating whether the document has been modified to include trapping information Trapped Text http://ns.adobe.com/pdfx/1.3/ pdfx PDF/X ID Schema internal ID of PDF/X standard GTS_PDFXVersion Text internal Conformance level of PDF/X standard GTS_PDFXConformance Text internal Company creating the PDF Company Text internal Date when document was last modified SourceModified Text http://ns.adobe.com/xap/1.0/mm/ xmpMM XMP Media Management Schema internal UUID based identifier for specific incarnation of a document InstanceID URI http://www.aiim.org/pdfa/ns/id/ pdfaid PDF/A ID Schema internal Part of PDF/A standard part Integer internal Amendment of PDF/A standard amd Text internal Conformance level of PDF/A standard conformance Text http://ns.adobe.com/pdf/1.3/ pdf Adobe PDF external Copyright information (mirrored from legacy Document Info field) Copyright Text http://ns.adobe.com/pdfx/1.3/ pdfx Adobe pdfx external Copyright information (mirrored from legacy Document Info field) Copyright Text pdfbox-1.8.11/xmpbox/src/test/resources/validxmp/emptyli.xml0000644000000000000000000000276012645757426022737 0ustar rootroot application/pdf title value pdfbox-1.8.11/xmpbox/src/test/resources/validxmp/metadata.rdf0000644000000000000000000002523012645757426023004 0ustar rootroot ADEP Document Services - DocConverter 10.0.0 "_MuhimbiKeywords_ ; _MuhimbiKeywords_ "; _MuhimbiKeywords_ ; _MuhimbiKeywords_ 2012-03-06T06:30:15Z 2012-03-06T06:30:15Z _MuhimbiCreator_ 2012-03-06T06:30:15Z uuid:dc9dc762-fb1e-11e0-0000-80af8e58d932011-10-17T14:24:38+01:00 converted Conversion to PDF/A was executed. ADEP Document Services - DocConverter 10.0.0 2012-03-06T06:30:15Z uuid:80aa9b06-33eb-2e23-7934-0eca006422df application/pdf _MuhimbiTitle_ _MuhimbiAuthor_ _MuhimbiKeywords_ ; _MuhimbiKeywords_ _MuhimbiKeywords_ _MuhimbiKeywords_ 1 B 2005 The XMP Media Management Schema is primarily for use by digital asset management (DAM) systems. http://ns.adobe.com/xap/1.0/mm/ xmpMM InstanceID URI internal UUID based identifier for specific incarnation of a document http://ns.adobe.com/pdfx/1.3/ pdfx GTS_PDFXConformance Text internal Conformance level of PDF/X standard GTS_PDFXVersion Text internal ID of PDF/X standard pdfbox-1.8.11/xmpbox/src/test/resources/validxmp/Notepad++_A1b.xmp0000644000000000000000000002477512645757426023475 0ustar rootroot FOP 0.20.5 convert application/pdf Notepad boring convert Bill 2012-07-26T07:59:36-04:00 2012-07-26T08:00:08-04:00 2012-07-26T08:00:08-04:00 uuid:8a3c03a1-f3be-4863-969c-6d349620a025 uuid:7aa05387-41d3-413a-9d61-164b354d5971 default 1 converted uuid:ae8e9f71-6013-4ade-a3e0-ed408df8fe9f converted to PDF/A-1b Preflight 2012-07-26T07:59:55-04:00 converted uuid:e83fa70f-efc1-4fc7-85b6-8bd61398025b converted to PDF/A-1b Preflight 2012-07-26T08:00:01-04:00 converted uuid:01a1cd62-6038-4c9e-a683-c8ea0c0ce5ac converted to PDF/A-1b Preflight 2012-07-26T08:00:07-04:00 1 B http://ns.adobe.com/pdf/1.3/ pdf Adobe PDF Schema internal A name object indicating whether the document has been modified to include trapping information Trapped Text http://ns.adobe.com/xap/1.0/mm/ xmpMM XMP Media Management Schema internal UUID based identifier for specific incarnation of a document InstanceID URI internal The common identifier for all versions and renditions of a document. OriginalDocumentID URI http://www.aiim.org/pdfa/ns/id/ pdfaid PDF/A ID Schema internal Part of PDF/A standard part Integer internal Amendment of PDF/A standard amd Text internal Conformance level of PDF/A standard conformance Text pdfbox-1.8.11/xmpbox/src/test/resources/validxmp/history2.rdf0000644000000000000000000002016012645757426023004 0ustar rootroot The XMP Media Management Schema is primarily for use by digital asset management (DAM) systems. http://ns.adobe.com/xap/1.0/mm/ xmpMM InstanceID URI internal UUID based identifier for specific incarnation of a document http://ns.adobe.com/pdfx/1.3/ pdfx GTS_PDFXConformance Text internal Conformance level of PDF/X standard GTS_PDFXVersion Text internal ID of PDF/X standard pdfbox-1.8.11/xmpbox/src/test/resources/org/0000755000000000000000000000000012645757426017470 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/org/apache/0000755000000000000000000000000012645757426020711 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/0000755000000000000000000000000012645757426022226 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/valueTypeDescription.xml0000644000000000000000000000266612645757426027144 0ustar rootroot mailaddress http://test.withfield.com/vt/ madn mailaddress value name Text personal name domain Text domain value pdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/parser/0000755000000000000000000000000012645757426023522 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/parser/ThumbisartorStyle.xml0000644000000000000000000001240712645757426027754 0ustar rootroot uuid:09C78666-2F91-3A9C-92AF-3691A6D594F7 2008-01-18T16:59:54+01:00 2008-01-18T16:59:54+01:00 2008-01-18T16:59:54+01:00 162 216 JPEG /9j/4AAQSkZJRgABAgEASABIAAD 162 216 JPEG /9j/4AAQSkZJRgABAgEASABIAAD ACME E-Mail Schema http://www.acme.com/ns/email/1/ acmeemail Delivery-Date Date internal date of email delivery From mailaddress internal sender email address mailaddress http://www.acme.com/ns/email/1/mailaddress/ mailaddress value add name Text plaintext name mailto Text email address 2007-11-09T09:55:36+01:00 John Doe john@acme.com 1 B 1:2005 PDFlib Personalization Server 7.0.2p5 (Win32) pdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/parser/AltBagSeqTest.xml0000644000000000000000000002163312645757426026714 0ustar rootroot application/pdf sujet titre sujet createur producer mots clefs 2010-03-10T14:14:45+01:00 2010-03-10T14:14:45+01:00 Outil de creation B 1 nom Text external Nom de la personne concernée par la demande prenom seq Text external Prenom de la personne concernée par la demande dateNaissance Date external Date de naissance de la personne concernée par la demande codePays Text external Code du pays de la personne concernée pays Text external Pays de la personne concernée cdp Text external Code postal de la personne concernée ville Text external Nom de la ville de la personne concernée dpt Text external Departement de la personne concernée bagTest bag Text external Test bag LangAltTest Lang Alt external Test Lang alt Schema Acte de naissance http://test.apache.com/xap/adn/ adn 59183 Spécimen 1985-01-05 Dunkerque 59 FR France Natacha Marguerite Suzanne bagval1 bagval2 Default information Infos français pdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/parser/isartorStyleXMPOK.xml0000644000000000000000000001117712645757426027576 0ustar rootroot uuid:09C78666-2F91-3A9C-92AF-3691A6D594F7 2008-01-18T16:59:54+01:00 2008-01-18T16:59:54+01:00 2008-01-18T16:59:54+01:00 ACME E-Mail Schema http://www.acme.com/ns/email/1/ acmeemail Delivery-Date Date internal date of email delivery From mailaddress internal sender email address mailaddress http://www.acme.com/ns/email/1/mailaddress/ mailaddress value add name Text plaintext name mailto Text email address 2007-11-09T09:55:36+01:00 John Doe john@acme.com 1 B 1:2005 PDFlib Personalization Server 7.0.2p5 (Win32) pdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/parser/empty_list.xml0000644000000000000000000000623012645757426026436 0ustar rootroot uuid:09C78666-2F91-3A9C-92AF-3691A6D594F7 a text value 1 g bailleul 1 copied 1 a la mano 1 a text value 2 g bailleul 2 copied 2 a la mano 2 a text value 3 g bailleul 3 copied 3 a la mano 3 pdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/parser/structured_recursive.xml0000644000000000000000000000556412645757426030551 0ustar rootroot uuid:09C78666-2F91-3A9C-92AF-3691A6D594F7 a text value g bailleul copied a la mano pdfbox-1.8.11/xmpbox/src/test/resources/org/apache/xmpbox/propertiesDescription.xml0000644000000000000000000000313512645757426027352 0ustar rootroot firstname Sample of firstname description lastname Sample of lastname description birth-place Sample of birth-place description birth-date Sample of birth-date description birth-country Sample of birth-country description pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/0000755000000000000000000000000012645757426021054 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/noxpacketend.xml0000644000000000000000000000273312645757426024266 0ustar rootroot application/pdf title value pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/noroot.xml0000644000000000000000000000175412645757426023125 0ustar rootroot pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/invalidroot2.xml0000644000000000000000000000206112645757426024211 0ustar rootroot pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/undefinedschema.xml0000644000000000000000000000256712645757426024732 0ustar rootroot 2007-11-09T09:55:36+01:00 John Doe john@acme.com pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/noxpacket.xml0000644000000000000000000000264512645757426023601 0ustar rootroot application/pdf title value pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/undefinedpropertyindefinedschema.xml0000644000000000000000000000751212645757426030400 0ustar rootroot ACME E-Mail Schema http://www.acme.com/ns/email/1/ acmeemail Delivery-Date Date internal date of email delivery From mailaddress internal sender email address mailaddress http://www.acme.com/ns/email/1/mailaddress/ mailaddress value add name Text plaintext name 2007-11-09T09:55:36+01:00 John Doe john@acme.com pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/invalidroot.xml0000644000000000000000000000177112645757426024136 0ustar rootroot A text value pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/undefinedstructuredindefinedschema.xml0000644000000000000000000000544012645757426030716 0ustar rootroot ACME E-Mail Schema http://www.acme.com/ns/email/1/ acmeemail Delivery-Date Date internal date of email delivery From mailaddress internal sender email address 2007-11-09T09:55:36+01:00 John Doe john@acme.com pdfbox-1.8.11/xmpbox/src/test/resources/invalidxmp/tworoot.xml0000644000000000000000000000216212645757426023314 0ustar rootroot pdfbox-1.8.11/xmpbox/src/test/java/0000755000000000000000000000000012645757426015610 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/0000755000000000000000000000000012645757426016377 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/apache/0000755000000000000000000000000012645757426017620 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/0000755000000000000000000000000012645757426021135 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/0000755000000000000000000000000012645757426022375 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/XMPBasicTest.java0000644000000000000000000000555712645757426025522 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.Types; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class XMPBasicTest extends AbstractXMPSchemaTest { public XMPBasicTest(String prop, PropertyType type, Object val) { super(prop, type, val); } @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); schema = metadata.createAndAddXMPBasicSchema(); schemaClass = XMPBasicSchema.class; } @Parameters public static Collection initializeParameters() throws Exception { List data = new ArrayList(); data.add(wrapProperty("Advisory", Types.XPath, Cardinality.Bag, new String[] { "xpath1", "xpath2" })); data.add(wrapProperty("BaseURL", Types.URL, "URL")); data.add(wrapProperty("CreateDate", Types.Date, Calendar.getInstance())); data.add(wrapProperty("CreatorTool", Types.AgentName, "CreatorTool")); data.add(wrapProperty("Identifier", Types.Text, Cardinality.Bag, new String[] { "id1", "id2" })); data.add(wrapProperty("Label", Types.Text, "label")); data.add(wrapProperty("MetadataDate", Types.Date, Calendar.getInstance())); data.add(wrapProperty("ModifyDate", Types.Date, Calendar.getInstance())); data.add(wrapProperty("Nickname", Types.Text, "nick name")); data.add(wrapProperty("Rating", Types.Integer, 7)); data.add(wrapProperty("Thumbnails", Types.Thumbnail, Cardinality.Alt, null)); return data; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/PhotoshopSchemaTest.java0000644000000000000000000000662712645757426027217 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Collection; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.Types; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class PhotoshopSchemaTest extends AbstractSchemaTester { protected PhotoshopSchema schema = null; public PhotoshopSchema getSchema() { return schema; } @Before public void before() throws Exception { super.before(); schema = xmp.createAndAddPhotoshopSchema(); } public PhotoshopSchemaTest(String fieldName, Types type, Cardinality card) { super(fieldName, type, card); } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { "AncestorID", Types.URI, Cardinality.Simple }); result.add(new Object[] { "AuthorsPosition", Types.Text, Cardinality.Simple }); result.add(new Object[] { "CaptionWriter", Types.ProperName, Cardinality.Simple }); result.add(new Object[] { "Category", Types.Text, Cardinality.Simple }); result.add(new Object[] { "City", Types.Text, Cardinality.Simple }); result.add(new Object[] { "ColorMode", Types.Integer, Cardinality.Simple }); result.add(new Object[] { "Country", Types.Text, Cardinality.Simple }); result.add(new Object[] { "Credit", Types.Text, Cardinality.Simple }); result.add(new Object[] { "DateCreated", Types.Date, Cardinality.Simple }); result.add(new Object[] { "Headline", Types.Text, Cardinality.Simple }); result.add(new Object[] { "History", Types.Text, Cardinality.Simple }); result.add(new Object[] { "ICCProfile", Types.Text, Cardinality.Simple }); result.add(new Object[] { "Instructions", Types.Text, Cardinality.Simple }); result.add(new Object[] { "Source", Types.Text, Cardinality.Simple }); result.add(new Object[] { "State", Types.Text, Cardinality.Simple }); result.add(new Object[] { "SupplementalCategories", Types.Text, Cardinality.Bag }); result.add(new Object[] { "TransmissionReference", Types.Text, Cardinality.Simple }); result.add(new Object[] { "Urgency", Types.Integer, Cardinality.Simple }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/AdobePDFTest.java0000644000000000000000000000730712645757426025453 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.Types; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class AdobePDFTest extends AbstractXMPSchemaTest { @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); schema = metadata.createAndAddAdobePDFSchema(); schemaClass = AdobePDFSchema.class; } @Parameters public static Collection initializeParameters() throws Exception { List data = new ArrayList(); data.add(wrapProperty("Keywords", Types.Text, "kw1 kw2 kw3")); data.add(wrapProperty("PDFVersion", Types.Text, "1.4")); data.add(wrapProperty("Producer", Types.Text, "testcase")); return data; } public AdobePDFTest(String property, PropertyType type, Object value) { super(property, type, value); } @Test public void testPDFAIdentification() throws Exception { AdobePDFSchema schem = metadata.createAndAddAdobePDFSchema(); String keywords = "keywords ihih"; String pdfVersion = "1.4"; String producer = "producer"; schem.setKeywords(keywords); schem.setPDFVersion(pdfVersion); // Check get null if property not defined Assert.assertNull(schem.getProducer()); schem.setProducer(producer); Assert.assertEquals("pdf", schem.getKeywordsProperty().getPrefix()); Assert.assertEquals("Keywords", schem.getKeywordsProperty().getPropertyName()); Assert.assertEquals(keywords, schem.getKeywords()); Assert.assertEquals("pdf", schem.getPDFVersionProperty().getPrefix()); Assert.assertEquals("PDFVersion", schem.getPDFVersionProperty().getPropertyName()); Assert.assertEquals(pdfVersion, schem.getPDFVersion()); Assert.assertEquals("pdf", schem.getProducerProperty().getPrefix()); Assert.assertEquals("Producer", schem.getProducerProperty().getPropertyName()); Assert.assertEquals(producer, schem.getProducer()); } @Test(expected = BadFieldValueException.class) public void testBadPDFAConformanceId() throws BadFieldValueException { PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema(); String conformance = "kiohiohiohiohio"; pdfaid.setConformance(conformance); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/AbstractXMPSchemaTest.java0000644000000000000000000005240612645757426027360 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Calendar; import java.util.List; import java.util.Map; import junit.framework.Assert; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AgentNameType; import org.apache.xmpbox.type.BooleanType; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.DateType; import org.apache.xmpbox.type.IntegerType; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.ThumbnailType; import org.apache.xmpbox.type.TypeMapping; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.type.URIType; import org.apache.xmpbox.type.URLType; import org.junit.Test; public abstract class AbstractXMPSchemaTest { protected XMPMetadata metadata; protected String property; protected PropertyType type; protected XMPSchema schema; protected Class schemaClass; protected Object value; public AbstractXMPSchemaTest(String property, PropertyType type, Object value) { this.property = property; this.value = value; this.type = type; } public static Object[] wrapProperty(String name, Types type, Object value) { return wrapProperty(name, type, Cardinality.Simple, value); } public static Object[] wrapProperty(String name, Types type, Cardinality card, Object value) { // if (type==Types.Boolean) { // Assert.assertTrue(value instanceof Boolean); // } else if (type==Types.Text) { // Assert.assertTrue(value instanceof String); // } else if (type==Types.Integer) { // Assert.assertTrue(value instanceof Integer); // } else if (type==Types.Date) { // Assert.assertTrue(value instanceof Calendar); // } else if (type==Types.URL) { // Assert.assertTrue(value instanceof String); // } return new Object[] { name, TypeMapping.createPropertyType(type, card), value }; } @Test public void testGetSetValue() throws Exception { if (type.type() == Types.Text && type.card() == Cardinality.Simple) { testGetSetTextValue(); } else if (type.type() == Types.Boolean && type.card() == Cardinality.Simple) { testGetSetBooleanValue(); } else if (type.type() == Types.Integer && type.card() == Cardinality.Simple) { testGetSetIntegerValue(); } else if (type.type() == Types.Date && type.card() == Cardinality.Simple) { testGetSetDateValue(); } else if (type.type() == Types.URI && type.card() == Cardinality.Simple) { testGetSetTextValue(); } else if (type.type() == Types.URL && type.card() == Cardinality.Simple) { testGetSetTextValue(); } else if (type.type() == Types.AgentName && type.card() == Cardinality.Simple) { testGetSetTextValue(); } else if (type.type() == Types.LangAlt && type.card() == Cardinality.Simple) { // do nothing } else if (type.type() == Types.ResourceRef && type.card() == Cardinality.Simple) { // do nothing } else if (type.card() != Cardinality.Simple) { // do nothing } else { throw new Exception("Unknown type : " + type); } } @Test public void testGetSetProperty() throws Exception { if (type.type() == Types.Text && type.card() == Cardinality.Simple) { testGetSetTextProperty(); } else if (type.type() == Types.URI && type.card() == Cardinality.Simple) { testGetSetURIProperty(); } else if (type.type() == Types.URL && type.card() == Cardinality.Simple) { testGetSetURLProperty(); } else if (type.type() == Types.AgentName && type.card() == Cardinality.Simple) { testGetSetAgentNameProperty(); } else if (type.type() == Types.Boolean && type.card() == Cardinality.Simple) { testGetSetBooleanProperty(); } else if (type.type() == Types.Integer && type.card() == Cardinality.Simple) { testGetSetIntegerProperty(); } else if (type.type() == Types.Date && type.card() == Cardinality.Simple) { testGetSetDateProperty(); } else if (type.type() == Types.Text && type.card() == Cardinality.Seq) { testGetSetTextListValue("seq"); } else if (type.type() == Types.Version && type.card() == Cardinality.Seq) { testGetSetTextListValue("seq"); } else if (type.type() == Types.Text && type.card() == Cardinality.Bag) { testGetSetTextListValue("bag"); } else if (type.type() == Types.ProperName && type.card() == Cardinality.Bag) { testGetSetTextListValue("bag"); } else if (type.type() == Types.XPath && type.card() == Cardinality.Bag) { testGetSetTextListValue("bag"); } else if (type.type() == Types.Date && type.card() == Cardinality.Seq) { testGetSetDateListValue("seq"); } else if (type.type() == Types.LangAlt && type.card() == Cardinality.Simple) { testGetSetLangAltValue(); } else if (type.type() == Types.Thumbnail && type.card() == Cardinality.Alt) { testGetSetThumbnail(); } else { throw new Exception("Unknown type : " + type); } Field[] fields = schemaClass.getFields(); for (Field field : fields) { if (field.isAnnotationPresent(PropertyType.class)) { if (!field.get(schema).equals(property)) { PropertyType pt = field.getAnnotation(PropertyType.class); if (pt.type() == Types.LangAlt) { // do not check method existence } else if (pt.type() == Types.Thumbnail && pt.card() == Cardinality.Alt) { // do not check method existence } else if (pt.type() == Types.ResourceRef) { // do not check method existence } else if (pt.type() == Types.Version && pt.card() == Cardinality.Seq) { // do not check method existence } else { // type test PropertyType spt = retrievePropertyType(field.get(schema).toString()); String getNameProperty = "get" + prepareName(field.get(schema).toString(), spt) + "Property"; Method getMethod = schemaClass.getMethod(getNameProperty); Assert.assertNull(getNameProperty + " should return null when testing " + property, getMethod.invoke(schema)); // value test String getNameValue = "get" + prepareName(field.get(schema).toString(), spt); getMethod = schemaClass.getMethod(getNameValue); Assert.assertNotNull(getNameValue + " method should exist", getMethod); Assert.assertNull(getNameValue + " should return null when testing " + property, getMethod.invoke(schema)); } } } } } protected PropertyType retrievePropertyType(String prop) throws IllegalArgumentException, IllegalAccessException { Field[] fields = schemaClass.getFields(); for (Field field : fields) { if (field.isAnnotationPresent(PropertyType.class)) { PropertyType pt = field.getAnnotation(PropertyType.class); if (field.get(schema).equals(prop)) { return pt; } } } return type; } protected String firstUpper(String name) { StringBuilder sb = new StringBuilder(name.length()); sb.append(name.substring(0, 1).toUpperCase()); sb.append(name.substring(1)); return sb.toString(); } protected String prepareName(String prop, PropertyType type) { String fu = firstUpper(prop); StringBuilder sb = new StringBuilder(fu.length() + 1); sb.append(fu); if (fu.endsWith("s")) { // do nothing } else if (fu.endsWith("y")) { // do nothing } else if (type.card() != Cardinality.Simple) { sb.append("s"); } return sb.toString(); } protected String setMethod(String prop) { StringBuilder sb = new StringBuilder(3 + prop.length()); sb.append("set").append(prepareName(prop, type)).append("Property"); return sb.toString(); } protected String addMethod(String prop) { String fu = firstUpper(prop); StringBuilder sb = new StringBuilder(3 + prop.length()); sb.append("add").append(fu); return sb.toString(); } protected String getMethod(String prop) { String fu = firstUpper(prop); StringBuilder sb = new StringBuilder(3 + prop.length()); sb.append("get").append(fu).append("Property"); return sb.toString(); } protected String setValueMethod(String prop) { String fu = firstUpper(prop); StringBuilder sb = new StringBuilder(8 + prop.length()); sb.append("set").append(fu); return sb.toString(); } protected String getValueMethod(String prop) { StringBuilder sb = new StringBuilder(8 + prop.length()); sb.append("get").append(prepareName(prop, type)); return sb.toString(); } protected String addToValueMethod(String prop) { String fu = firstUpper(prop); StringBuilder sb = new StringBuilder(10 + prop.length()); sb.append("add").append(fu); return sb.toString(); } protected void testGetSetBooleanProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); BooleanType bt = new BooleanType(metadata, null, schema.getPrefix(), property, value); Method setMethod = schemaClass.getMethod(setName, BooleanType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, bt); Boolean found = ((BooleanType) getMethod.invoke(schema)).getValue(); Assert.assertEquals(value, found); } protected void testGetSetDateProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); DateType dt = new DateType(metadata, null, schema.getPrefix(), property, value); Method setMethod = schemaClass.getMethod(setName, DateType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, dt); Calendar found = ((DateType) getMethod.invoke(schema)).getValue(); Assert.assertEquals(value, found); } protected void testGetSetIntegerProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); IntegerType it = new IntegerType(metadata, null, schema.getPrefix(), property, value); Method setMethod = schemaClass.getMethod(setName, IntegerType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, it); Integer found = ((IntegerType) getMethod.invoke(schema)).getValue(); Assert.assertEquals(value, found); } protected void testGetSetTextProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); TextType tt = metadata.getTypeMapping().createText(null, schema.getPrefix(), property, (String) value); Method setMethod = schemaClass.getMethod(setName, TextType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, tt); String found = ((TextType) getMethod.invoke(schema)).getStringValue(); Assert.assertEquals(value, found); } protected void testGetSetURIProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); URIType tt = metadata.getTypeMapping().createURI(null, schema.getPrefix(), property, (String) value); Method setMethod = schemaClass.getMethod(setName, URIType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, tt); String found = ((TextType) getMethod.invoke(schema)).getStringValue(); Assert.assertEquals(value, found); } protected void testGetSetURLProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); URLType tt = metadata.getTypeMapping().createURL(null, schema.getPrefix(), property, (String) value); Method setMethod = schemaClass.getMethod(setName, URLType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, tt); String found = ((TextType) getMethod.invoke(schema)).getStringValue(); Assert.assertEquals(value, found); } protected void testGetSetAgentNameProperty() throws Exception { String setName = setMethod(property); String getName = getMethod(property); AgentNameType tt = metadata.getTypeMapping() .createAgentName(null, schema.getPrefix(), property, (String) value); Method setMethod = schemaClass.getMethod(setName, AgentNameType.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, tt); String found = ((AgentNameType) getMethod.invoke(schema)).getStringValue(); Assert.assertEquals(value, found); } protected void testGetSetTextListValue(String tp) throws Exception { String setName = addToValueMethod(property); String getName = getValueMethod(property); String[] svalue = (String[]) value; Arrays.sort(svalue); // push all Method setMethod = schemaClass.getMethod(setName, String.class); for (String string : svalue) { setMethod.invoke(schema, string); } // retrieve Method getMethod = schemaClass.getMethod(getName); List fields = (List) getMethod.invoke(schema); for (String field : fields) { Assert.assertTrue(field + " should be found in list", Arrays.binarySearch(svalue, field) >= 0); } } protected void testGetSetDateListValue(String tp) throws Exception { String setName = addToValueMethod(property); String getName = getValueMethod(property); Calendar[] svalue = (Calendar[]) value; Arrays.sort(svalue); // push all Method setMethod = schemaClass.getMethod(setName, Calendar.class); for (Calendar inst : svalue) { setMethod.invoke(schema, inst); } // retrieve Method getMethod = schemaClass.getMethod(getName); List fields = (List) getMethod.invoke(schema); for (Calendar field : fields) { Assert.assertTrue(field + " should be found in list", Arrays.binarySearch(svalue, field) >= 0); } } protected void testGetSetThumbnail() throws Exception { String addName = addMethod(property); String getName = getMethod(property); Method setMethod = schemaClass.getMethod(addName, Integer.class, Integer.class, String.class, String.class); Method getMethod = schemaClass.getMethod(getName); Integer height = 162; Integer width = 400; String format = "JPEG"; String img = "/9j/4AAQSkZJRgABAgEASABIAAD"; setMethod.invoke(schema, height, width, format, img); List found = ((List) getMethod.invoke(schema)); Assert.assertTrue(found.size() == 1); ThumbnailType t1 = found.get(0); Assert.assertEquals(height, t1.getHeight()); Assert.assertEquals(width, t1.getWidth()); Assert.assertEquals(format, t1.getFormat()); Assert.assertEquals(img, t1.getImage()); } protected void testGetSetLangAltValue() throws Exception { String setName = addToValueMethod(property); String getName = getValueMethod(property); Map svalue = (Map) value; // push all Method setMethod = schemaClass.getMethod(setName, String.class, String.class); for (Map.Entry inst : svalue.entrySet()) { setMethod.invoke(schema, inst.getKey(), inst.getValue()); } // retrieve String getLanguagesName = "get" + firstUpper(property) + "Languages"; Method getLanguages = schemaClass.getMethod(getLanguagesName); List lgs = (List) getLanguages.invoke(schema); for (String string : lgs) { Method getMethod = schemaClass.getMethod(getName, String.class); String res = (String) getMethod.invoke(schema, string); Assert.assertEquals(res, svalue.get(string)); } } protected void testGetSetURLValue() throws Exception { String setName = addToValueMethod(property); String getName = getValueMethod(property); String svalue = (String) value; // push all Method setMethod = schemaClass.getMethod(setName, String.class, String.class); setMethod.invoke(schema, property, svalue); // retrieve String getLanguagesName = "get" + firstUpper(property) + "Languages"; Method getLanguages = schemaClass.getMethod(getLanguagesName); List lgs = (List) getLanguages.invoke(schema); for (String string : lgs) { Method getMethod = schemaClass.getMethod(getName, String.class); String res = (String) getMethod.invoke(schema, string); Assert.assertEquals(res, svalue); } } protected void testGetSetTextValue() throws Exception { String setName = setValueMethod(property); String getName = getValueMethod(property); Method setMethod = schemaClass.getMethod(setName, String.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, value); String found = (String) getMethod.invoke(schema); Assert.assertEquals(value, found); } protected void testGetSetBooleanValue() throws Exception { String setName = setValueMethod(property); String getName = getValueMethod(property); Method setMethod = schemaClass.getMethod(setName, Boolean.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, value); Boolean found = (Boolean) getMethod.invoke(schema); Assert.assertEquals(value, found); } protected void testGetSetDateValue() throws Exception { String setName = setValueMethod(property); String getName = getValueMethod(property); Method setMethod = schemaClass.getMethod(setName, Calendar.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, value); Calendar found = (Calendar) getMethod.invoke(schema); Assert.assertEquals(value, found); } protected void testGetSetIntegerValue() throws Exception { String setName = setValueMethod(property); String getName = getValueMethod(property); Method setMethod = schemaClass.getMethod(setName, Integer.class); Method getMethod = schemaClass.getMethod(getName); setMethod.invoke(schema, value); Integer found = (Integer) getMethod.invoke(schema); Assert.assertEquals(value, found); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/AbstractSchemaTester.java0000644000000000000000000002033612645757426027317 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import junit.framework.Assert; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.AbstractSimpleProperty; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.TypeMapping; import org.apache.xmpbox.type.TypeTestingHelper; import org.apache.xmpbox.type.Types; import org.apache.xmpbox.xml.DomXmpParser; import org.junit.Test; public abstract class AbstractSchemaTester { protected XMPMetadata xmp; protected String fieldName; protected Types type; protected Cardinality cardinality; protected TypeMapping typeMapping = null; protected DomXmpParser builder; public void before() throws Exception { builder = new DomXmpParser(); xmp = XMPMetadata.createXMPMetadata(); typeMapping = xmp.getTypeMapping(); } protected abstract XMPSchema getSchema(); protected Class getSchemaClass() { return getSchema().getClass(); } public AbstractSchemaTester(String fieldName, Types type, Cardinality card) { this.fieldName = fieldName; this.type = type; this.cardinality = card; } @Test public void testInitializedToNull() throws Exception { // default method Assert.assertNull(getSchema().getProperty(fieldName)); // accessor if (cardinality == Cardinality.Simple) { String getter = TypeTestingHelper.calculateSimpleGetter(fieldName); Method get = getSchemaClass().getMethod(getter, new Class[0]); Object result = get.invoke(getSchema(), new Object[0]); Assert.assertNull(result); } else { // arrays String getter = TypeTestingHelper.calculateArrayGetter(fieldName); Method get = getSchemaClass().getMethod(getter, new Class[0]); Object result = get.invoke(getSchema(), new Object[0]); Assert.assertNull(result); } } @Test public void testSettingValue() throws Exception { if (cardinality != Cardinality.Simple) return; // only test simple properties Object value = TypeTestingHelper.getJavaValue(type); AbstractSimpleProperty property = getSchema().instanciateSimple(fieldName, value); getSchema().addProperty(property); String qn = getPropertyQualifiedName(fieldName); Assert.assertNotNull(getSchema().getProperty(fieldName)); // check other properties not modified List fields = TypeTestingHelper.getXmpFields(getSchemaClass()); for (Field field : fields) { // do not check the current name String fqn = getPropertyQualifiedName(field.get(null).toString()); if (!fqn.equals(qn)) { Assert.assertNull(getSchema().getProperty(fqn)); } } } @Test public void testSettingValueInArray() throws Exception { if (cardinality == Cardinality.Simple) return; // only test array properties Object value = TypeTestingHelper.getJavaValue(type); AbstractSimpleProperty property = getSchema().instanciateSimple(fieldName, value); switch (cardinality) { case Seq: getSchema().addUnqualifiedSequenceValue(property.getPropertyName(), property); break; case Bag: getSchema().addBagValue(property.getPropertyName(), property); break; default: throw new Exception("Unexpected case in test : " + cardinality.name()); } String qn = getPropertyQualifiedName(fieldName); Assert.assertNotNull(getSchema().getProperty(fieldName)); // check other properties not modified List fields = TypeTestingHelper.getXmpFields(getSchemaClass()); for (Field field : fields) { // do not check the current name String fqn = getPropertyQualifiedName(field.get(null).toString()); if (!fqn.equals(qn)) { Assert.assertNull(getSchema().getProperty(fqn)); } } } @Test public void testPropertySetterSimple() throws Exception { if (cardinality != Cardinality.Simple) return; String setter = TypeTestingHelper.calculateSimpleSetter(fieldName) + "Property"; Object value = TypeTestingHelper.getJavaValue(type); AbstractSimpleProperty asp = typeMapping.instanciateSimpleProperty(getSchema().getNamespace(), getSchema() .getPrefix(), fieldName, value, type); Method set = getSchemaClass().getMethod(setter, new Class[] { type.getImplementingClass() }); set.invoke(getSchema(), new Object[] { asp }); // check property set AbstractSimpleProperty stored = (AbstractSimpleProperty) getSchema().getProperty(fieldName); Assert.assertEquals(value, stored.getValue()); // check getter String getter = TypeTestingHelper.calculateSimpleGetter(fieldName) + "Property"; Method get = getSchemaClass().getMethod(getter, new Class[0]); Object result = get.invoke(getSchema(), new Object[0]); Assert.assertTrue(type.getImplementingClass().isAssignableFrom(result.getClass())); Assert.assertEquals(asp, result); } @Test public void testPropertySetterInArray() throws Exception { if (cardinality == Cardinality.Simple) return; // add value String setter = "add" + TypeTestingHelper.calculateFieldNameForMethod(fieldName); // TypeDescription td = // typeMapping.getSimpleDescription(type); Object value1 = TypeTestingHelper.getJavaValue(type); Method set = getSchemaClass().getMethod(setter, new Class[] { TypeTestingHelper.getJavaType(type) }); set.invoke(getSchema(), new Object[] { value1 }); // retrieve complex property String getter = TypeTestingHelper.calculateArrayGetter(fieldName) + "Property"; Method getcp = getSchemaClass().getMethod(getter, new Class[0]); Object ocp = getcp.invoke(getSchema(), new Object[0]); Assert.assertTrue(ocp instanceof ArrayProperty); ArrayProperty cp = (ArrayProperty) ocp; // check size is ok (1) Assert.assertEquals(1, cp.getContainer().getAllProperties().size()); // add a new one Object value2 = TypeTestingHelper.getJavaValue(type); set.invoke(getSchema(), new Object[] { value2 }); Assert.assertEquals(2, cp.getContainer().getAllProperties().size()); // remove the first String remover = "remove" + TypeTestingHelper.calculateFieldNameForMethod(fieldName); Method remove = getSchemaClass().getMethod(remover, new Class[] { TypeTestingHelper.getJavaType(type) }); remove.invoke(getSchema(), value1); Assert.assertEquals(1, cp.getContainer().getAllProperties().size()); } protected String getPropertyQualifiedName(String name) { StringBuilder sb = new StringBuilder(); sb.append(getSchema().getPrefix()).append(":").append(name); return sb.toString(); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/XmpRightsSchemaTest.java0000644000000000000000000000522012645757426027145 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.Types; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class XmpRightsSchemaTest extends AbstractXMPSchemaTest { public XmpRightsSchemaTest(String property, PropertyType type, Object value) { super(property, type, value); } @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); schema = metadata.createAndAddXMPRightsManagementSchema(); schemaClass = XMPRightsManagementSchema.class; } @Parameters public static Collection initializeParameters() throws Exception { List data = new ArrayList(); data.add(wrapProperty("Certificate", Types.URL, "http://une.url.vers.un.certificat/moncert.cer")); data.add(wrapProperty("Marked", Types.Boolean, true)); data.add(wrapProperty("Owner", Types.ProperName, Cardinality.Bag, new String[] { "OwnerName" })); Map desc = new HashMap(2); desc.put("fr", "Termes d'utilisation"); desc.put("en", "Usage Terms"); data.add(wrapProperty("UsageTerms", Types.LangAlt, desc)); data.add(wrapProperty("WebStatement", Types.URL, "http://une.url.vers.une.page.fr/")); return data; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/PDFAIdentificationTest.java0000644000000000000000000000423412645757426027467 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.Types; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class PDFAIdentificationTest extends AbstractXMPSchemaTest { @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); schema = metadata.createAndAddPFAIdentificationSchema(); schemaClass = PDFAIdentificationSchema.class; } @Parameters public static Collection initializeParameters() throws Exception { List data = new ArrayList(); data.add(wrapProperty("part", Types.Integer, 1)); data.add(wrapProperty("amd", Types.Text, "2005")); data.add(wrapProperty("conformance", Types.Text, "B")); return data; } public PDFAIdentificationTest(String property, PropertyType type, Object value) { super(property, type, value); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/DublinCoreTest.java0000644000000000000000000000556512645757426026141 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Collection; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.Types; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class DublinCoreTest extends AbstractSchemaTester { protected DublinCoreSchema schema = null; public DublinCoreSchema getSchema() { return schema; } @Before public void before() throws Exception { super.before(); schema = xmp.createAndAddDublinCoreSchema(); } public DublinCoreTest(String fieldName, Types type, Cardinality card) { super(fieldName, type, card); } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { "contributor", Types.ProperName, Cardinality.Bag }); result.add(new Object[] { "coverage", Types.Text, Cardinality.Simple }); result.add(new Object[] { "creator", Types.ProperName, Cardinality.Seq }); result.add(new Object[] { "date", Types.Date, Cardinality.Seq }); result.add(new Object[] { "format", Types.MIMEType, Cardinality.Simple }); result.add(new Object[] { "identifier", Types.Text, Cardinality.Simple }); result.add(new Object[] { "language", Types.Locale, Cardinality.Bag }); result.add(new Object[] { "publisher", Types.ProperName, Cardinality.Bag }); result.add(new Object[] { "relation", Types.Text, Cardinality.Bag }); result.add(new Object[] { "source", Types.Text, Cardinality.Simple }); result.add(new Object[] { "subject", Types.Text, Cardinality.Bag }); result.add(new Object[] { "type", Types.Text, Cardinality.Bag }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/XMPSchemaTest.java0000644000000000000000000004171012645757426025670 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.io.IOException; import java.util.Calendar; import java.util.List; import junit.framework.Assert; import org.apache.xmpbox.DateConverter; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XmpConstants; import org.apache.xmpbox.type.AbstractField; import org.apache.xmpbox.type.ArrayProperty; import org.apache.xmpbox.type.Attribute; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.BooleanType; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.DateType; import org.apache.xmpbox.type.IntegerType; import org.apache.xmpbox.type.TextType; import org.apache.xmpbox.type.TypeMapping; import org.junit.Before; import org.junit.Test; public class XMPSchemaTest { protected XMPMetadata parent; protected XMPSchema schem; @Before public void resetDocument() throws Exception { parent = XMPMetadata.createXMPMetadata(); schem = new XMPSchema(parent, "nsURI", "nsSchem"); } /** * Check if Bag (Unordered Array) management is ok * * @throws InappropriateTypeException */ @Test public void testBagManagement() throws Exception { String bagName = "BAGTEST"; String value1 = "valueOne"; String value2 = "valueTwo"; schem.addBagValue(bagName, schem.getMetadata().getTypeMapping().createText(null, "rdf", "li", value1)); schem.addQualifiedBagValue(bagName, value2); List values = schem.getUnqualifiedBagValueList(bagName); Assert.assertEquals(value1, values.get(0)); Assert.assertEquals(value2, values.get(1)); schem.removeUnqualifiedBagValue(bagName, value1); List values2 = schem.getUnqualifiedBagValueList(bagName); Assert.assertEquals(1, values2.size()); Assert.assertEquals(value2, values2.get(0)); } @Test public void testArrayList() throws Exception { XMPMetadata meta = XMPMetadata.createXMPMetadata(); ArrayProperty newSeq = meta.getTypeMapping().createArrayProperty(null, "nsSchem", "seqType", Cardinality.Seq); TypeMapping tm = meta.getTypeMapping(); TextType li1 = tm.createText(null, "rdf", "li", "valeur1"); TextType li2 = tm.createText(null, "rdf", "li", "valeur2"); newSeq.getContainer().addProperty(li1); newSeq.getContainer().addProperty(li2); schem.addProperty(newSeq); List list = schem.getUnqualifiedArrayList("seqType"); Assert.assertTrue(list.contains(li1)); Assert.assertTrue(list.contains(li2)); } /** * Check if Seq (Ordered Array) management is ok * * @throws InappropriateTypeException * @throws IOException */ @Test public void testSeqManagement() throws Exception { Calendar date = Calendar.getInstance(); BooleanType bool = parent.getTypeMapping().createBoolean(null, "rdf", "li", true); String textVal = "seqValue"; String seqName = "SEQNAME"; schem.addUnqualifiedSequenceDateValue(seqName, date); schem.addUnqualifiedSequenceValue(seqName, bool); schem.addUnqualifiedSequenceValue(seqName, textVal); List dates = schem.getUnqualifiedSequenceDateValueList(seqName); Assert.assertEquals(1, dates.size()); Assert.assertEquals(date, dates.get(0)); List values = schem.getUnqualifiedSequenceValueList(seqName); Assert.assertEquals(3, values.size()); Assert.assertEquals(DateConverter.toISO8601(date), values.get(0)); Assert.assertEquals(bool.getStringValue(), values.get(1)); Assert.assertEquals(textVal, values.get(2)); schem.removeUnqualifiedSequenceDateValue(seqName, date); Assert.assertEquals(0, schem.getUnqualifiedSequenceDateValueList(seqName).size()); schem.removeUnqualifiedSequenceValue(seqName, bool); schem.removeUnqualifiedSequenceValue(seqName, textVal); Assert.assertEquals(0, schem.getUnqualifiedSequenceValueList(seqName).size()); } @Test public void rdfAboutTest() { Assert.assertEquals("",schem.getAboutValue()); String about = "about"; schem.setAboutAsSimple(about); Assert.assertEquals(about, schem.getAboutValue()); schem.setAboutAsSimple(""); Assert.assertEquals("",schem.getAboutValue()); schem.setAboutAsSimple(null); Assert.assertEquals("",schem.getAboutValue()); } @Test(expected = BadFieldValueException.class) public void testBadRdfAbout() throws Exception { schem.setAbout(new Attribute(null, "about", "")); } @Test public void testSetSpecifiedSimpleTypeProperty() throws Exception { String prop = "testprop"; String val = "value"; String val2 = "value2"; schem.setTextPropertyValueAsSimple(prop, val); Assert.assertEquals(val, schem.getUnqualifiedTextPropertyValue(prop)); schem.setTextPropertyValueAsSimple(prop, val2); Assert.assertEquals(val2, schem.getUnqualifiedTextPropertyValue(prop)); schem.setTextPropertyValueAsSimple(prop, null); Assert.assertNull(schem.getUnqualifiedTextProperty(prop)); } @Test public void testSpecifiedSimplePropertyFormer() throws Exception { String prop = "testprop"; String val = "value"; String val2 = "value2"; schem.setTextPropertyValueAsSimple(prop, val); TextType text = schem.getMetadata().getTypeMapping().createText(null, schem.getPrefix(), prop, "value2"); schem.setTextProperty(text); Assert.assertEquals(val2, schem.getUnqualifiedTextPropertyValue(prop)); Assert.assertEquals(text, schem.getUnqualifiedTextProperty(prop)); } @Test public void testAsSimpleMethods() throws Exception { String bool = "bool"; boolean boolVal = true; String date = "date"; Calendar dateVal = Calendar.getInstance(); String integ = "integer"; Integer i = 1; String langprop = "langprop"; String lang = "x-default"; String langVal = "langVal"; String bagprop = "bagProp"; String bagVal = "bagVal"; String seqprop = "SeqProp"; String seqPropVal = "seqval"; String seqdate = "SeqDate"; String prefSchem = ""; schem.setBooleanPropertyValueAsSimple(bool, boolVal); schem.setDatePropertyValueAsSimple(date, dateVal); schem.setIntegerPropertyValueAsSimple(integ, i); schem.setUnqualifiedLanguagePropertyValue(langprop, lang, langVal); schem.addBagValueAsSimple(bagprop, bagVal); schem.addUnqualifiedSequenceValue(seqprop, seqPropVal); schem.addSequenceDateValueAsSimple(seqdate, dateVal); Assert.assertEquals(Boolean.valueOf(boolVal), schem.getBooleanProperty(prefSchem + bool).getValue()); Assert.assertEquals(dateVal, schem.getDateProperty(prefSchem + date).getValue()); Assert.assertEquals("" + i, schem.getIntegerProperty(prefSchem + integ).getStringValue()); Assert.assertEquals(langVal, schem.getUnqualifiedLanguagePropertyValue(langprop, lang)); Assert.assertTrue(schem.getUnqualifiedBagValueList(bagprop).contains(bagVal)); Assert.assertTrue(schem.getUnqualifiedSequenceValueList(seqprop).contains(seqPropVal)); Assert.assertTrue(schem.getUnqualifiedSequenceDateValueList(seqdate).contains(dateVal)); Assert.assertTrue(schem.getUnqualifiedLanguagePropertyLanguagesValue(langprop).contains(lang)); Assert.assertEquals(boolVal, schem.getBooleanPropertyValueAsSimple(bool).booleanValue()); Assert.assertEquals(dateVal, schem.getDatePropertyValueAsSimple(date)); Assert.assertEquals(i, schem.getIntegerPropertyValueAsSimple(integ)); Assert.assertEquals(langVal, schem.getUnqualifiedLanguagePropertyValue(langprop, lang)); Assert.assertTrue(schem.getUnqualifiedBagValueList(bagprop).contains(bagVal)); Assert.assertTrue(schem.getUnqualifiedSequenceValueList(seqprop).contains(seqPropVal)); Assert.assertTrue(schem.getUnqualifiedSequenceDateValueList(seqdate).contains(dateVal)); Assert.assertTrue(schem.getUnqualifiedLanguagePropertyLanguagesValue(langprop).contains(lang)); } /** * Test All common simple properties management in XMPSchema * * @throws InappropriateTypeException * @throws BadFieldValueException */ @Test public void testProperties() throws Exception { Assert.assertEquals("nsURI", schem.getNamespace()); // In real cases, rdf ns will be declared before ! schem.addNamespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf"); String aboutVal = "aboutTest"; schem.setAboutAsSimple(aboutVal); Assert.assertEquals(aboutVal, schem.getAboutValue()); Attribute about = new Attribute(XmpConstants.RDF_NAMESPACE, "about", "YEP"); schem.setAbout(about); Assert.assertEquals(about, schem.getAboutAttribute()); String textProp = "textProp"; String textPropVal = "TextPropTest"; schem.setTextPropertyValue(textProp, textPropVal); Assert.assertEquals(textPropVal, schem.getUnqualifiedTextPropertyValue(textProp)); TextType text = parent.getTypeMapping().createText(null, "nsSchem", "textType", "GRINGO"); schem.setTextProperty(text); Assert.assertEquals(text, schem.getUnqualifiedTextProperty("textType")); Calendar dateVal = Calendar.getInstance(); String date = "nsSchem:dateProp"; schem.setDatePropertyValue(date, dateVal); Assert.assertEquals(dateVal, schem.getDatePropertyValue(date)); DateType dateType = parent.getTypeMapping().createDate(null, "nsSchem", "dateType", Calendar.getInstance()); schem.setDateProperty(dateType); Assert.assertEquals(dateType, schem.getDateProperty("dateType")); String bool = "nsSchem:booleanTestProp"; Boolean boolVal = false; schem.setBooleanPropertyValue(bool, boolVal); Assert.assertEquals(boolVal, schem.getBooleanPropertyValue(bool)); BooleanType boolType = parent.getTypeMapping().createBoolean(null, "nsSchem", "boolType", false); schem.setBooleanProperty(boolType); Assert.assertEquals(boolType, schem.getBooleanProperty("boolType")); String intProp = "nsSchem:IntegerTestProp"; Integer intPropVal = 5; schem.setIntegerPropertyValue(intProp, intPropVal); Assert.assertEquals(intPropVal, schem.getIntegerPropertyValue(intProp)); IntegerType intType = parent.getTypeMapping().createInteger(null, "nsSchem", "intType", 5); schem.setIntegerProperty(intType); Assert.assertEquals(intType, schem.getIntegerProperty("intType")); // Check bad type verification boolean ok = false; try { schem.getIntegerProperty("boolType"); } catch (IllegalArgumentException e) { ok = true; } Assert.assertEquals(true, ok); ok = false; try { schem.getUnqualifiedTextProperty("intType"); } catch (IllegalArgumentException e) { ok = true; } Assert.assertEquals(true, ok); ok = false; try { schem.getDateProperty("textType"); } catch (IllegalArgumentException e) { ok = true; } Assert.assertEquals(true, ok); ok = false; try { schem.getBooleanProperty("dateType"); } catch (IllegalArgumentException e) { ok = true; } } @Test public void testAltProperties() throws Exception { String altProp = "AltProp"; String defaultLang = "x-default"; String defaultVal = "Default Language"; String usLang = "en-us"; String usVal = "American Language"; String frLang = "fr-fr"; String frVal = "Lang française"; schem.setUnqualifiedLanguagePropertyValue(altProp, usLang, usVal); schem.setUnqualifiedLanguagePropertyValue(altProp, defaultLang, defaultVal); schem.setUnqualifiedLanguagePropertyValue(altProp, frLang, frVal); Assert.assertEquals(defaultVal, schem.getUnqualifiedLanguagePropertyValue(altProp, defaultLang)); Assert.assertEquals(frVal, schem.getUnqualifiedLanguagePropertyValue(altProp, frLang)); Assert.assertEquals(usVal, schem.getUnqualifiedLanguagePropertyValue(altProp, usLang)); List languages = schem.getUnqualifiedLanguagePropertyLanguagesValue(altProp); // default language must be in first place Assert.assertEquals(defaultLang, languages.get(0)); Assert.assertTrue(languages.contains(usLang)); Assert.assertTrue(languages.contains(frLang)); // Test replacement/removal frVal = "Langue française"; schem.setUnqualifiedLanguagePropertyValue(altProp, frLang, frVal); Assert.assertEquals(frVal, schem.getUnqualifiedLanguagePropertyValue(altProp, frLang)); schem.setUnqualifiedLanguagePropertyValue(altProp, frLang, null); languages = schem.getUnqualifiedLanguagePropertyLanguagesValue(altProp); Assert.assertFalse(languages.contains(frLang)); schem.setUnqualifiedLanguagePropertyValue(altProp, frLang, frVal); } /** * check if merging is ok * * @throws InappropriateTypeException * @throws IOException */ @Test public void testMergeSchema() throws Exception { String bagName = "bagName"; String seqName = "seqName"; String qseqName = "test:" + seqName; String altName = "AltProp"; String qaltName = "test:" + altName; String valBagSchem1 = "BagvalSchem1"; String valBagSchem2 = "BagvalSchem2"; String valSeqSchem1 = "seqvalSchem1"; String valSeqSchem2 = "seqvalSchem2"; String valAltSchem1 = "altvalSchem1"; String langAltSchem1 = "x-default"; String valAltSchem2 = "altvalSchem2"; String langAltSchem2 = "fr-fr"; XMPSchema schem1 = new XMPSchema(parent, "http://www.test.org/schem/", "test"); schem1.addQualifiedBagValue(bagName, valBagSchem1); schem1.addUnqualifiedSequenceValue(seqName, valSeqSchem1); schem1.setUnqualifiedLanguagePropertyValue(altName, langAltSchem1, valAltSchem1); XMPSchema schem2 = new XMPSchema(parent, "http://www.test.org/schem/", "test"); schem2.addQualifiedBagValue(bagName, valBagSchem2); schem2.addUnqualifiedSequenceValue(seqName, valSeqSchem2); schem2.setUnqualifiedLanguagePropertyValue(altName, langAltSchem2, valAltSchem2); schem1.merge(schem2); // Check if all values are present Assert.assertEquals(valAltSchem2, schem1.getUnqualifiedLanguagePropertyValue(altName, langAltSchem2)); Assert.assertEquals(valAltSchem1, schem1.getUnqualifiedLanguagePropertyValue(altName, langAltSchem1)); List bag = schem1.getUnqualifiedBagValueList(bagName); Assert.assertTrue(bag.contains(valBagSchem1)); Assert.assertTrue(bag.contains(valBagSchem2)); List seq = schem1.getUnqualifiedSequenceValueList(seqName); Assert.assertTrue(seq.contains(valSeqSchem1)); Assert.assertTrue(seq.contains(valSeqSchem1)); } @Test public void testListAndContainerAccessor() throws Exception { String boolname = "bool"; boolean boolVal = true; BooleanType bool = parent.getTypeMapping().createBoolean(null, schem.getPrefix(), boolname, boolVal); Attribute att = new Attribute(XmpConstants.RDF_NAMESPACE, "test", "vgh"); schem.setAttribute(att); schem.setBooleanProperty(bool); Assert.assertEquals(schem.getAllProperties(), schem.getAllProperties()); Assert.assertTrue(schem.getAllProperties().contains(bool)); Assert.assertTrue(schem.getAllAttributes().contains(att)); Assert.assertEquals(bool, schem.getProperty(boolname)); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/AdobePDFErrorsTest.java0000644000000000000000000000624512645757426026650 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import junit.framework.Assert; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.xml.DomXmpParser; import org.junit.Before; import org.junit.Test; public class AdobePDFErrorsTest { protected XMPMetadata metadata; protected DomXmpParser builder; @Before public void initTempMetaData() throws Exception { builder = new DomXmpParser(); metadata = XMPMetadata.createXMPMetadata(); } @Test public void testPDFAIdentification() throws Exception { AdobePDFSchema schem = metadata.createAndAddAdobePDFSchema(); String keywords = "keywords ihih"; String pdfVersion = "1.4"; String producer = "producer"; schem.setKeywords(keywords); schem.setPDFVersion(pdfVersion); // Check get null if property not defined Assert.assertNull(schem.getProducer()); schem.setProducer(producer); Assert.assertEquals("Keywords", schem.getKeywordsProperty().getPropertyName()); Assert.assertEquals(keywords, schem.getKeywords()); Assert.assertEquals("PDFVersion", schem.getPDFVersionProperty().getPropertyName()); Assert.assertEquals(pdfVersion, schem.getPDFVersion()); Assert.assertEquals("Producer", schem.getProducerProperty().getPropertyName()); Assert.assertEquals(producer, schem.getProducer()); // check retrieve this schema in metadata Assert.assertEquals(schem, metadata.getAdobePDFSchema()); // SaveMetadataHelper.serialize(metadata, true, System.out); } @Test(expected = BadFieldValueException.class) public void testBadPDFAConformanceId() throws Exception { PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema(); String conformance = "kiohiohiohiohio"; pdfaid.setConformance(conformance); } @Test(expected = IllegalArgumentException.class) public void testBadVersionIdValueType() throws Exception { PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema(); pdfaid.setPartValueWithString("1"); pdfaid.setPartValueWithString("ojoj"); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/PDFAIdentificationOthersTest.java0000644000000000000000000000574712645757426030666 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import junit.framework.Assert; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.BadFieldValueException; import org.junit.Before; import org.junit.Test; public class PDFAIdentificationOthersTest { protected XMPMetadata metadata; @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); } @Test public void testPDFAIdentification() throws Exception { PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema(); Integer versionId = 1; String amdId = "2005"; String conformance = "B"; pdfaid.setPartValueWithInt(versionId); pdfaid.setAmd(amdId); pdfaid.setConformance(conformance); Assert.assertEquals(versionId, pdfaid.getPart()); Assert.assertEquals(amdId, pdfaid.getAmendment()); Assert.assertEquals(conformance, pdfaid.getConformance()); Assert.assertEquals("" + versionId, pdfaid.getPartProperty().getStringValue()); Assert.assertEquals(amdId, pdfaid.getAmdProperty().getStringValue()); Assert.assertEquals(conformance, pdfaid.getConformanceProperty().getStringValue()); // check retrieve this schema in metadata Assert.assertEquals(pdfaid, metadata.getPDFIdentificationSchema()); // SaveMetadataHelper.serialize(metadata, true, System.out); } @Test(expected = BadFieldValueException.class) public void testBadPDFAConformanceId() throws BadFieldValueException { PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema(); String conformance = "kiohiohiohiohio"; pdfaid.setConformance(conformance); } @Test(expected = IllegalArgumentException.class) public void testBadVersionIdValueType() throws Exception { PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema(); pdfaid.setPartValueWithString("1"); pdfaid.setPartValueWithString("ojoj"); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/BasicJobTicketSchemaTest.java0000644000000000000000000001200212645757426030034 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import junit.framework.Assert; import org.apache.commons.io.IOUtils; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.JobType; import org.apache.xmpbox.type.StructuredType; import org.apache.xmpbox.xml.DomXmpParser; import org.apache.xmpbox.xml.XmpSerializer; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class BasicJobTicketSchemaTest { protected static DomXmpParser builder; protected XMPMetadata metadata; protected XmpSerializer serializer; @BeforeClass public static void bc() throws Exception { builder = new DomXmpParser(); } @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); serializer = new XmpSerializer(); } private InputStream transfer(ByteArrayOutputStream out) { IOUtils.closeQuietly(out); ByteArrayInputStream bis = new ByteArrayInputStream(out.toByteArray()); return bis; } @Test public void testAddTwoJobs() throws Exception { XMPBasicJobTicketSchema basic = metadata.createAndAddBasicJobTicketSchema(); basic.addJob("zeid1", "zename1", "zeurl1", "aaa"); basic.addJob("zeid2", "zename2", "zeurl2"); // serializer.serialize(metadata, System.out, true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); serializer.serialize(metadata, bos, true); InputStream is = transfer(bos); XMPMetadata rxmp = builder.parse(is); XMPBasicJobTicketSchema jt = rxmp.getBasicJobTicketSchema(); Assert.assertNotNull(jt); Assert.assertEquals(2, jt.getJobs().size()); } @Test public void testAddWithDefaultPrefix() throws Exception { XMPBasicJobTicketSchema basic = metadata.createAndAddBasicJobTicketSchema(); basic.addJob("zeid2", "zename2", "zeurl2"); // serializer.serialize(metadata, System.out, true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); serializer.serialize(metadata, bos, true); InputStream is = transfer(bos); XMPMetadata rxmp = builder.parse(is); XMPBasicJobTicketSchema jt = rxmp.getBasicJobTicketSchema(); Assert.assertNotNull(jt); Assert.assertEquals(1, jt.getJobs().size()); StructuredType stjob = JobType.class.getAnnotation(StructuredType.class); JobType job = jt.getJobs().get(0); Assert.assertEquals("zeid2", job.getId()); Assert.assertEquals("zename2", job.getName()); Assert.assertEquals("zeurl2", job.getUrl()); // Assert.assertEquals("Invalid namespace",stjob.namespace(), // job.getNamespace()); // Assert.assertEquals(stjob.preferedPrefix(), job.getPrefix()); } @Test public void testAddWithDefinedPrefix() throws Exception { XMPBasicJobTicketSchema basic = metadata.createAndAddBasicJobTicketSchema(); basic.addJob("zeid2", "zename2", "zeurl2", "aaa"); // SaveMetadataHelper.serialize(metadata, System.out); // serializer.serialize(metadata, System.out, true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); serializer.serialize(metadata, bos, true); InputStream is = transfer(bos); XMPMetadata rxmp = builder.parse(is); XMPBasicJobTicketSchema jt = rxmp.getBasicJobTicketSchema(); Assert.assertNotNull(jt); Assert.assertEquals(1, jt.getJobs().size()); JobType job = jt.getJobs().get(0); // SaveMetadataHelper.serialize(rxmp, System.out); // StructuredType stjob = // JobType.class.getAnnotation(StructuredType.class); Assert.assertEquals("zeid2", job.getId()); Assert.assertEquals("zename2", job.getName()); Assert.assertEquals("zeurl2", job.getUrl()); // Assert.assertEquals(stjob.namespace(), job.getNamespace()); // Assert.assertEquals("aaa", job.getPrefix()); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/schema/XMPMediaManagementTest.java0000644000000000000000000000614412645757426027506 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.schema; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.type.Cardinality; import org.apache.xmpbox.type.PropertyType; import org.apache.xmpbox.type.Types; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class XMPMediaManagementTest extends AbstractXMPSchemaTest { @Before public void initTempMetaData() throws Exception { metadata = XMPMetadata.createXMPMetadata(); schema = metadata.createAndAddXMPMediaManagementSchema(); schemaClass = XMPMediaManagementSchema.class; } @Parameters public static Collection initializeParameters() throws Exception { List data = new ArrayList(); data.add(wrapProperty("DocumentID", Types.URI, "uuid:FB031973-5E75-11B2-8F06-E7F5C101C07A")); data.add(wrapProperty("Manager", Types.AgentName, "Raoul")); data.add(wrapProperty("ManageTo", Types.URI, "uuid:36")); data.add(wrapProperty("ManageUI", Types.URI, "uuid:3635")); // data.add(wrapProperty("ManageFrom", "ResourceRef", "uuid:36")); data.add(wrapProperty("InstanceID", Types.URI, "uuid:42")); data.add(wrapProperty("OriginalDocumentID", Types.Text, "uuid:142")); // data.add(wrapProperty("RenditionClass", "Text", "myclass")); data.add(wrapProperty("RenditionParams", Types.Text, "my params")); data.add(wrapProperty("VersionID", Types.Text, "14")); data.add(wrapProperty("Versions", Types.Version, Cardinality.Seq, new String[] { "1", "2", "3" })); data.add(wrapProperty("History", Types.Text, Cardinality.Seq, new String[] { "action 1", "action 2", "action 3" })); data.add(wrapProperty("Ingredients", Types.Text, Cardinality.Bag, new String[] { "resource1", "resource2" })); return data; } public XMPMediaManagementTest(String property, PropertyType type, Object value) { super(property, type, value); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/DoubleSameTypeSchemaTest.java0000644000000000000000000000603012645757426026642 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; import java.util.ArrayList; import java.util.List; import junit.framework.Assert; import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.type.StructuredType; import org.junit.Before; import org.junit.Test; /** * Test with 2 dublinCore with different prefix (Test comportment of XMPMetadata) * * @author a183132 * */ public class DoubleSameTypeSchemaTest { protected XMPMetadata metadata; @Before public void testInit() throws Exception { metadata = XMPMetadata.createXMPMetadata(); } @Test public void testDoubleDublinCore() throws Exception { DublinCoreSchema dc1 = metadata.createAndAddDublinCoreSchema(); String ownPrefix = "test"; DublinCoreSchema dc2 = new DublinCoreSchema(metadata, ownPrefix); metadata.addSchema(dc2); List creators = new ArrayList(); creators.add("creator1"); creators.add("creator2"); String format = "application/pdf"; dc1.setFormat(format); dc1.addCreator(creators.get(0)); dc1.addCreator(creators.get(1)); String coverage = "Coverage"; dc2.setCoverage(coverage); dc2.addCreator(creators.get(0)); dc2.addCreator(creators.get(1)); StructuredType stDub = DublinCoreSchema.class.getAnnotation(StructuredType.class); // We can't use metadata.getDublinCoreSchema() due to specification of // XMPBox (see Javadoc of XMPMetadata) Assert.assertEquals(format, ((DublinCoreSchema) metadata.getSchema(stDub.preferedPrefix(), stDub.namespace())).getFormat()); Assert.assertEquals(coverage, ((DublinCoreSchema) metadata.getSchema(ownPrefix, stDub.namespace())).getCoverage()); List schems = metadata.getAllSchemas(); DublinCoreSchema dc; for (XMPSchema xmpSchema : schems) { dc = (DublinCoreSchema) xmpSchema; Assert.assertTrue(dc.getCreators().containsAll(creators)); } } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/TestXMPWithDefinedSchemas.java0000644000000000000000000000424512645757426026730 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.xmpbox.xml.DomXmpParser; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestXMPWithDefinedSchemas { @Parameters public static Collection initializeParameters() throws Exception { List data = new ArrayList(); data.add(new Object[] { "/validxmp/override_ns.rdf" }); data.add(new Object[] { "/validxmp/ghost2.xmp" }); data.add(new Object[] { "/validxmp/history2.rdf" }); data.add(new Object[] { "/validxmp/Notepad++_A1b.xmp" }); data.add(new Object[] { "/validxmp/metadata.rdf" }); return data; } private String path; public TestXMPWithDefinedSchemas(String path) { this.path = path; } @Test public void main() throws Exception { InputStream is = this.getClass().getResourceAsStream(path); DomXmpParser builder = new DomXmpParser(); XMPMetadata rxmp = builder.parse(is); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/parser/0000755000000000000000000000000012645757426022431 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/parser/PropMappingTest.java0000644000000000000000000000244612645757426026376 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.parser; import org.apache.xmpbox.type.PropertiesDescription; import org.junit.Before; public class PropMappingTest { protected PropertiesDescription propMap; protected String nsURI = "http://www.test.org/PropMap#"; @Before public void init() { propMap = new PropertiesDescription(); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java0000644000000000000000000002504212645757426027265 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.parser; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.List; import org.apache.xmpbox.DateConverter; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.AdobePDFSchema; import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.XMPBasicSchema; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.type.ThumbnailType; import org.apache.xmpbox.xml.DomXmpParser; import org.apache.xmpbox.xml.XmpParsingException; import org.apache.xmpbox.xml.XmpParsingException.ErrorType; import org.apache.xmpbox.xml.XmpSerializer; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class DeserializationTest { protected ByteArrayOutputStream bos; protected XmpSerializer serializer; @Before public void init() throws Exception { bos = new ByteArrayOutputStream(); serializer = new XmpSerializer(); } @Test public void testStructuredRecursive() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/structured_recursive.xml"); DomXmpParser xdb = new DomXmpParser(); xdb.parse(fis); } @Test public void testEmptyLi() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/empty_list.xml"); DomXmpParser xdb = new DomXmpParser(); xdb.parse(fis); } @Test public void testEmptyLi2() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/validxmp/emptyli.xml"); DomXmpParser xdb = new DomXmpParser(); XMPMetadata meta = xdb.parse(fis); DublinCoreSchema dc = meta.getDublinCoreSchema(); dc.getCreatorsProperty(); } @Test public void testGetTitle() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/validxmp/emptyli.xml"); DomXmpParser xdb = new DomXmpParser(); XMPMetadata meta = xdb.parse(fis); DublinCoreSchema dc = meta.getDublinCoreSchema(); String s = dc.getTitle(null); Assert.assertEquals("title value", s); } @Test public void testAltBagSeq() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/AltBagSeqTest.xml"); DomXmpParser xdb = new DomXmpParser(); xdb.parse(fis); // XMPMetadata metadata=xdb.parse(fis); // SaveMetadataHelper.serialize(metadata, true, System.out); } @Test public void testIsartorStyleWithThumbs() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/ThumbisartorStyle.xml"); DomXmpParser xdb = new DomXmpParser(); XMPMetadata metadata = xdb.parse(fis); // Assert.assertEquals("uuid:09C78666-2F91-3A9C-92AF-3691A6D594F7", metadata.getXMPMediaManagementSchema() .getDocumentID()); // // // Assert.assertEquals(DateConverter.toCalendar("2008-01-18T16:59:54+01:00"), metadata.getXMPBasicSchema() .getCreateDate()); Assert.assertEquals(DateConverter.toCalendar("2008-01-18T16:59:54+01:00"), metadata.getXMPBasicSchema() .getModifyDate()); Assert.assertEquals(DateConverter.toCalendar("2008-01-18T16:59:54+01:00"), metadata.getXMPBasicSchema() .getMetadataDate()); // THUMBNAILS TEST List thumbs = metadata.getXMPBasicSchema().getThumbnailsProperty(); Assert.assertNotNull(thumbs); Assert.assertEquals(2, thumbs.size()); ThumbnailType thumb = thumbs.get(0); Assert.assertEquals(new Integer(162), thumb.getHeight()); Assert.assertEquals(new Integer(216), thumb.getWidth()); Assert.assertEquals("JPEG", thumb.getFormat()); Assert.assertEquals("/9j/4AAQSkZJRgABAgEASABIAAD", thumb.getImage()); thumb = thumbs.get(1); Assert.assertEquals(new Integer(162), thumb.getHeight()); Assert.assertEquals(new Integer(216), thumb.getWidth()); Assert.assertEquals("JPEG", thumb.getFormat()); Assert.assertEquals("/9j/4AAQSkZJRgABAgEASABIAAD", thumb.getImage()); } @Test public void testWithNoXPacketStart() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/noxpacket.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.XpacketBadStart, e.getErrorType()); } } @Test public void testWithNoXPacketEnd() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/noxpacketend.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.XpacketBadEnd, e.getErrorType()); } } @Test public void testWithNoRDFElement() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/noroot.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.Format, e.getErrorType()); } } @Test public void testWithTwoRDFElement() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/tworoot.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.Format, e.getErrorType()); } } @Test public void testWithInvalidRDFElementPrefix() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/invalidroot2.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.Format, e.getErrorType()); } } @Test public void testWithRDFRootAsText() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/invalidroot.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.Format, e.getErrorType()); } } @Test public void testUndefinedSchema() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/undefinedschema.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.NoSchema, e.getErrorType()); } } @Test public void testUndefinedPropertyWithDefinedSchema() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/undefinedpropertyindefinedschema.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.NoType, e.getErrorType()); } } @Test public void testUndefinedStructuredWithDefinedSchema() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/invalidxmp/undefinedstructuredindefinedschema.xml"); DomXmpParser xdb = new DomXmpParser(); try { xdb.parse(fis); Assert.fail("Should fail during parse"); } catch (XmpParsingException e) { Assert.assertEquals(ErrorType.NoValueType, e.getErrorType()); } } @Test public void testRdfAboutFound() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/validxmp/emptyli.xml"); DomXmpParser xdb = new DomXmpParser(); XMPMetadata meta = xdb.parse(fis); List schemas = meta.getAllSchemas(); for (XMPSchema xmpSchema : schemas) { Assert.assertNotNull(xmpSchema.getAboutAttribute()); } } @Test public void testWihtAttributesAsProperties() throws Exception { InputStream fis = DomXmpParser.class.getResourceAsStream("/validxmp/attr_as_props.xml"); DomXmpParser xdb = new DomXmpParser(); XMPMetadata meta = xdb.parse(fis); AdobePDFSchema pdf = meta.getAdobePDFSchema(); Assert.assertEquals("GPL Ghostscript 8.64", pdf.getProducer()); DublinCoreSchema dc = meta.getDublinCoreSchema(); Assert.assertEquals("application/pdf", dc.getFormat()); XMPBasicSchema basic = meta.getXMPBasicSchema(); Assert.assertNotNull(basic.getCreateDate()); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/XMPMetaDataTest.java0000644000000000000000000001025412645757426024707 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; import java.util.List; import junit.framework.Assert; import org.apache.xmpbox.schema.XMPSchema; import org.apache.xmpbox.xml.XmpSerializationException; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; /** * Test XMP MetaData Transformer * * @author a183132 * */ public class XMPMetaDataTest { protected XMPMetadata metadata; protected Document parent; protected XMPSchema tmp, tmp2; @Before public void init() throws Exception { metadata = XMPMetadata.createXMPMetadata(); String tmpNsURI = "http://www.test.org/schem/"; tmp = new XMPSchema(metadata, tmpNsURI, "test"); tmp.addQualifiedBagValue("BagContainer", "Value1"); tmp.addQualifiedBagValue("BagContainer", "Value2"); tmp.addQualifiedBagValue("BagContainer", "Value3"); tmp.addUnqualifiedSequenceValue("SeqContainer", "Value1"); tmp.addUnqualifiedSequenceValue("SeqContainer", "Value2"); tmp.addUnqualifiedSequenceValue("SeqContainer", "Value3"); tmp.addProperty(metadata.getTypeMapping().createText(null, "test", "simpleProperty", "YEP")); tmp2 = new XMPSchema(metadata, "http://www.space.org/schem/", "space", "space"); tmp2.addUnqualifiedSequenceValue("SeqSpContainer", "ValueSpace1"); tmp2.addUnqualifiedSequenceValue("SeqSpContainer", "ValueSpace2"); tmp2.addUnqualifiedSequenceValue("SeqSpContainer", "ValueSpace3"); metadata.addSchema(tmp); metadata.addSchema(tmp2); // Check schema getting Assert.assertEquals(tmp, metadata.getSchema(tmpNsURI)); Assert.assertNull(metadata.getSchema("THIS URI NOT EXISTS !")); } @Test public void testAddingSchem() { List vals = metadata.getAllSchemas(); Assert.assertTrue(vals.contains(tmp)); Assert.assertTrue(vals.contains(tmp2)); } /* * @Test public void displayResult() throws TransformException { System.out.println * ("info used:\n XPacketBegin:"+metadata.getXpacketBegin()+ "\n XPacketID:"+metadata.getXpacketId()); * SaveMetadataHelper.serialize(metadata, true, System.out); * * } */ @Test(expected = org.apache.xmpbox.xml.XmpSerializationException.class) public void testTransformerExceptionMessage() throws XmpSerializationException { throw new XmpSerializationException("TEST"); } @Test(expected = org.apache.xmpbox.xml.XmpSerializationException.class) public void testTransformerExceptionWithCause() throws XmpSerializationException { throw new XmpSerializationException("TEST", new Throwable()); } @Test public void testInitMetaDataWithInfo() throws Exception { String xpacketBegin = "TESTBEG", xpacketId = "TESTID", xpacketBytes = "TESTBYTES", xpacketEncoding = "TESTENCOD"; metadata = XMPMetadata.createXMPMetadata(xpacketBegin, xpacketId, xpacketBytes, xpacketEncoding); Assert.assertEquals(xpacketBegin, metadata.getXpacketBegin()); Assert.assertEquals(xpacketId, metadata.getXpacketId()); Assert.assertEquals(xpacketBytes, metadata.getXpacketBytes()); Assert.assertEquals(xpacketEncoding, metadata.getXpacketEncoding()); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/SaveMetadataHelperTest.java0000644000000000000000000000374112645757426026344 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox; import org.apache.xmpbox.schema.AdobePDFSchema; import org.apache.xmpbox.schema.DublinCoreSchema; import org.junit.Test; public class SaveMetadataHelperTest { @Test public void testSchemaParsing() throws Exception { DublinCoreSchema dc = new DublinCoreSchema(XMPMetadata.createXMPMetadata()); dc.setCoverage("coverage"); dc.addContributor("contributor1"); dc.addContributor("contributor2"); dc.addDescription("x-default", "Description"); } @Test public void testMetadataParsing() throws Exception { XMPMetadata meta = XMPMetadata.createXMPMetadata(); DublinCoreSchema dc = meta.createAndAddDublinCoreSchema(); dc.setCoverage("coverage"); dc.addContributor("contributor1"); dc.addContributor("contributor2"); dc.addDescription("x-default", "Description"); AdobePDFSchema pdf = meta.createAndAddAdobePDFSchema(); pdf.setProducer("Producer"); pdf.setPDFVersion("1.4"); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/0000755000000000000000000000000012645757426022116 5ustar rootrootpdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestJobType.java0000644000000000000000000000413712645757426025202 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collection; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestJobType extends AbstractStructuredTypeTester { protected JobType structured = null; @Before public void before() throws Exception { super.before(); structured = new JobType(xmp, "job"); } public TestJobType(Class clz, String field, Types type) { super(clz, field, type); } @Override protected AbstractStructuredType getStructured() { return structured; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { JobType.class, "id", Types.Text }); result.add(new Object[] { JobType.class, "name", Types.Text }); result.add(new Object[] { JobType.class, "url", Types.URL }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/AbstractStructuredTypeTester.java0000644000000000000000000001053412645757426030645 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import junit.framework.Assert; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.xml.DomXmpParser; import org.junit.Test; public abstract class AbstractStructuredTypeTester { protected XMPMetadata xmp; protected String fieldName; protected Types type; protected Class clz; protected TypeMapping typeMapping = null; protected DomXmpParser builder; public void before() throws Exception { builder = new DomXmpParser(); xmp = XMPMetadata.createXMPMetadata(); typeMapping = xmp.getTypeMapping(); } public AbstractStructuredTypeTester(Class clz, String fieldName, Types type) { this.clz = clz; this.fieldName = fieldName; this.type = type; } protected abstract AbstractStructuredType getStructured(); @Test public void testInitializedToNull() throws Exception { // default method Assert.assertNull(getStructured().getProperty(fieldName)); // accessor Method get = clz.getMethod(TypeTestingHelper.calculateSimpleGetter(fieldName), new Class[0]); Object result = get.invoke(getStructured(), new Object[0]); Assert.assertNull(result); } @Test public void testSettingValue() throws Exception { Object value = TypeTestingHelper.getJavaValue(type); getStructured().addSimpleProperty(fieldName, value); Assert.assertNotNull(getStructured().getProperty(fieldName)); // check other properties not modified List fields = TypeTestingHelper.getXmpFields(clz); for (Field field : fields) { // do not check the current name String name = field.get(null).toString(); if (!name.equals(fieldName)) { Assert.assertNull(getStructured().getProperty(name)); } } } @Test public void testPropertyType() throws Exception { Object value = TypeTestingHelper.getJavaValue(type); getStructured().addSimpleProperty(fieldName, value); Assert.assertNotNull(getStructured().getProperty(fieldName)); // check property type AbstractSimpleProperty asp = (AbstractSimpleProperty) getStructured().getProperty(fieldName); Assert.assertEquals(type.getImplementingClass(), asp.getClass()); } @Test public void testSetter() throws Exception { String setter = TypeTestingHelper.calculateSimpleSetter(fieldName); Object value = TypeTestingHelper.getJavaValue(type); Method set = clz.getMethod(setter, new Class[] { TypeTestingHelper.getJavaType(type) }); set.invoke(getStructured(), new Object[] { value }); // check property set Assert.assertEquals(value, ((AbstractSimpleProperty) getStructured().getProperty(fieldName)).getValue()); // check getter Method get = clz.getMethod(TypeTestingHelper.calculateSimpleGetter(fieldName), new Class[0]); Object result = get.invoke(getStructured(), new Object[0]); // Assert.assertEquals(getJavaType(td),result.getClass()); Assert.assertTrue(TypeTestingHelper.getJavaType(type).isAssignableFrom(result.getClass())); Assert.assertEquals(value, result); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestDerivedType.java0000644000000000000000000000715412645757426026054 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collection; import org.apache.xmpbox.XMPMetadata; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestDerivedType { public static final String PREFIX = "myprefix"; public static final String NAME = "myname"; public static final String VALUE = "myvalue"; protected XMPMetadata xmp; protected String type = null; protected Class clz = null; protected Constructor constructor = null; public TestDerivedType(Class clz, String type) { super(); this.clz = clz; this.type = type; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { AgentNameType.class, "AgentName" }); result.add(new Object[] { ChoiceType.class, "Choice" }); result.add(new Object[] { GUIDType.class, "GUID" }); result.add(new Object[] { LocaleType.class, "Locale" }); result.add(new Object[] { MIMEType.class, "MIME" }); result.add(new Object[] { PartType.class, "Part" }); result.add(new Object[] { ProperNameType.class, "ProperName" }); result.add(new Object[] { RenditionClassType.class, "RenditionClass" }); result.add(new Object[] { URIType.class, "URI" }); result.add(new Object[] { URLType.class, "URL" }); result.add(new Object[] { XPathType.class, "XPath" }); return result; } @Before public void before() throws Exception { xmp = XMPMetadata.createXMPMetadata(); constructor = clz.getConstructor(new Class[] { XMPMetadata.class, String.class, String.class, String.class, Object.class }); } protected TextType instanciate(XMPMetadata metadata, String namespaceURI, String prefix, String propertyName, Object value) throws Exception { Object[] initargs = new Object[] { metadata, namespaceURI, prefix, propertyName, value }; return constructor.newInstance(initargs); } @Test public void test1() throws Exception { TextType element = instanciate(xmp, null, PREFIX, NAME, VALUE); Assert.assertNull(element.getNamespace()); Assert.assertTrue(element.getValue() instanceof String); Assert.assertEquals(VALUE, element.getValue()); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestResourceRefType.java0000644000000000000000000000644112645757426026714 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collection; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestResourceRefType extends AbstractStructuredTypeTester { protected ResourceRefType structured = null; @Before public void before() throws Exception { super.before(); structured = new ResourceRefType(xmp); } public TestResourceRefType(Class clz, String field, Types type) { super(clz, field, type); } @Override protected AbstractStructuredType getStructured() { return structured; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); // result.add(new Object [] // {ResourceRefType.class,"alternatePaths","seq URI"}); result.add(new Object[] { ResourceRefType.class, "documentID", Types.URI }); result.add(new Object[] { ResourceRefType.class, "filePath", Types.URI }); result.add(new Object[] { ResourceRefType.class, "fromPart", Types.Part }); result.add(new Object[] { ResourceRefType.class, "instanceID", Types.URI }); result.add(new Object[] { ResourceRefType.class, "lastModifyDate", Types.Date }); result.add(new Object[] { ResourceRefType.class, "manager", Types.AgentName }); result.add(new Object[] { ResourceRefType.class, "managerVariant", Types.Text }); result.add(new Object[] { ResourceRefType.class, "manageTo", Types.URI }); result.add(new Object[] { ResourceRefType.class, "manageUI", Types.URI }); result.add(new Object[] { ResourceRefType.class, "maskMarkers", Types.Choice }); result.add(new Object[] { ResourceRefType.class, "partMapping", Types.Text }); result.add(new Object[] { ResourceRefType.class, "renditionClass", Types.RenditionClass }); result.add(new Object[] { ResourceRefType.class, "renditionParams", Types.Text }); result.add(new Object[] { ResourceRefType.class, "toPart", Types.Part }); result.add(new Object[] { ResourceRefType.class, "versionID", Types.Text }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestSimpleMetadataProperties.java0000644000000000000000000001757212645757426030604 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.Calendar; import java.util.List; import org.apache.xmpbox.XMPMetadata; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Test MetaData Objects for simple properties * * @author a183132 * */ public class TestSimpleMetadataProperties { protected XMPMetadata parent; @Before public void resetDocument() throws Exception { parent = XMPMetadata.createXMPMetadata(); } /** * Check the detection of a bad type * * @throws InappropriateTypeException */ @Test(expected = IllegalArgumentException.class) public void testBooleanBadTypeDetection() { new BooleanType(parent, null, "test", "booleen", "Not a Boolean"); } /** * Check the detection of a bad type * * @throws InappropriateTypeException */ @Test(expected = IllegalArgumentException.class) public void testDateBadTypeDetection() { new DateType(parent, null, "test", "date", "Bad Date"); } /** * Check the detection of a bad type * * @throws InappropriateTypeException */ @Test(expected = IllegalArgumentException.class) public void testIntegerBadTypeDetection() { new IntegerType(parent, null, "test", "integer", "Not an int"); } /** * Check the detection of a bad type * * @throws InappropriateTypeException */ @Test(expected = IllegalArgumentException.class) public void testRealBadTypeDetection() throws Exception { new RealType(parent, null, "test", "real", "Not a real"); } /** * Check the detection of a bad type * * @throws InappropriateTypeException */ @Test(expected = IllegalArgumentException.class) public void testTextBadTypeDetection() throws Exception { new TextType(parent, null, "test", "text", Calendar.getInstance()); } /** * Check if information between objects and the elment generated are equals * * @throws Exception */ @Test public void testElementAndObjectSynchronization() throws Exception { boolean boolv = true; Calendar datev = Calendar.getInstance(); int integerv = 1; float realv = Float.parseFloat("1.69"); String textv = "TEXTCONTENT"; BooleanType bool = parent.getTypeMapping().createBoolean(null, "test", "booleen", boolv); DateType date = parent.getTypeMapping().createDate(null, "test", "date", datev); IntegerType integer = parent.getTypeMapping().createInteger(null, "test", "integer", integerv); RealType real = parent.getTypeMapping().createReal(null, "test", "real", realv); TextType text = parent.getTypeMapping().createText(null, "test", "text", textv); Assert.assertEquals(boolv, bool.getValue()); Assert.assertEquals(datev, date.getValue()); Assert.assertEquals(Integer.valueOf(integerv), integer.getValue()); Assert.assertEquals(realv, real.getValue(), 0); Assert.assertEquals(textv, text.getStringValue()); } /** * Check the creation from string attributes * * @throws Exception */ @Test public void testCreationFromString() throws Exception { String boolv = "False"; String datev = "2010-03-22T14:33:11+01:00"; String integerv = "10"; String realv = "1.92"; String textv = "text"; BooleanType bool = new BooleanType(parent, null, "test", "booleen", boolv); DateType date = new DateType(parent, null, "test", "date", datev); IntegerType integer = new IntegerType(parent, null, "test", "integer", integerv); RealType real = new RealType(parent, null, "test", "real", realv); TextType text = new TextType(parent, null, "test", "text", textv); Assert.assertEquals(boolv, bool.getStringValue()); Assert.assertEquals(datev, date.getStringValue()); Assert.assertEquals(integerv, integer.getStringValue()); Assert.assertEquals(realv, real.getStringValue()); Assert.assertEquals(textv, text.getStringValue()); } /** * Check creation when a namespace is specified * * @throws Exception */ @Test public void testObjectCreationWithNamespace() throws Exception { String ns = "http://www.test.org/pdfa/"; BooleanType bool = parent.getTypeMapping().createBoolean(ns, "test", "booleen", true); DateType date = parent.getTypeMapping().createDate(ns, "test", "date", Calendar.getInstance()); IntegerType integer = parent.getTypeMapping().createInteger(ns, "test", "integer", 1); RealType real = parent.getTypeMapping().createReal(ns, "test", "real", (float) 1.6); TextType text = parent.getTypeMapping().createText(ns, "test", "text", "TEST"); Assert.assertEquals(ns, bool.getNamespace()); Assert.assertEquals(ns, date.getNamespace()); Assert.assertEquals(ns, integer.getNamespace()); Assert.assertEquals(ns, real.getNamespace()); Assert.assertEquals(ns, text.getNamespace()); } /** * Throw InappropriateType Exception * * @throws InappropriateTypeException */ @Test(expected = IllegalArgumentException.class) public void testExceptionWithCause() throws Exception { throw new IllegalArgumentException("TEST", new Throwable()); } /** * Check if attributes management works * * @throws Exception */ @Test public void testAttribute() throws Exception { IntegerType integer = new IntegerType(parent, null, "test", "integer", 1); Attribute value = new Attribute("http://www.test.org/test/", "value1", "StringValue1"); Attribute value2 = new Attribute("http://www.test.org/test/", "value2", "StringValue2"); integer.setAttribute(value); // System.out.println(value.getQualifiedName()); Assert.assertEquals(value, integer.getAttribute(value.getName())); Assert.assertTrue(integer.containsAttribute(value.getName())); // Replacement check integer.setAttribute(value2); Assert.assertEquals(value2, integer.getAttribute(value2.getName())); integer.removeAttribute(value2.getName()); Assert.assertFalse(integer.containsAttribute(value2.getName())); // Attribute with namespace Creation checking Attribute valueNS = new Attribute("http://www.tefst2.org/test/", "value2", "StringValue.2"); integer.setAttribute(valueNS); Attribute valueNS2 = new Attribute("http://www.test2.org/test/", "value2", "StringValueTwo"); integer.setAttribute(valueNS2); List atts = integer.getAllAttributes(); /* * for (Attribute attribute : atts) { System.out.println(attribute.getLocalName ()+" :"+attribute.getValue()); } */ Assert.assertFalse(atts.contains(valueNS)); Assert.assertTrue(atts.contains(valueNS2)); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestVersionType.java0000644000000000000000000000434612645757426026117 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collection; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestVersionType extends AbstractStructuredTypeTester { protected VersionType structured = null; @Before public void before() throws Exception { super.before(); structured = new VersionType(xmp); } public TestVersionType(Class clz, String field, Types type) { super(clz, field, type); } @Override protected AbstractStructuredType getStructured() { return structured; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); // result.add(new Object [] {VersionType.class,"version",Types.Text}); // result.add(new Object [] {VersionType.class,"comments",Types.Text}); // result.add(new Object [] // {VersionType.class,"modifyDate",Types.Date}); result.add(new Object[] { VersionType.class, "modifier", Types.ProperName }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestAbstractStructuredType.java0000644000000000000000000000654412645757426030324 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.Calendar; import junit.framework.Assert; import org.apache.xmpbox.XMPMetadata; import org.junit.Before; import org.junit.Test; public class TestAbstractStructuredType { private static class MyStructuredType extends AbstractStructuredType { @PropertyType(type = Types.Text, card = Cardinality.Simple) public static final String MYTEXT = "my-text"; @PropertyType(type = Types.Date, card = Cardinality.Simple) public static final String MYDATE = "my-date"; public MyStructuredType(XMPMetadata metadata, String namespaceURI, String fieldPrefix) { super(metadata, namespaceURI, fieldPrefix, "structuredPN"); } } protected MyStructuredType st; public static final String MY_NS = "http://www.apache.org/test#"; public static final String MY_PREFIX = "test"; @Before public void before() throws Exception { XMPMetadata xmp = XMPMetadata.createXMPMetadata(); st = new MyStructuredType(xmp, MY_NS, MY_PREFIX); } @Test public void validate() throws Exception { Assert.assertEquals(MY_NS, st.getNamespace()); Assert.assertEquals(MY_PREFIX, st.getPrefix()); Assert.assertEquals(MY_PREFIX, st.getPrefix()); } @Test public void testNonExistingProperty() throws Exception { Assert.assertNull(st.getProperty("NOT_EXISTING")); } @Test public void testNotValuatedPropertyProperty() throws Exception { Assert.assertNull(st.getProperty(MyStructuredType.MYTEXT)); } @Test public void testValuatedTextProperty() throws Exception { String s = "my value"; st.addSimpleProperty(MyStructuredType.MYTEXT, s); Assert.assertEquals(s, st.getPropertyValueAsString(MyStructuredType.MYTEXT)); Assert.assertNull(st.getPropertyValueAsString(MyStructuredType.MYDATE)); Assert.assertNotNull(st.getProperty(MyStructuredType.MYTEXT)); } @Test public void testValuatedDateProperty() throws Exception { Calendar c = Calendar.getInstance(); st.addSimpleProperty(MyStructuredType.MYDATE, c); Assert.assertEquals(c, st.getDatePropertyAsCalendar(MyStructuredType.MYDATE)); Assert.assertNull(st.getDatePropertyAsCalendar(MyStructuredType.MYTEXT)); Assert.assertNotNull(st.getProperty(MyStructuredType.MYDATE)); } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestResourceEventType.java0000644000000000000000000000467112645757426027264 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collection; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestResourceEventType extends AbstractStructuredTypeTester { protected ResourceEventType structured = null; @Before public void before() throws Exception { super.before(); structured = new ResourceEventType(xmp); } public TestResourceEventType(Class clz, String field, Types type) { super(clz, field, type); } @Override protected AbstractStructuredType getStructured() { return structured; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { ResourceEventType.class, "action", Types.Choice }); result.add(new Object[] { ResourceEventType.class, "changed", Types.Text }); result.add(new Object[] { ResourceEventType.class, "instanceID", Types.GUID }); result.add(new Object[] { ResourceEventType.class, "parameters", Types.Text }); result.add(new Object[] { ResourceEventType.class, "softwareAgent", Types.AgentName }); result.add(new Object[] { ResourceEventType.class, "when", Types.Date }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestThumbnailType.java0000644000000000000000000000434212645757426026411 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collection; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestThumbnailType extends AbstractStructuredTypeTester { protected ThumbnailType structured = null; @Before public void before() throws Exception { super.before(); structured = new ThumbnailType(xmp); } public TestThumbnailType(Class clz, String field, Types type) { super(clz, field, type); } @Override protected AbstractStructuredType getStructured() { return structured; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { ThumbnailType.class, "format", Types.Choice }); result.add(new Object[] { ThumbnailType.class, "height", Types.Integer }); result.add(new Object[] { ThumbnailType.class, "width", Types.Integer }); result.add(new Object[] { ThumbnailType.class, "image", Types.Text }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TypeTestingHelper.java0000644000000000000000000001036612645757426026406 0ustar rootroot/***************************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Random; import java.util.UUID; public final class TypeTestingHelper { public static String calculateSimpleGetter(String name) { StringBuilder sb = new StringBuilder(3 + name.length()); sb.append("get").append(calculateFieldNameForMethod(name)); return sb.toString(); } public static String calculateArrayGetter(String name) { StringBuilder sb = new StringBuilder(4 + name.length()); String fn = calculateFieldNameForMethod(name); sb.append("get").append(fn); if (!fn.endsWith("s")) { sb.append("s"); } return sb.toString(); } public static String calculateSimpleSetter(String name) { StringBuilder sb = new StringBuilder(3 + name.length()); sb.append("set").append(calculateFieldNameForMethod(name)); return sb.toString(); } public static String calculateFieldNameForMethod(String name) { StringBuilder sb = new StringBuilder(name.length()); sb.append(name.substring(0, 1).toUpperCase()).append(name.substring(1)); return sb.toString(); } public static Class getJavaType(Types type) { if (type.getImplementingClass() == TextType.class) { return String.class; } else if (type.getImplementingClass() == DateType.class) { return Calendar.class; } else if (type.getImplementingClass() == IntegerType.class) { return Integer.class; } else if (TextType.class.isAssignableFrom(type.getImplementingClass())) { return String.class; } else { throw new IllegalArgumentException("Type not expected in test : " + type.getImplementingClass()); } } public static Object getJavaValue(Types type) { if (type.getImplementingClass() == TextType.class) { return UUID.randomUUID().toString(); } else if (type.getImplementingClass() == DateType.class) { // use random because test are too fast (generate same calendar // twice) Calendar calendar = Calendar.getInstance(); Random rand = new Random(); calendar.setTimeInMillis(rand.nextLong()); return calendar; } else if (type.getImplementingClass() == IntegerType.class) { return new Integer(14); } else if (TextType.class.isAssignableFrom(type.getImplementingClass())) { // all derived from TextType return UUID.randomUUID().toString(); } else { throw new IllegalArgumentException("Type not expected in test : " + type.getImplementingClass()); } } public static List getXmpFields(Class clz) { Field[] fields = clz.getFields(); List result = new ArrayList(fields.length); for (Field field : fields) { if (field.getAnnotation(PropertyType.class) != null) { result.add(field); } } return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/TestLayerType.java0000644000000000000000000000405212645757426025540 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import java.util.ArrayList; import java.util.Collection; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestLayerType extends AbstractStructuredTypeTester { protected LayerType structured = null; @Before public void before() throws Exception { super.before(); structured = new LayerType(xmp); } public TestLayerType(Class clz, String field, Types type) { super(clz, field, type); } @Override protected AbstractStructuredType getStructured() { return structured; } @Parameters public static Collection initializeParameters() throws Exception { Collection result = new ArrayList(); result.add(new Object[] { LayerType.class, "LayerName", Types.Text }); result.add(new Object[] { LayerType.class, "LayerText", Types.Text }); return result; } } pdfbox-1.8.11/xmpbox/src/test/java/org/apache/xmpbox/type/AttributeTest.java0000644000000000000000000000456612645757426025577 0ustar rootroot/***************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ****************************************************************************/ package org.apache.xmpbox.type; import junit.framework.Assert; import org.junit.Test; public class AttributeTest { @Test public void testAtt() { String nsUri = "nsUri"; String prefix = "prefix"; String localName = "localName"; String value = "value"; Attribute att = new Attribute(nsUri, localName, value); Assert.assertEquals(nsUri, att.getNamespace()); Assert.assertEquals(localName, att.getName()); Assert.assertEquals(value, att.getValue()); String nsUri2 = "nsUri2"; String prefix2 = "prefix2"; String localName2 = "localName2"; String value2 = "value2"; att.setNsURI(nsUri2); att.setName(localName2); att.setValue(value2); Assert.assertEquals(nsUri2, att.getNamespace()); Assert.assertEquals(localName2, att.getName()); Assert.assertEquals(value2, att.getValue()); } @Test public void testAttWithoutPrefix() { String nsUri = "nsUri"; String localName = "localName"; String value = "value"; Attribute att = new Attribute(nsUri, localName, value); Assert.assertEquals(nsUri, att.getNamespace()); Assert.assertEquals(localName, att.getName()); att = new Attribute(nsUri, localName, value); Assert.assertEquals(nsUri, att.getNamespace()); Assert.assertEquals(localName, att.getName()); } } pdfbox-1.8.11/xmpbox/pom.xml0000644000000000000000000000733212645757426014443 0ustar rootroot 4.0.0 xmpbox bundle Apache XmpBox The Apache XmpBox library is an open source Java tool that implements Adobe's XMP(TM) specification. It can be used to parse, validate and create xmp contents. It is mainly used by subproject preflight of Apache PDFBox. XmpBox is a subproject of Apache PDFBox. org.apache.pdfbox pdfbox-parent 1.8.11 ../parent/pom.xml junit junit 4.8.1 test commons-io commons-io 1.4 test org.apache.felix maven-bundle-plugin true org.apache.maven.plugins maven-checkstyle-plugin 2.10 ../pdfbox-checkstyle-5.xml org.codehaus.mojo taglist-maven-plugin 2.4 UTF-8 en false TODO List TODO exact FIXME exact org.codehaus.mojo cobertura-maven-plugin 2.3 org.apache.maven.plugins maven-surefire-report-plugin 2.6 true true ${project.reporting.outputDirectory}/surefire-report pdfbox-1.8.11/xmpbox/README.txt0000644000000000000000000000327212645757426014623 0ustar rootroot==================================================== Apache XmpBox ==================================================== The Apache XmpBox library is an open source Java tool that implements Adobe's XMP(TM) specification. You need Java 5 (or higher) and Maven 2 to build XmpBox. The recommended build command is: mvn clean install The default build will compile the Java sources and package the binary classes into a jar package. See the Maven documentation for all the other available build options. See the issue tracker at https://issues.apache.org/jira/browse/PDFBOX (component XmpBox) for the full list of known issues and requested features. XmpBox is a subproject of Apache PDFBox. PDFBox is a project of the Apache Software Foundation . License (see also LICENSE.txt) ============================== Collective work: Copyright 2014 The Apache Software Foundation. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pdfbox-1.8.11/jempbox/0000755000000000000000000000000012645757504013245 5ustar rootrootpdfbox-1.8.11/jempbox/src/0000755000000000000000000000000012645757434014036 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/0000755000000000000000000000000012645757434014762 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/0000755000000000000000000000000012645757434015703 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/0000755000000000000000000000000012645757434016472 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/apache/0000755000000000000000000000000012645757434017713 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/0000755000000000000000000000000012645757434021357 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/0000755000000000000000000000000012645757434022163 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchema.java0000644000000000000000000010714312645757434024621 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.apache.jempbox.impl.DateConverter; import org.apache.jempbox.impl.XMLUtil; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * This class represents a metadata schema that can be stored in an XMP * document. It handles all generic properties that are available. See * subclasses for access to specific properties. * * @author Ben Litchfield * */ public class XMPSchema { /** * The standard xmlns namespace. */ public static final String NS_NAMESPACE = "http://www.w3.org/2000/xmlns/"; /** * The XML schema prefix. */ protected String prefix; /** * The DOM representation of this object. */ protected Element schema = null; /** * Create a new blank schema that can be populated. * * @param parent * The parent XMP document that this schema will be part of. * @param namespaceName * The name of the namespace, ie pdf,dc,... * @param namespaceURI * The URI of the namespace, ie "http://ns.adobe.com/pdf/1.3/" */ public XMPSchema(XMPMetadata parent, String namespaceName, String namespaceURI) { schema = parent.xmpDocument.createElementNS( "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf:Description"); prefix = namespaceName; schema.setAttributeNS(NS_NAMESPACE, "xmlns:" + namespaceName, namespaceURI); } /** * Create schema from an existing XML element. * * @param element * The existing XML element. * @param aPrefix * The XML prefix. */ public XMPSchema(Element element, String aPrefix) { schema = element; if (aPrefix != null) { prefix = aPrefix; } else { prefix = ""; } } /** * Get the XML element that is represented by this schema. * * @return The root XML element of this schema. */ public Element getElement() { return schema; } /** * Get the RDF about attribute. * * @return The RDF 'about' attribute. */ public String getAbout() { return getTextProperty("rdf:about"); } /** * Set the RDF 'about' attribute. Passing in null will clear this attribute. * * @param about * The new RFD about value. */ public void setAbout(String about) { if (about == null) { schema.removeAttribute("rdf:about"); } else { schema.setAttribute("rdf:about", about); } } /** * Set a simple text property on the schema. * * @param propertyName * The name of the property, it must contain the namespace * prefix, ie "pdf:Keywords" * @param propertyValue * The value for the property, can be any string. Passing null * will remove the property. */ public void setTextProperty(String propertyName, String propertyValue) { if (propertyValue == null) { schema.removeAttribute(propertyName); NodeList keywordList = schema.getElementsByTagName(propertyName); for (int i = 0; i < keywordList.getLength(); i++) { schema.removeChild(keywordList.item(i)); } } else { if (schema.hasAttribute(propertyName)) { schema.setAttribute(propertyName, propertyValue); } else { if (schema.hasChildNodes()) { NodeList nodeList = schema .getElementsByTagName(propertyName); if (nodeList.getLength() > 0) { Element node = (Element) nodeList.item(0); node.setNodeValue(propertyValue); } else { Element textNode = schema.getOwnerDocument() .createElement(propertyName); XMLUtil.setStringValue(textNode, propertyValue); schema.appendChild(textNode); } } else { schema.setAttribute(propertyName, propertyValue); } } } } /** * Get the value of a simple text property. * * @param propertyName * The name of the property to get, it must include the namespace * prefix. ie "pdf:Keywords". * * @return The value of the text property or the null if there is no value. */ public String getTextProperty(String propertyName) { // propertyValue == null does not work, since getAttribute returns the // empty string if the attribute is not found if (schema.hasAttribute(propertyName)) { return schema.getAttribute(propertyName); } else { NodeList nodes = schema.getElementsByTagName(propertyName); if (nodes.getLength() > 0) { Element node = (Element) nodes.item(0); return XMLUtil.getStringValue(node); } return null; } } /** * Get the value of the property as a date. * * @param propertyName * The fully qualified property name for the date. * * @return The value of the property as a date. * * @throws IOException * If there is an error converting the value to a date. */ public Calendar getDateProperty(String propertyName) throws IOException { return DateConverter.toCalendar(getTextProperty(propertyName)); } /** * Set the value of the property as a date. * * @param propertyName * The fully qualified property name for the date. * @param date * The date to set, or null to clear. */ public void setDateProperty(String propertyName, Calendar date) { if (date != null) { setTextProperty(propertyName, DateConverter.toISO8601(date)); } else { // remove the value for the given property setTextProperty(propertyName, null); } } /** * Get the value of the property as a boolean. * * @param propertyName * The fully qualified property name for the boolean. * * @return The value of the property as a boolean. */ public Boolean getBooleanProperty(String propertyName) { Boolean value = null; String stringValue = getTextProperty(propertyName); if (stringValue != null) { value = stringValue.equals("True") ? Boolean.TRUE : Boolean.FALSE; } return value; } /** * Set the value of the property as a boolean. * * @param propertyName * The fully qualified property name for the boolean. * @param bool * The boolean to set, or null to clear. */ public void setBooleanProperty(String propertyName, Boolean bool) { String value = null; if (bool != null) { value = bool.booleanValue() ? "True" : "False"; } setTextProperty(propertyName, value); } /** * Get the value of the property as an integer. * * @param propertyName * The fully qualified property name for the integer. * * @return The value of the property as an integer. */ public Integer getIntegerProperty(String propertyName) { Integer retval = null; String intProperty = getTextProperty(propertyName); if (intProperty != null && intProperty.length() > 0) { retval = new Integer(intProperty); } return retval; } /** * Set the value of the property as an integer. * * @param propertyName * The fully qualified property name for the integer. * @param intValue * The int to set, or null to clear. */ public void setIntegerProperty(String propertyName, Integer intValue) { String textValue = null; if (intValue != null) { textValue = intValue.toString(); } setTextProperty(propertyName, textValue); } /** * Remove all matching entries with the given value from the bag. * * @param bagName * The name of the bag, it must include the namespace prefix. ie * "pdf:Keywords". * @param bagValue * The value to remove from the bagList. */ public void removeBagValue(String bagName, String bagValue) { Element bagElement = null; NodeList nodes = schema.getElementsByTagName(bagName); if (nodes.getLength() > 0) { Element contElement = (Element) nodes.item(0); NodeList bagList = contElement.getElementsByTagName("rdf:Bag"); if (bagList.getLength() > 0) { bagElement = (Element) bagList.item(0); NodeList items = bagElement.getElementsByTagName("rdf:li"); for (int i = items.getLength() - 1; i >= 0; i--) { Element li = (Element) items.item(i); String value = XMLUtil.getStringValue(li); if (value.equals(bagValue)) { bagElement.removeChild(li); } } } } } /** * Add an entry to a bag property. * * @param bagName * The name of the bag, it must include the namespace prefix. ie * "pdf:Keywords". * @param bagValue * The value to add to the bagList. */ public void addBagValue(String bagName, String bagValue) { Element bagElement = null; NodeList nodes = schema.getElementsByTagName(bagName); if (nodes.getLength() > 0) { Element contElement = (Element) nodes.item(0); NodeList bagList = contElement.getElementsByTagName("rdf:Bag"); if (bagList.getLength() > 0) { bagElement = (Element) bagList.item(0); } } else { Element contElement = schema.getOwnerDocument().createElement( bagName); schema.appendChild(contElement); bagElement = schema.getOwnerDocument().createElement("rdf:Bag"); contElement.appendChild(bagElement); } Element liElement = schema.getOwnerDocument().createElement("rdf:li"); XMLUtil.setStringValue(liElement, bagValue); if (bagElement != null) { bagElement.appendChild(liElement); } } /** * Get all the values of the bag property. This will return a list of * java.lang.String objects, this is a read-only list. * * @param bagName * The name of the bag property to get, it must include the * namespace prefix. ie "pdf:Keywords" * * @return All of the values of the bag property in a list. */ public List getBagList(String bagName) { List retval = null; NodeList nodes = schema.getElementsByTagName(bagName); if (nodes.getLength() > 0) { Element contributor = (Element) nodes.item(0); NodeList bagList = contributor.getElementsByTagName("rdf:Bag"); if (bagList.getLength() > 0) { Element bag = (Element) bagList.item(0); retval = new ArrayList(); NodeList items = bag.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); retval.add(XMLUtil.getStringValue(li)); } retval = Collections.unmodifiableList(retval); } } return retval; } /** * Remove all matching values from a sequence property. * * @param seqName * The name of the sequence property. It must include the * namespace prefix. ie "pdf:Keywords". * @param seqValue * The value to remove from the list. */ public void removeSequenceValue(String seqName, String seqValue) { Element bagElement = null; NodeList nodes = schema.getElementsByTagName(seqName); if (nodes.getLength() > 0) { Element contElement = (Element) nodes.item(0); NodeList bagList = contElement.getElementsByTagName("rdf:Seq"); if (bagList.getLength() > 0) { bagElement = (Element) bagList.item(0); NodeList items = bagElement.getElementsByTagName("rdf:li"); for (int i = items.getLength() - 1; i >= 0; i--) { Element li = (Element) items.item(i); String value = XMLUtil.getStringValue(li); if (value.equals(seqValue)) { bagElement.removeChild(li); } } } } } /** * Remove a value from a sequence property. This will remove all entries * from the list. * * @param seqName * The name of the sequence property. It must include the * namespace prefix. ie "pdf:Keywords". * @param seqValue * The value to remove from the list. */ public void removeSequenceValue(String seqName, Elementable seqValue) { Element bagElement = null; NodeList nodes = schema.getElementsByTagName(seqName); if (nodes.getLength() > 0) { Element contElement = (Element) nodes.item(0); NodeList bagList = contElement.getElementsByTagName("rdf:Seq"); if (bagList.getLength() > 0) { bagElement = (Element) bagList.item(0); NodeList items = bagElement.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); if (li == seqValue.getElement()) { bagElement.removeChild(li); } } } } } /** * Add a new value to a sequence property. * * @param seqName * The name of the sequence property, it must include the * namespace prefix. ie "pdf:Keywords" * @param seqValue * The value to add to the sequence. */ public void addSequenceValue(String seqName, String seqValue) { Element bagElement = null; NodeList nodes = schema.getElementsByTagName(seqName); if (nodes.getLength() > 0) { Element contElement = (Element) nodes.item(0); NodeList bagList = contElement.getElementsByTagName("rdf:Seq"); if (bagList.getLength() > 0) { bagElement = (Element) bagList.item(0); } else { // xml is crap discard it schema.removeChild(nodes.item(0)); } } if (bagElement == null) { Element contElement = schema.getOwnerDocument().createElement( seqName); schema.appendChild(contElement); bagElement = schema.getOwnerDocument().createElement("rdf:Seq"); contElement.appendChild(bagElement); } Element liElement = schema.getOwnerDocument().createElement("rdf:li"); liElement.appendChild(schema.getOwnerDocument() .createTextNode(seqValue)); bagElement.appendChild(liElement); } /** * Add a new value to a sequence property. * * @param seqName * The name of the sequence property, it must include the * namespace prefix. ie "pdf:Keywords" * @param seqValue * The value to add to the sequence. */ public void addSequenceValue(String seqName, Elementable seqValue) { Element bagElement = null; NodeList nodes = schema.getElementsByTagName(seqName); if (nodes.getLength() > 0) { Element contElement = (Element) nodes.item(0); NodeList bagList = contElement.getElementsByTagName("rdf:Seq"); if (bagList.getLength() > 0) { bagElement = (Element) bagList.item(0); } } else { Element contElement = schema.getOwnerDocument().createElement( seqName); schema.appendChild(contElement); bagElement = schema.getOwnerDocument().createElement("rdf:Seq"); contElement.appendChild(bagElement); } if (bagElement != null) { bagElement.appendChild(seqValue.getElement()); } } /** * Get all the values in a sequence property. * * @param seqName * The name of the sequence property, it must include the * namespace prefix. ie "pdf:Keywords". * * @return A read-only list of java.lang.String objects or null if the * property does not exist. */ public List getSequenceList(String seqName) { List retval = null; NodeList nodes = schema.getElementsByTagName(seqName); if (nodes.getLength() > 0) { Element contributor = (Element) nodes.item(0); NodeList bagList = contributor.getElementsByTagName("rdf:Seq"); if (bagList.getLength() > 0) { Element bag = (Element) bagList.item(0); retval = new ArrayList(); NodeList items = bag.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); retval.add(XMLUtil.getStringValue(li)); } retval = Collections.unmodifiableList(retval); } } return retval; } /** * Get a list of ResourceEvent objects. * * @param seqName * The name of the sequence to retrieve. * * @return A list of ResourceEvent objects or null if they do not exist. */ public List getEventSequenceList(String seqName) { List retval = null; NodeList nodes = schema.getElementsByTagName(seqName); if (nodes.getLength() > 0) { Element contributor = (Element) nodes.item(0); NodeList bagList = contributor.getElementsByTagName("rdf:Seq"); if (bagList.getLength() > 0) { Element bag = (Element) bagList.item(0); retval = new ArrayList(); NodeList items = bag.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); retval.add(new ResourceEvent(li)); } retval = Collections.unmodifiableList(retval); } } return retval; } /** * Remove a date sequence value from the list. * * @param seqName * The name of the sequence property, it must include the * namespace prefix. ie "pdf:Keywords" * @param date * The date to remove from the sequence property. */ public void removeSequenceDateValue(String seqName, Calendar date) { String dateAsString = DateConverter.toISO8601(date); removeSequenceValue(seqName, dateAsString); } /** * Add a date sequence value to the list. * * @param seqName * The name of the sequence property, it must include the * namespace prefix. ie "pdf:Keywords" * @param date * The date to add to the sequence property. */ public void addSequenceDateValue(String seqName, Calendar date) { String dateAsString = DateConverter.toISO8601(date); addSequenceValue(seqName, dateAsString); } /** * Get all the date values in a sequence property. * * @param seqName * The name of the sequence property, it must include the * namespace prefix. ie "pdf:Keywords". * * @return A read-only list of java.util.Calendar objects or null if the * property does not exist. * * @throws IOException * If there is an error converting the value to a date. */ public List getSequenceDateList(String seqName) throws IOException { List strings = getSequenceList(seqName); List retval = null; if (strings != null) { retval = new ArrayList(); for (int i = 0; i < strings.size(); i++) { retval.add(DateConverter.toCalendar(strings.get(i))); } } return retval; } /** * Set the value of a multi-lingual property. * * @param propertyName * The name of the property, it must include the namespace * prefix. ie "pdf:Keywords" * @param language * The language code of the value. If null then "x-default" is * assumed. * @param value * The value of the property in the specified language. */ public void setLanguageProperty(String propertyName, String language, String value) { NodeList nodes = schema.getElementsByTagName(propertyName); Element property = null; if (nodes.getLength() == 0) { if (value == null) { // value is null, it doesn't already exist so there // is nothing to do. return; } property = schema.getOwnerDocument().createElement(propertyName); schema.appendChild(property); } else { property = (Element) nodes.item(0); } Element alt = null; NodeList altList = property.getElementsByTagName("rdf:Alt"); if (altList.getLength() == 0) { if (value == null) { // value is null, it doesn't already exist so there // is nothing to do. return; } alt = schema.getOwnerDocument().createElement("rdf:Alt"); property.appendChild(alt); } else { alt = (Element) altList.item(0); } NodeList items = alt.getElementsByTagName("rdf:li"); if (language == null) { language = "x-default"; } boolean foundValue = false; for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); if (value == null) { alt.removeChild(li); } else if (language.equals(li.getAttribute("xml:lang"))) { foundValue = true; XMLUtil.setStringValue(li, value); } } if (value != null && !foundValue) { Element li = schema.getOwnerDocument().createElement("rdf:li"); li.setAttribute("xml:lang", language); XMLUtil.setStringValue(li, value); if (language.equals("x-default")) { // default should be first element, see XMP spec alt.insertBefore(li, alt.getFirstChild()); } else { alt.appendChild(li); } } } /** * Get the value of a multi-lingual property. * * @param propertyName * The name of the property, it must include the namespace * prefix. ie "pdf:Keywords" * @param language * The language code of the value. If null then "x-default" is * assumed. * * @return The value of the language property. */ public String getLanguageProperty(String propertyName, String language) { String retval = null; if (language == null) { language = "x-default"; } NodeList nodes = schema.getElementsByTagName(propertyName); if (nodes.getLength() > 0) { Element property = (Element) nodes.item(0); NodeList altList = property.getElementsByTagName("rdf:Alt"); if (altList.getLength() > 0) { Element alt = (Element) altList.item(0); NodeList items = alt.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength() && retval == null; i++) { Element li = (Element) items.item(i); String elementLanguage = li.getAttribute("xml:lang"); if (language.equals(elementLanguage)) { retval = XMLUtil.getStringValue(li); } } } else if (property.getChildNodes().getLength() == 1 && Node.TEXT_NODE == property.getFirstChild().getNodeType()) { retval = property.getFirstChild().getNodeValue(); } } return retval; } /** * Set the value of a multi-lingual property. * * @param propertyName * The name of the property, it must include the namespace * prefix. ie "pdf:Keywords" * @param language * The language code of the value. If null then "x-default" is * assumed. * @param value * The value of the property in the specified language. */ public void setThumbnailProperty(String propertyName, String language, Thumbnail value) { NodeList nodes = schema.getElementsByTagName(propertyName); Element property = null; if (nodes.getLength() == 0) { if (value == null) { // value is null, it doesn't already exist so there // is nothing to do. return; } property = schema.getOwnerDocument().createElement(propertyName); schema.appendChild(property); } else { property = (Element) nodes.item(0); } Element alt = null; NodeList altList = property.getElementsByTagName("rdf:Alt"); if (altList.getLength() == 0) { if (value == null) { // value is null, it doesn't already exist so there // is nothing to do. return; } alt = schema.getOwnerDocument().createElement("rdf:Alt"); property.appendChild(alt); } else { alt = (Element) altList.item(0); } NodeList items = alt.getElementsByTagName("rdf:li"); if (language == null) { language = "x-default"; } boolean foundValue = false; for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); if (value == null) { alt.removeChild(li); } else if (language.equals(li.getAttribute("xml:lang"))) { foundValue = true; alt.replaceChild(li, value.getElement()); } } if (value != null && !foundValue) { Element li = value.getElement(); li.setAttribute("xml:lang", language); if (language.equals("x-default")) { // default should be first element, see XMP spec alt.insertBefore(li, alt.getFirstChild()); } else { alt.appendChild(li); } } } /** * Get the value of a multi-lingual property. * * @param propertyName * The name of the property, it must include the namespace * prefix. ie "pdf:Keywords" * @param language * The language code of the value. If null then "x-default" is * assumed. * * @return The value of the language property. */ public Thumbnail getThumbnailProperty(String propertyName, String language) { Thumbnail retval = null; if (language == null) { language = "x-default"; } NodeList nodes = schema.getElementsByTagName(propertyName); if (nodes.getLength() > 0) { Element property = (Element) nodes.item(0); NodeList altList = property.getElementsByTagName("rdf:Alt"); if (altList.getLength() > 0) { Element alt = (Element) altList.item(0); NodeList items = alt.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength() && retval == null; i++) { Element li = (Element) items.item(i); String elementLanguage = li.getAttribute("xml:lang"); if (language.equals(elementLanguage)) { retval = new Thumbnail(li); } } } } return retval; } /** * Get a list of all languages that are currently defined for a specific * property. * * @param propertyName * The name of the property, it must include the namespace * prefix. ie "pdf:Keywords" * * @return A list of all languages, this will return an non-null empty list * if none have been defined. */ public List getLanguagePropertyLanguages(String propertyName) { List retval = new ArrayList(); NodeList nodes = schema.getElementsByTagName(propertyName); if (nodes.getLength() > 0) { Element property = (Element) nodes.item(0); NodeList altList = property.getElementsByTagName("rdf:Alt"); if (altList.getLength() > 0) { Element alt = (Element) altList.item(0); NodeList items = alt.getElementsByTagName("rdf:li"); for (int i = 0; i < items.getLength(); i++) { Element li = (Element) items.item(i); String elementLanguage = li.getAttribute("xml:lang"); if (elementLanguage == null) { retval.add("x-default"); } else { retval.add(elementLanguage); } } } } return retval; } /** * A basic schema merge, it merges bags and sequences and replace everything * else. * * @param xmpSchema The schema to merge. * @throws IOException If there is an error during the merge. */ public void merge(XMPSchema xmpSchema) throws IOException { if (!xmpSchema.getClass().equals(this.getClass())) { throw new IOException("Can only merge schemas of the same type."); } NamedNodeMap attributes = xmpSchema.getElement().getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node a = attributes.item(i); String name = a.getNodeName(); if (name.startsWith(prefix)) { String newValue = xmpSchema.getTextProperty(name); setTextProperty(name, newValue); } } NodeList nodes = xmpSchema.getElement().getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node a = nodes.item(i); String name = a.getNodeName(); if (name.startsWith(prefix)) { if (a instanceof Element) { Element e = (Element) a; if (nodes.getLength() > 0) { NodeList seqList = e.getElementsByTagName("rdf:Seq"); if (seqList.getLength() > 0) { List newList = xmpSchema.getSequenceList(name); List oldList = getSequenceList(name); Iterator it = newList.iterator(); while (it.hasNext()) { String object = it.next(); if (oldList == null || !oldList.contains(object)) { addSequenceValue(name, object); } } continue; } NodeList bagList = e.getElementsByTagName("rdf:Bag"); if (bagList.getLength() > 0) { List newList = xmpSchema.getBagList(name); List oldList = getBagList(name); Iterator it = newList.iterator(); while (it.hasNext()) { String object = it.next(); if (oldList == null || !oldList.contains(object)) { addBagValue(name, object); } } continue; } } } String newValue = xmpSchema.getTextProperty(name); setTextProperty(name, newValue); } } } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/ResourceRef.java0000644000000000000000000001647612645757434025270 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.apache.jempbox.impl.XMLUtil; import org.w3c.dom.Element; /** * This class represents a multiple part reference to a resource. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class ResourceRef implements Elementable { /** * The DOM representation of this object. */ protected Element parent = null; /** * Create a resource reference based on a existing parent property set. * * @param parentElement The parent element that will store the resource properties. */ public ResourceRef( Element parentElement ) { parent = parentElement; if( !parent.hasAttribute( "xmlns:stRef" ) ) { parent.setAttributeNS( XMPSchema.NS_NAMESPACE, "xmlns:stRef", "http://ns.adobe.com/xap/1.0/sType/ResourceRef#" ); } } /** * Get the underlying XML element. * * @return The XML element that this object represents. */ public Element getElement() { return parent; } /** * Get the referenced resource's id. * * @return The id of the reference. */ public String getInstanceID() { return XMLUtil.getStringValue( parent, "stRef:instanceID" ); } /** * Set the referenced resource's id. * * @param id The id of the reference. */ public void setInstanceID( String id ) { XMLUtil.setStringValue( parent, "stRef:instanceID", id ); } /** * Get the referenced resource's document id. * * @return The id of the reference document. */ public String getDocumentID() { return XMLUtil.getStringValue( parent, "stRef:documentID" ); } /** * Set the referenced resource's document id. * * @param id The id of the reference document. */ public void setDocumentID( String id ) { XMLUtil.setStringValue( parent, "stRef:documentID", id ); } /** * Get the referenced resource's document version id. * * @return The id of the reference document version. */ public String getVersionID() { return XMLUtil.getStringValue( parent, "stRef:versionID" ); } /** * Set the referenced resource's version id. * * @param id The id of the reference document version. */ public void setVersionID( String id ) { XMLUtil.setStringValue( parent, "stRef:veresionID", id ); } /** * Get the rendition class. * * @return The value of the rendition class property. * * @see ResourceRef#setRenditionClass( String ) */ public String getRenditionClass() { return XMLUtil.getStringValue( parent, "stRef:renditionClass" ); } /** * Set the rendition class. The rendition class is derived from a defined * set of names. The value is series of colon separated tokens and parameters.
* Defined values are:
* * * * * * * * * *
Token NameDescription
defaultSpecifies master document, no additional tokens allowed
thumbnailA simplied preview. Recommended order is: thumbnailformat:size:colorspace
screenScreen resolution
proofA review proof
draftA review rendition
low-resA low resolution, full size stand-in
* * * @param renditionClass The rendition class. */ public void setRenditionClass( String renditionClass ) { XMLUtil.setStringValue( parent, "stRef:renditionClass", renditionClass ); } /** * Get the extra rendition params. * * @return Additional rendition parameters. */ public String getRenditionParams() { return XMLUtil.getStringValue( parent, "stRef:renditionParams" ); } /** * Set addition rendition params. * * @param params Additional rendition parameters that are too complex for the rendition class. */ public void setRenditionParams( String params ) { XMLUtil.setStringValue( parent, "stRef:renditionParams", params ); } /** * Get name of the asset management system that manages this resource. * * @return The name of a asset management system. */ public String getManager() { return XMLUtil.getStringValue( parent, "stRef:manager" ); } /** * Set the name of the system that manages this resource. * * @param manager The name of the management system. */ public void setMangager( String manager ) { XMLUtil.setStringValue( parent, "stRef:manager", manager ); } /** * Get name of the variant of asset management system that manages this resource. * * @return The name of a asset management system. */ public String getManagerVariant() { return XMLUtil.getStringValue( parent, "stRef:managerVariant" ); } /** * Set the name of the variant of the system that manages this resource. * * @param managerVariant The name of the management system. */ public void setMangagerVariant( String managerVariant ) { XMLUtil.setStringValue( parent, "stRef:managerVariant", managerVariant ); } /** * URI identifying the managed resource. * * @return The URI to resource. */ public String getManagerTo() { return XMLUtil.getStringValue( parent, "stRef:managerTo" ); } /** * Set the URI to the managed resource. * * @param managerTo The URI to the managed resource. */ public void setMangagerTo( String managerTo ) { XMLUtil.setStringValue( parent, "stRef:managerTo", managerTo ); } /** * URI to info about the managed resource. * * @return The URI to the resource info. */ public String getManagerUI() { return XMLUtil.getStringValue( parent, "stRef:managerUI" ); } /** * Set the URI to the info about the managed resource. * * @param managerUI The URI to the managed resource information. */ public void setMangagerUI( String managerUI ) { XMLUtil.setStringValue( parent, "stRef:managerUI", managerUI ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaRightsManagement.java0000644000000000000000000001333112645757434027772 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.util.List; import org.w3c.dom.Element; /** * Define XMP properties that are related to rights management. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class XMPSchemaRightsManagement extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/xap/1.0/rights/"; /** * Construct a new blank PDF schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaRightsManagement(XMPMetadata parent) { super(parent, "xmpRights", NAMESPACE); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaRightsManagement(Element element, String prefix) { super(element, prefix); } /** * The online rights management certificate. * * @param certificate The URL to the rights cert. */ public void setCertificateURL( String certificate ) { setTextProperty("xmpRights:Certificate", certificate); } /** * Get the URL of the rights managment certificate. * * @return The rights management certificate URL. */ public String getCertificateURL() { return getTextProperty(prefix + ":Certificate"); } /** * Flag indicating if this is a rights managed resource. * * @param marked The marked value. */ public void setMarked( Boolean marked ) { setBooleanProperty(prefix + ":Marked", marked); } /** * Get the flag that indicates if this is a marked resource.. * * @return The value of the marked flag. */ public Boolean getMarked() { Boolean b = getBooleanProperty(prefix + ":Marked"); return b != null ? b : Boolean.FALSE; } /** * Remove an owner from the list. * * @param owner The owner to remove. */ public void removeOwner( String owner ) { removeBagValue(prefix + ":Owner", owner); } /** * Add an owner to the list. * * @param owner A new legal owner to this resource. */ public void addOwner( String owner ) { addBagValue(prefix + ":Owner", owner); } /** * Get the complete list of legal owners. * * @return The list of owners. */ public List getOwners() { return getBagList(prefix + ":Owner"); } /** * Set the default usage terms for this resource. * * @param terms The resource usage terms. */ public void setUsageTerms( String terms ) { setLanguageProperty(prefix + ":UsageTerms", null, terms); } /** * Get the default usage terms for the document. * * @return The terms for this resource. */ public String getUsageTerms() { return getLanguageProperty(prefix + ":UsageTerms", null); } /** * Set the usage terms of this resource in a specific language. * * @param language The language code. * @param terms The terms of this resource. */ public void setDescription( String language, String terms ) { setLanguageProperty(prefix + ":UsageTerms", language, terms); } /** * Get the usage terms in a specific language. * * @param language The language code to get the description for. * * @return The usage terms in the specified language or null if it does not exist. */ public String getUsageTerms( String language ) { return getLanguageProperty(prefix + ":UsageTerms", language); } /** * Get a list of all languages that a usage term exists for. * * @return A non-null list of languages, potentially an empty list. */ public List getUsageTermsLanguages() { return getLanguagePropertyLanguages(prefix + ":UsageTerms"); } /** * Set the external link that describes the owners/rights of this resource. * * @param webStatement The URL to a terms site. */ public void setWebStatement( String webStatement ) { setTextProperty(prefix + ":WebStatement", webStatement); } /** * Get the URL that describes the terms of this resource. * * @return The usage rights URL. */ public String getWebStatement() { return getTextProperty(prefix + ":WebStatement"); } /** * Set the copyright information. * * @param copyright The copyright information. */ public void setCopyright( String copyright ) { setTextProperty(prefix + ":Copyright", copyright); } /** * Get the copyright information. * * @return The copyright information. */ public String getCopyright() { return getTextProperty(prefix + ":Copyright"); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaIptc4xmpCore.java0000644000000000000000000001534312645757434027063 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.util.List; import org.w3c.dom.Element; /** * Define XMP properties used with IPTC specification. * * @author $Author: benlitchfield $ * @version $Revision: 1.3 $ */ public class XMPSchemaIptc4xmpCore extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"; /** * Construct a new blank IPTC schema. * * @param metadata The parent metadata schema that this will be part of. */ public XMPSchemaIptc4xmpCore(XMPMetadata metadata) { super(metadata, "Iptc4xmpCore", NAMESPACE); } /** * Constructor from an existing element. * * @param element The XML element. * @param aPrefix The XML prefix; Iptc4xmpCore. */ public XMPSchemaIptc4xmpCore(Element element, String aPrefix) { super(element, aPrefix); } /** * Contact Info Address City. * * @param city The city name. */ public void setCiAdrCity( String city ) { setTextProperty(prefix + ":CiAdrCity", city); } /** * Contact Info Address City. * * @return The city. */ public String getCiAdrCity() { return getTextProperty(prefix + ":CiAdrCity"); } /** * Contact Info country. * * @param country The CI country. */ public void setCiAdrCtry( String country ) { setTextProperty(prefix + ":CiAdrCtry", country); } /** * Contact Info country. * * @return The CI country. */ public String getCiAdrCtry() { return getTextProperty(prefix + ":CiAdrCtry"); } /** * Contact Info Extended Address(company name). * * @param adr Address info. */ public void setCiAdrExtadr( String adr ) { setTextProperty(prefix + ":CiAdrExtadr", adr); } /** * Contact Info Extended Address(company name). * * @return The extended address info. */ public String getCiAdrExtadr() { return getTextProperty(prefix + ":CiAdrExtadr"); } /** * Postal code. * * @param po The postal code. */ public void setCiAdrPcode( String po ) { setTextProperty(prefix + ":CiAdrPcode", po); } /** * Postal code. * * @return The postal code. */ public String getCiAdrPcode() { return getTextProperty(prefix + ":CiAdrPcode"); } /** * Postal region or state. * * @param state The postal region */ public void setCiAdrRegion( String state ) { setTextProperty(prefix + ":CiAdrRegion", state); } /** * Postal region or state. * * @return The postal state. */ public String getCiAdrRegion() { return getTextProperty(prefix + ":CiAdrRegion"); } /** * Work email. * * @param email The work email. */ public void setCiEmailWork( String email ) { setTextProperty(prefix + ":CiEmailWork", email); } /** * Work email. * * @return The work email. */ public String getCiEmailWork() { return getTextProperty(prefix + ":CiEmailWork"); } /** * Work telephone. * * @param tel The work telephone. */ public void setCiTelWork( String tel ) { setTextProperty(prefix + ":CiTelWork", tel); } /** * Work Telephone. * * @return The work telephone. */ public String getCiTelWork() { return getTextProperty(prefix + ":CiTelWork"); } /** * Work URL. * * @param url The work URL. */ public void setCiUrlWork( String url ) { setTextProperty(prefix + ":CiUrlWork", url); } /** * Work URL. * * @return work URL. */ public String getCiUrlWork() { return getTextProperty(prefix + ":CiUrlWork"); } /** * Name of location that the content is focussing on. * * @param loc The location. */ public void setLocation( String loc ) { setTextProperty(prefix + ":Location", loc); } /** * Name of location that the content is focussing on. * @return The location. */ public String getLocation() { return getTextProperty(prefix + ":Location"); } /** * The IPTC scene. * * @param scene The IPTC scene. */ public void addScene( String scene ) { addBagValue(prefix + ":Scene", scene); } /** * A list of all the scenes. * * @return The list of scenes. */ public List getScenes() { return getBagList(prefix + ":Scene"); } /** * Add IPTC subject code. * @param subject The IPTC subject. */ public void addSubjectCode( String subject ) { addBagValue(prefix + ":SubjectCode", subject); } /** * Get a list of all IPTC subject codes. * * @return All IPTC subject codes. */ public List getSubjectCodes() { return getBagList(prefix + ":SubjectCode"); } /** * Nature of a news object. * * @param genre The news genre. */ public void setIntellectualGenre( String genre ) { setTextProperty(prefix + ":IntellectualGenre", genre); } /** * Nature of a news object. * * @return The news genre. */ public String getIntellectualGenre() { return getTextProperty(prefix + ":IntellectualGenre"); } /** * ISO Country Code. * * @param code The country code. */ public void setCountryCode( String code ) { setTextProperty(prefix + ":CountryCode", code); } /** * ISO Country Code. * * @return The country code. */ public String getCountryCode() { return getTextProperty(prefix + ":CountryCode"); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaDublinCore.java0000644000000000000000000003300612645757434026564 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.io.IOException; import java.util.Calendar; import java.util.List; import org.w3c.dom.Element; /** * Define XMP properties used with the Dublin Core specification. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class XMPSchemaDublinCore extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://purl.org/dc/elements/1.1/"; /** * Construct a new blank Dublin Core schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaDublinCore( XMPMetadata parent ) { super( parent, "dc", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaDublinCore( Element element, String prefix ) { super( element, prefix ); } /** * Remove a contributor from the list of contributors. * * @param contributor The contributor to remove. */ public void removeContributor( String contributor ) { removeBagValue( prefix + ":contributor", contributor ); } /** * Add a contributor to the list of contributors. A contributor is someone other than an author. * * @param contributor The name of the contributor. */ public void addContributor( String contributor ) { addBagValue( prefix + ":contributor", contributor ); } /** * Get the complete list of contributors. * * @return The list of contributors. */ public List getContributors() { return getBagList( prefix + ":contributor" ); } /** * Set the coverage property. * * @param coverage The extend or scope of the resource. */ public void setCoverage( String coverage ) { setTextProperty( prefix + ":coverage", coverage ); } /** * Get the coverage property. * * @return The extent or scope of the resource. */ public String getCoverage() { return getTextProperty( prefix + ":coverage" ); } /** * Remove a creator from the list of creators. * * @param creator The author of the resource. */ public void removeCreator( String creator ) { removeSequenceValue( prefix + ":creator", creator ); } /** * Add a creator. * * @param creator The author of the resource. */ public void addCreator( String creator ) { addSequenceValue( prefix + ":creator", creator ); } /** * Get a complete list of creators. * * @return A list of java.lang.String objects. */ public List getCreators() { return getSequenceList( prefix + ":creator" ); } /** * Remove a date from the list of 'interesting' dates. * * @param date The date to remove. */ public void removeDate( Calendar date ) { removeSequenceDateValue( prefix + ":date", date ); } /** * Add a date of interest to this schema. * * @param date The date to add to the schema. */ public void addDate( Calendar date ) { addSequenceDateValue( prefix + ":date", date ); } /** * Get a list of all dates of interest to this resource. * * @return A list of java.util.Calendar objects. * * @throws IOException If there is an error creating the date object. */ public List getDates() throws IOException { return getSequenceDateList( prefix + ":date" ); } /** * Set the default value for the description. * * @param description The description of this resource. */ public void setDescription( String description ) { setLanguageProperty( prefix + ":description", null, description ); } /** * Get the default value for the description. * * @return The description of this resource. */ public String getDescription() { return getLanguageProperty( prefix + ":description", null ); } /** * Set the description of this resource in a specific language. * * @param language The language code. * @param description The description in a specific language. */ public void setDescription( String language, String description ) { setLanguageProperty( prefix + ":description", language, description ); } /** * Get the description in a specific language. * * @param language The language code to get the description for. * * @return The description in the specified language or null if it does not exist. */ public String getDescription( String language ) { return getLanguageProperty( prefix + ":description", language ); } /** * Get a list of all languages that a description exists for. * * @return A non-null list of languages, potentially an empty list. */ public List getDescriptionLanguages() { return getLanguagePropertyLanguages( prefix + ":description" ); } /** * Set the format property. * * @param format The mime-type of the saved resource. */ public void setFormat( String format ) { setTextProperty( prefix + ":format", format ); } /** * Get the format property. * * @return The mime-type of the resource. */ public String getFormat() { return getTextProperty( prefix + ":format" ); } /** * Set the resource identifier. * * @param id An id to the resource. */ public void setIdentifier( String id ) { setTextProperty( prefix + ":identifier", id ); } /** * Get the resource id. * * @return A key that identifies this resource. */ public String getIdentifier() { return getTextProperty( prefix + ":identifier" ); } /** * Remove a language from the list of languages. * * @param language The language to remove. */ public void removeLanguage( String language ) { removeBagValue( prefix + ":language", language ); } /** * Add a language to the list of languages. * * @param language The name of the language. */ public void addLanguage( String language ) { addBagValue( prefix + ":language", language ); } /** * Get the complete list of languages. * * @return The list of languages. */ public List getLanguages() { return getBagList( prefix + ":language" ); } /** * Remove a publisher from the list of publishers. * * @param publisher The publisher to remove. */ public void removePublisher( String publisher ) { removeBagValue( prefix + ":publisher", publisher ); } /** * Add a publisher to the list of publishers. * * @param publisher The name of the publisher. */ public void addPublisher( String publisher ) { addBagValue( prefix + ":publisher", publisher ); } /** * Get the complete list of publishers. * * @return The list of publishers. */ public List getPublishers() { return getBagList( prefix + ":publisher" ); } /** * Remove a relation from the list of relationships. * A relationship to another resource. * * @param relation The publisher to remove. */ public void removeRelation( String relation ) { removeBagValue( prefix + ":relation", relation ); } /** * Add a relation to the list of relationships. * A relationship to another resource. * * @param relation The relation to the other resource. */ public void addRelation( String relation ) { addBagValue( prefix + ":relation", relation ); } /** * Get the complete list of relationships. * * @return The list of relationships. */ public List getRelationships() { return getBagList( prefix + ":relation" ); } /** * Set the default value for the rights of this document. This property * specifies informal rights of the document. * * @param rights The rights for this resource. */ public void setRights( String rights ) { setLanguageProperty( prefix + ":rights", null, rights ); } /** * Get the default value for the rights of this document. * * @return The informal rights for this resource. */ public String getRights() { return getLanguageProperty( prefix + ":rights", null ); } /** * Set the rights for this resource in a specific language. * * @param language The language code. * @param rights The rights in a specific language. */ public void setRights( String language, String rights ) { setLanguageProperty( prefix + ":rights", language, rights ); } /** * Get the rights in a specific language. * * @param language The language code to get the description for. * * @return The rights in the specified language or null if it does not exist. */ public String getRights( String language ) { return getLanguageProperty( prefix + ":rights", language ); } /** * Get a list of all languages that a rights description exists for. * * @return A non-null list of languages, potentially an empty list. */ public List getRightsLanguages() { return getLanguagePropertyLanguages( prefix + ":rights" ); } /** * Set the resource source identifier. * * @param id An id to the resource source. */ public void setSource( String id ) { setTextProperty( prefix + ":source", id ); } /** * Get the resource source id. * * @return A key that identifies this source of this resource. */ public String getSource() { return getTextProperty( prefix + ":source" ); } /** * Remove a subject from the list of subjects. * * @param subject The subject to remove. */ public void removeSubject( String subject ) { removeBagValue( prefix + ":subject", subject ); } /** * Add a subject to the list of subjects. * * @param subject The subject of this resource. */ public void addSubject( String subject ) { addBagValue( prefix + ":subject", subject ); } /** * Get the complete list of subjects. * * @return The list of subjects. */ public List getSubjects() { return getBagList( prefix + ":subject" ); } /** * Set the default value for the title. * * @param title The title of this resource. */ public void setTitle( String title ) { setLanguageProperty( prefix + ":title", null, title ); } /** * Get the default value for the title. * * @return The title of this resource. */ public String getTitle() { return getLanguageProperty( prefix + ":title", null ); } /** * Set the title of this resource in a specific language. * * @param language The language code. * @param title The title in a specific language. */ public void setTitle( String language, String title ) { setLanguageProperty( prefix + ":title", language, title ); } /** * Get the title in a specific language. * * @param language The language code to get the description for. * * @return The title in the specified language or null if it does not exist. */ public String getTitle( String language ) { return getLanguageProperty( prefix + ":title", language ); } /** * Get a list of all languages that a title exists for. * * @return A non-null list of languages, potentially an empty list. */ public List getTitleLanguages() { return getLanguagePropertyLanguages( prefix + ":title" ); } /** * Add a type to the bag of types of this resource. * * @param type The type of resource to add (poem, novel). */ public void addType( String type ) { addBagValue(prefix + ":type", type ); } /** * Get the list of types for this resource. * * @return A list of types for this resource. */ public List getTypes() { return getBagList(prefix + ":type" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaPDF.java0000644000000000000000000000572612645757434025157 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.w3c.dom.Element; /** * Define XMP properties used with Adobe PDF documents. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class XMPSchemaPDF extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/pdf/1.3/"; /** * Construct a new blank PDF schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPDF( XMPMetadata parent ) { super( parent, "pdf", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaPDF( Element element, String prefix ) { super( element, prefix ); } /** * PDF Keywords. * * @param keywords The PDF keywords. */ public void setKeywords( String keywords ) { setTextProperty( prefix + ":Keywords", keywords ); } /** * Get the PDF keywords. * * @return The PDF keywords. */ public String getKeywords() { return getTextProperty( prefix + ":Keywords" ); } /** * Set the PDF file version. 1.2,1.3,... * * @param pdfVersion The version of the PDF file format. */ public void setPDFVersion( String pdfVersion ) { setTextProperty( prefix + ":PDFVersion", pdfVersion ); } /** * Get the PDF version. * * @return The value of the PDF version property. */ public String getPDFVersion() { return getTextProperty( prefix + ":PDFVersion" ); } /** * Set the PDF producer. * * @param producer The tool that created the PDF. */ public void setProducer( String producer ) { setTextProperty( prefix + ":Producer", producer ); } /** * Get the value of the producer property. * * @return The producer property. */ public String getProducer() { return getTextProperty( prefix + ":Producer" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaMediaManagement.java0000644000000000000000000001760012645757434027554 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.util.List; import org.apache.jempbox.impl.XMLUtil; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * Define XMP properties that are related to digital asset management. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class XMPSchemaMediaManagement extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/xap/1.0/mm/"; /** * Construct a new blank PDF schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaMediaManagement( XMPMetadata parent ) { super( parent, "xmpMM", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaMediaManagement( Element element, String prefix ) { super( element, prefix ); } /** * Get a reference to the original document that this document is * derived from. * * @return A reference to the derived document, or null if one does not exist. */ public ResourceRef getDerivedFrom() { ResourceRef retval = null; NodeList nodes = schema.getElementsByTagName( prefix + ":DerivedFrom" ); if( nodes.getLength() > 0 ) { Element derived = (Element)nodes.item( 0 ); retval = new ResourceRef(derived); } else { //the old name was RenditionOf, this is now deprecated but lets //try to find it in case of older XMP documents. NodeList deprecatedNodes = schema.getElementsByTagName( "xmpMM:RenditionOf" ); if( deprecatedNodes.getLength() > 0 ) { Element derived = (Element)deprecatedNodes.item( 0 ); retval = new ResourceRef(derived); } } return retval; } /** * Create a new Derived From resource ref that can be populated. You * will still need to call setDerivedFrom after this is created. * * @return A new blank derived from instance. */ public ResourceRef createDerivedFrom() { Element node = schema.getOwnerDocument().createElement( prefix + ":DerivedFrom" ); ResourceRef ref = new ResourceRef( node ); return ref; } /** * Set or clear the derived from value. * * @param resource The resource reference to set. * * @see XMPSchemaMediaManagement#createDerivedFrom() */ public void setDerivedFrom( ResourceRef resource ) { XMLUtil.setElementableValue( schema, prefix + ":DerivedFrom", resource ); } /** * Set the common identifier to all versions of this document. It should * be based on a UUID. * * @param id An identifier for the document. */ public void setDocumentID( String id ) { setTextProperty( prefix + ":DocumentID", id ); } /** * Get id that identifies all versions of this document. * * @return The document id. */ public String getDocumentID() { return getTextProperty( prefix + ":DocumentID" ); } /** * * @param id An identifier for the current version. */ public void setVersionID( String id ) { setTextProperty( prefix + ":VersionID", id ); } /** * * @return The current version id. */ public String getVersionID() { return getTextProperty( prefix + ":VersionID" ); } /** * Get a list of all historical events that have occured for this resource. * * @return A list of ResourceEvent objects or null. */ public List getHistory() { return getEventSequenceList( prefix + ":History" ); } /** * Remove an event from the list of events. * * @param event The event to remove. */ public void removeHistory( ResourceEvent event ) { removeSequenceValue( prefix + ":History", event ); } /** * Add a new historical event. * * @param event The event to add to the list of history. */ public void addHistory( ResourceEvent event ) { addSequenceValue( prefix + ":History", event ); } /** * Get a reference to the document prior to it being managed. * * @return A reference to the managed document. */ public ResourceRef getManagedFrom() { ResourceRef retval = null; NodeList nodes = schema.getElementsByTagName( prefix + ":ManagedFrom" ); if( nodes.getLength() > 0 ) { Element derived = (Element)nodes.item( 0 ); retval = new ResourceRef(derived); } return retval; } /** * Create a new Managed From resource ref that can be populated. You * will still need to call setManagedFrom after this is created. * * @return A new blank managed from instance. */ public ResourceRef createManagedFrom() { Element node = schema.getOwnerDocument().createElement( prefix + ":ManagedFrom" ); ResourceRef ref = new ResourceRef( node ); return ref; } /** * Set or clear the managed from value. * * @param resource The resource reference to set. * * @see XMPSchemaMediaManagement#createManagedFrom() */ public void setManagedFrom( ResourceRef resource ) { XMLUtil.setElementableValue( schema, prefix + ":ManagedFrom", resource ); } /** * Set the asset management system that manages this resource. * * @param manager The name of the asset management system. */ public void setManager( String manager ) { setTextProperty( prefix + ":Manager", manager ); } /** * Get the name of the asset management system that manages this resource. * * @return The name of the asset management system. */ public String getManager() { return getTextProperty( prefix + ":Manager" ); } /** * Set the URI identifying the managed resource. * * @param uri URI to the managed resource. */ public void setManageTo( String uri ) { setTextProperty( prefix + ":ManageTo", uri ); } /** * Get the URI to the managed resource. * * @return The managed resource URI. */ public String getManageTo() { return getTextProperty( prefix + ":ManageTo" ); } /** * Set the URI identifying information about the managed resource. * * @param uri URI to the managed resource info. */ public void setManageUI( String uri ) { setTextProperty( prefix + ":ManageUI", uri ); } /** * Get the URI to the managed resource information. * * @return The managed resource information URI. */ public String getManageUI() { return getTextProperty( prefix + ":ManageUI" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/package.html0000644000000000000000000000171512645757434024450 0ustar rootroot This package holds data access classes for XMP data structures. pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaBasic.java0000644000000000000000000002334412645757434025563 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.io.IOException; import java.util.Calendar; import java.util.List; import org.w3c.dom.Element; /** * Define XMP properties that are common to all schemas. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class XMPSchemaBasic extends XMPSchema { /** * The namespace of this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/xap/1.0/"; /** * Construct a new blank PDF schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaBasic( XMPMetadata parent ) { super( parent, "xmp", NAMESPACE ); schema.setAttributeNS( NS_NAMESPACE, "xmlns:xapGImg", "http://ns.adobe.com/xap/1.0/g/img/" ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaBasic( Element element, String prefix ) { super( element, prefix ); if( schema.getAttribute( "xmlns:xapGImg" ) == null ) { schema.setAttributeNS( NS_NAMESPACE, "xmlns:xapGImg", "http://ns.adobe.com/xap/1.0/g/img/" ); } } /** * Remove an Advisory xpath expression. * * @param advisory An xpath expression specifying properties that * were edited outside of the authoring application. */ public void removeAdvisory( String advisory ) { removeBagValue( prefix + ":Advisory", advisory ); } /** * Add an advisory to the list. * * @param advisory The new advisory xpath expression. */ public void addAdvisory( String advisory ) { addBagValue( prefix + ":Advisory", advisory ); } /** * Get the complete list of advisories. * * @return The list of advisories. */ public List getAdvisories() { return getBagList( prefix + ":Advisory" ); } /** * The base URL of the resource, for relative URLs in the document. * * @param url The base URL. */ public void setBaseURL( String url ) { setTextProperty( prefix + ":BaseURL", url ); } /** * Get the base URL of the resource. * * @return The base URL. */ public String getBaseURL() { return getTextProperty( prefix + ":BaseURL" ); } /** * Set the creation date of the resource. * * @param date The creation date of the resource. */ public void setCreateDate( Calendar date ) { setDateProperty( prefix + ":CreateDate", date ); } /** * Get the creation date of the resource. * * @return The creation date of the resource. * * @throws IOException If there is an error while converting this property to * a date. */ public Calendar getCreateDate() throws IOException { return getDateProperty( prefix + ":CreateDate" ); } /** * The creator tool for the resource. In the form of "vendor app version", ie * "Adobe Acrobat Distiller 5.0" * * @param creator The tool that was used to create the resource. */ public void setCreatorTool( String creator ) { setTextProperty( prefix + ":CreatorTool", creator ); } /** * Get the tool that created this resource, in the form of "vendor app version", ie * "Adobe Acrobat Distiller 5.0". * * @return The creator tool. */ public String getCreatorTool() { return getTextProperty( prefix + ":CreatorTool" ); } /** * Remove an identifier to this resource. * * @param id An identifier to this resource. */ public void removeIdentifier( String id ) { removeBagValue( prefix + ":Identifier", id ); } /** * Add a new identifier for this resource. * * @param id A new identifier for this resource. */ public void addIdentifier( String id ) { addBagValue( prefix + ":Identifier", id ); } /** * Get the complete list of identifiers. * * @return The list of identifiers. */ public List getIdentifiers() { return getBagList( prefix + ":Identifier" ); } /** * Set a short phrase that identifies this resource. * * @param label A short description of this resource. */ public void setLabel( String label ) { setTextProperty( prefix + ":Label", label ); } /** * Get the short phrase that describes this resource. * * @return The label for this resource. */ public String getLabel() { return getTextProperty( prefix + "p:Label" ); } /** * Set a Title for this resource. * * @param title A title denoting this resource */ public void setTitle( String title ) { setTextProperty( prefix + ":Title", title); } /** * Get the title for this resource. * * @return The titled denoting this resource. */ public String getTitle() { return getTextProperty( prefix + ":Title" ); } /** * Set the date that any metadata was updated. * * @param date The metadata change date for this resource. */ public void setMetadataDate( Calendar date ) { setDateProperty( prefix + ":MetadataDate", date ); } /** * Get the metadata change date for this resource. * * @return The metadata change date of the resource. * * @throws IOException If there is an error while converting this property to * a date. */ public Calendar getMetadataDate() throws IOException { return getDateProperty( prefix + ":MetadataDate" ); } /** * Set the date that the resource was last modified. * * @param date The modify date for this resource. */ public void setModifyDate( Calendar date ) { setDateProperty( prefix + ":ModifyDate", date ); } /** * Get the date the resource was last modified. * * @return The modify date of the resource. * * @throws IOException If there is an error while converting this property to * a date. */ public Calendar getModifyDate() throws IOException { return getDateProperty( prefix + ":ModifyDate" ); } /** * Set a short informal name for the resource. * * @param nickname A short name of this resource. */ public void setNickname( String nickname ) { setTextProperty( prefix + ":Nickname", nickname ); } /** * Get the short informal name for this resource. * * @return The short name for this resource. */ public String getNickname() { return getTextProperty( prefix + ":Nickname" ); } /** * Get a number that indicates the documents status. * * @return The rating of the document. */ public Integer getRating() { return getIntegerProperty( prefix + ":Rating" ); } /** * Set the document status. * * @param rating A number indicating status relative to other documents. */ public void setRating( Integer rating ) { setIntegerProperty( prefix + ":Rating", rating ); } /** * Set the default value for the thumbnail. * * @param thumbnail The thumbnail of this resource. */ public void setThumbnail( Thumbnail thumbnail ) { setThumbnailProperty( prefix + ":Thumbnails", null, thumbnail ); } /** * Get the default value for the thumbnail. * * @return The thumbnail of this resource. */ public Thumbnail getThumbnail() { return getThumbnailProperty( prefix + ":Thumbnails", null ); } /** * Set the thumbnail of this resource in a specific language. * * @param language The language code. * @param thumbnail The thumbnail in a specific language. */ public void setThumbnail( String language, Thumbnail thumbnail ) { setThumbnailProperty( prefix + ":Thumbnails", language, thumbnail ); } /** * Get the thumbnail in a specific language. * * @param language The language code to get the description for. * * @return The thumbnail in the specified language or null if it does not exist. */ public Thumbnail getThumbnail( String language ) { return getThumbnailProperty( prefix + ":Thumbnails", language ); } /** * Get a list of all languages that a thumbnail exists for. * * @return A non-null list of languages, potentially an empty list. */ public List getThumbnailLanguages() { return getLanguagePropertyLanguages( prefix + ":Thumbnails" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaDynamicMedia.java0000644000000000000000000000320012645757434027053 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.w3c.dom.Element; /** * Dynamic Media schema. * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.2 $ */ public class XMPSchemaDynamicMedia extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/xmp/1.0/DynamicMedia/"; /** * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaDynamicMedia( XMPMetadata parent ) { super( parent, "xmpDM", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaDynamicMedia( Element element, String prefix) { super( element , prefix); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/ResourceEvent.java0000644000000000000000000002133712645757434025625 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.io.IOException; import java.util.Calendar; import org.apache.jempbox.impl.DateConverter; import org.apache.jempbox.impl.XMLUtil; import org.w3c.dom.Element; /** * This class represents a high level event that occured during the processing * of this resource. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class ResourceEvent implements Elementable { /** * Namespace for a resource event. */ public static final String NAMESPACE = "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"; /** * A predefined action. */ public static final String ACTION_CONVERTED = "converted"; /** * A predefined action. */ public static final String ACTION_COPIED = "copied"; /** * A predefined action. */ public static final String ACTION_CREATED = "created"; /** * A predefined action. */ public static final String ACTION_CROPPED = "cropped"; /** * A predefined action. */ public static final String ACTION_EDITED = "edited"; /** * A predefined action. */ public static final String ACTION_FILTERED = "filtered"; /** * A predefined action. */ public static final String ACTION_FORMATTED = "formatted"; /** * A predefined action. */ public static final String ACTION_VERSION_UPDATED = "version_updated"; /** * A predefined action. */ public static final String ACTION_PRINTED = "printed"; /** * A predefined action. */ public static final String ACTION_PUBLISHED = "published"; /** * A predefined action. */ public static final String ACTION_MANAGED = "managed"; /** * A predefined action. */ public static final String ACTION_PRODUCED = "produced"; /** * A predefined action. */ public static final String ACTION_RESIZED = "resized"; /** * The DOM representation of this object. */ protected Element parent = null; /** * Create a resource reference based on a existing parent property set. * * @param parentElement The parent element that will store the resource properties. */ public ResourceEvent( Element parentElement ) { parent = parentElement; if( !parent.hasAttribute( "xmlns:stEvt" ) ) { parent.setAttributeNS( XMPSchema.NS_NAMESPACE, "xmlns:stEvt", NAMESPACE ); } } /** * Create resource event based on schema. * * @param schema The schema that this event will be part of. */ public ResourceEvent( XMPSchema schema ) { parent = schema.getElement().getOwnerDocument().createElement( "rdf:li" ); parent.setAttributeNS( XMPSchema.NS_NAMESPACE, "xmlns:stEvt", NAMESPACE ); } /** * Get the underlying XML element. * * @return The XML element that this object represents. */ public Element getElement() { return parent; } /** * Get the action that occured. See the ACTION_XXX constants. * * @return An action key, such as 'created' or 'printed'. */ public String getAction() { return XMLUtil.getStringValue( parent, "stEvt:action" ); } /** * Set the action that this event represents. See the ACTION_XXX constants. * * @param action The action that this event represents. */ public void setAction( String action ) { XMLUtil.setStringValue( parent, "stEvt:action", action ); } /** * Get the referenced resource's instance id. * * @return The id of the reference document instance. */ public String getInstanceID() { return XMLUtil.getStringValue( parent, "stEvt:instanceID" ); } /** * Set the referenced resource's document instance id. * * @param id The id of the reference document instance. */ public void setInstanceID( String id ) { XMLUtil.setStringValue( parent, "stEvt:instanceID", id ); } /** * Get an additional description of the event. * * @return Additional description of this event */ public String getParameters() { return XMLUtil.getStringValue( parent, "stEvt:parameters" ); } /** * Set some addition description to this event. * * @param param The additional action parameters. */ public void setParameters( String param ) { XMLUtil.setStringValue( parent, "stEvt:parameters", param ); } /** * Get the software that performed this action. * * @return The software that performed the action. */ public String getSoftwareAgent() { return XMLUtil.getStringValue( parent, "stEvt:softwareAgent" ); } /** * Set the software that performed this operation. * * @param software The name of the software that performed this action. */ public void setSoftwareAgent( String software ) { XMLUtil.setStringValue( parent, "stEvt:softwareAgent", software ); } /** * Get the date/time that this event occured. * * @return The date of the event. * * @throws IOException If there is an error creating the date. */ public Calendar getWhen() throws IOException { return DateConverter.toCalendar( XMLUtil.getStringValue( parent, "stEvt:when" ) ); } /** * Set when the event occured. * * @param when The date that the event occured. */ public void setWhen( Calendar when ) { XMLUtil.setStringValue( parent, "stEvt:when", DateConverter.toISO8601( when ) ); } /** * Get name of the asset management system that manages this resource. * * @return The name of a asset management system. */ public String getManager() { return XMLUtil.getStringValue( parent, "stRef:manager" ); } /** * Set the name of the system that manages this resource. * * @param manager The name of the management system. */ public void setMangager( String manager ) { XMLUtil.setStringValue( parent, "stRef:manager", manager ); } /** * Get name of the variant of asset management system that manages this resource. * * @return The name of a asset management system. */ public String getManagerVariant() { return XMLUtil.getStringValue( parent, "stRef:managerVariant" ); } /** * Set the name of the variant of the system that manages this resource. * * @param managerVariant The name of the management system. */ public void setMangagerVariant( String managerVariant ) { XMLUtil.setStringValue( parent, "stRef:managerVariant", managerVariant ); } /** * URI identifying the managed resource. * * @return The URI to resource. */ public String getManagerTo() { return XMLUtil.getStringValue( parent, "stRef:managerTo" ); } /** * Set the URI to the managed resource. * * @param managerTo The URI to the managed resource. */ public void setMangagerTo( String managerTo ) { XMLUtil.setStringValue( parent, "stRef:managerTo", managerTo ); } /** * URI to info about the managed resource. * * @return The URI to the resource info. */ public String getManagerUI() { return XMLUtil.getStringValue( parent, "stRef:managerUI" ); } /** * Set the URI to the info about the managed resource. * * @param managerUI The URI to the managed resource information. */ public void setMangagerUI( String managerUI ) { XMLUtil.setStringValue( parent, "stRef:managerUI", managerUI ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/Elementable.java0000644000000000000000000000227312645757434025247 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.w3c.dom.Element; /** * A simple class that allows access to an XML element. * * @author Ben Litchfield * @version $Revision: 1.1 $ */ public interface Elementable { /** * Get the XML element that this object represents. * * @return The xml element. */ public Element getElement(); }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/Thumbnail.java0000644000000000000000000000777512645757434024771 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.apache.jempbox.impl.XMLUtil; import org.w3c.dom.Element; /** * This class represents a thumbnail datatype. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class Thumbnail { /** * A supported thumnail format. */ public static final String FORMAT_JPEG = "JPEG"; /** * The DOM representation of this object. */ protected Element parent = null; /** * Create a new thumbnail element. * * @param metadata The metadata document that his thumbnail will be part of. */ public Thumbnail( XMPMetadata metadata ) { this( metadata.xmpDocument.createElement( "rdf:li" ) ); } /** * Create a thumnail based on a parent property set. * * @param parentElement The parent element that will store the thumbnail properties. */ public Thumbnail( Element parentElement ) { parent = parentElement; parent.setAttributeNS( XMPSchema.NS_NAMESPACE, "xmlns:xapGImg", "http://ns.adobe.com/xap/1.0/g/img/" ); } /** * Get the underlying XML element. * * @return The XML element that this object represents. */ public Element getElement() { return parent; } /** * Get the height of the image in pixels. * * @return The height of the image in pixels. */ public Integer getHeight() { return XMLUtil.getIntValue( parent, "xapGImg:height" ); } /** * Set the height of the element. * * @param height The updated height of the element. */ public void setHeight( Integer height ) { XMLUtil.setIntValue( parent, "xapGImg:height", height ); } /** * Get the width of the image in pixels. * * @return The width of the image in pixels. */ public Integer getWidth() { return XMLUtil.getIntValue( parent, "xapGImg:width" ); } /** * Set the width of the element. * * @param width The updated width of the element. */ public void setWidth( Integer width ) { XMLUtil.setIntValue( parent, "xapGImg:width", width ); } /** * Set the format of the thumbnail, currently only JPEG is supported. See FORMAT_XXX constants. * * @param format The image format. */ public void setFormat( String format ) { XMLUtil.setStringValue( parent, "xapGImg:format", format ); } /** * Get the format of the thumbnail. See FORMAT_XXX constants. * * @return The image format. */ public String getFormat() { return XMLUtil.getStringValue( parent, "xapGImg:format" ); } /** * Set the image data in base 64 encoding. * * @param image The image. */ public void setImage( String image ) { XMLUtil.setStringValue( parent, "xapGImg:image", image ); } /** * Get the image data in base 64 encoding. * * @return The image data. */ public String getImage() { return XMLUtil.getStringValue( parent, "xapGImg:image" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaPhotoshop.java0000644000000000000000000001706512645757434026530 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.util.List; import org.w3c.dom.Element; /** * Define XMP properties used with Adobe Photoshop documents. * * @author $Author: benlitchfield $ * @version $Revision: 1.2 $ */ public class XMPSchemaPhotoshop extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/photoshop/1.0/"; /** * Construct a new blank Photoshop schema. * * @param parent * The parent metadata schema that this will be part of. */ public XMPSchemaPhotoshop(XMPMetadata parent) { super(parent, "photoshop", NAMESPACE); } /** * Constructor for existing XML element. * * @param element The XML element. * @param aPrefix The XML prefix; photoshop. */ public XMPSchemaPhotoshop(Element element, String aPrefix) { super(element, aPrefix); } /** * By-line title. * * @param s The authors position. */ public void setAuthorsPosition( String s ) { setTextProperty(prefix + ":AuthorsPosition", s); } /** * By-line title. * * @return The authors position. */ public String getAuthorsPosition() { return getTextProperty(prefix + ":AuthorsPosition"); } /** * Writer/editor. * * @param s The caption writer. */ public void setCaptionWriter( String s ) { setTextProperty(prefix + ":CaptionWriter", s); } /** * Writer/editor. * * @return The caption writer. */ public String getCaptionWriter() { return getTextProperty(prefix + ":CaptionWriter"); } /** * Category; limited to 3 7-bit characters. * @param s The category. */ public void setCategory( String s ) { if( s != null && s.length() > 3 ) { throw new RuntimeException( "Error: photoshop:Category is limited to three characters value='" + s + "'" ); } setTextProperty(prefix + ":Category", s); } /** * The category. * * @return The category. */ public String getCategory() { return getTextProperty(prefix + ":Category"); } /** * The city. * * @param s The city. */ public void setCity( String s ) { setTextProperty(prefix + ":City", s); } /** * The city. * * @return The city. */ public String getCity() { return getTextProperty(prefix + ":City"); } /** * The country. * * @param s The country. */ public void setCountry( String s ) { setTextProperty(prefix + ":Country", s); } /** * The country. * * @return The country. */ public String getCountry() { return getTextProperty(prefix + ":Country"); } /** * Credit. * * @param s The credit property. */ public void setCredit( String s ) { setTextProperty(prefix + ":Credit", s); } /** * The credit property. * * @return The credit property. */ public String getCredit() { return getTextProperty(prefix + ":Credit"); } /** * Date created; creation date of the source document which may be * earlier than the digital representation. * * @param s The date created. */ public void setDateCreated( String s ) { setTextProperty(prefix + ":DateCreated", s); } /** * Creation date. * * @return The creation date. */ public String getDateCreated() { return getTextProperty(prefix + ":DateCreated"); } /** * The headline. * * @param s The headline. */ public void setHeadline( String s ) { setTextProperty(prefix + ":Headline", s); } /** * Headline. * * @return The headline. */ public String getHeadline() { return getTextProperty(prefix + ":Headline"); } /** * Instructions. * * @param s The instructions. */ public void setInstructions( String s ) { setTextProperty(prefix + ":Instructions", s); } /** * The instructions. * * @return The instructions. */ public String getInstructions() { return getTextProperty(prefix + ":Instructions"); } /** * The source. * * @param s The source. */ public void setSource( String s ) { setTextProperty(prefix + ":Source", s); } /** * The source. * * @return The source. */ public String getSource() { return getTextProperty(prefix + ":Source"); } /** * The state. * * @param s The state. */ public void setState( String s ) { setTextProperty(prefix + ":State", s); } /** * The state. * * @return The state. */ public String getState() { return getTextProperty(prefix + ":State"); } /** * Add a new supplemental category. * * @param s The supplemental category. */ public void addSupplementalCategory( String s ) { addBagValue(prefix + ":SupplementalCategories", s); } /** * Get a list of all supplemental categories. * * @return The supplemental categories. */ public List getSupplementalCategories() { return getBagList(prefix + ":SupplementalCategories"); } /** * Remove a supplemental category. * * @param s The supplemental category. */ public void removeSupplementalCategory( String s ) { removeBagValue(prefix + ":SupplementalCategories", s); } /** * The transmission reference. * * @param s The transmission reference. */ public void setTransmissionReference( String s ) { setTextProperty(prefix + ":TransmissionReference", s); } /** * The transmission reference. * * @return The transmission reference. */ public String getTransmissionReference() { return getTextProperty(prefix + ":TransmissionReference"); } /** * The urgency. * * @param s The urgency. */ public void setUrgency( Integer s ) { if( s != null ) { if( s.intValue() < 1 || s.intValue() > 8 ) { throw new RuntimeException( "Error: photoshop:Urgency must be between 1 and 8. value=" + s ); } } setIntegerProperty(prefix + ":Urgency", s); } /** * The urgency. * * @return The urgency. */ public Integer getUrgency() { return getIntegerProperty(prefix + ":Urgency"); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaBasicJobTicket.java0000644000000000000000000000322212645757434027353 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.w3c.dom.Element; /** * Implementation of Basic Job Ticket Schema. * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.2 $ */ public class XMPSchemaBasicJobTicket extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/xap/1.0/bj/"; /** * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaBasicJobTicket( XMPMetadata parent ) { super( parent, "xmpBJ", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaBasicJobTicket( Element element, String prefix ) { super( element , prefix); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchemaPagedText.java0000644000000000000000000000315312645757434026423 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import org.w3c.dom.Element; /** * Paged Text Schema. * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.2 $ */ public class XMPSchemaPagedText extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://ns.adobe.com/xap/1.0/t/pg/"; /** * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPagedText( XMPMetadata parent ) { super( parent, "xmpTPg", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The XML prefix. */ public XMPSchemaPagedText( Element element, String prefix ) { super( element , prefix); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/0000755000000000000000000000000012645757434023075 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/XMPSchemaPDFAId.java0000644000000000000000000000617512645757434026446 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp.pdfa; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.w3c.dom.Element; /** * Define XMP properties used PDFA extension schema description schemas. * TODO 2 naked so far, implement * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.1 $ */ public class XMPSchemaPDFAId extends XMPSchema { /** * The namespace for this schema. * This is the future amendment of the PDFA Spec with the trailing slash at end */ public static final String NAMESPACE = "http://www.aiim.org/pdfa/ns/id/"; /** * Construct a new blank PDFA schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPDFAId( XMPMetadata parent ) { super( parent, "pdfaid", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaPDFAId( Element element , String prefix) { super( element , prefix); } /** * Get the ISO19005 part number. * * @return The ISO 19005 part number. */ public Integer getPart() { return getIntegerProperty( prefix+":part" ); } /** * Set the ISO19005 part number. * * @param part The ISO 19005 part number. */ public void setPart( Integer part ) { setIntegerProperty( prefix+":part", part); } /** * Set the amendment idenitifier. * * @param amd The amendment idenitifier. */ public void setAmd( String amd ) { setTextProperty( prefix+":amd", amd); } /** * Get the amendment idenitifier. * * @return The amendment idenitifier. */ public String getAmd() { return getTextProperty( prefix+":amd" ); } /** * Set the conformance level. * * @param conformance The conformance level. */ public void setConformance( String conformance ) { setTextProperty( prefix+":conformance", conformance); } /** * Get the conformance level. * * @return The conformance level. */ public String getConformance() { return getTextProperty( prefix+":conformance" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/package.html0000644000000000000000000000172212645757434025360 0ustar rootroot This package holds data access classes for XMP PDFA data structures. pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/XMPMetadataPDFA.java0000644000000000000000000001310712645757434026502 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp.pdfa; import java.io.IOException; import org.apache.jempbox.impl.XMLUtil; import org.apache.jempbox.xmp.XMPMetadata; import org.w3c.dom.Document; import org.xml.sax.InputSource; /** * PDFA Metadata. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class XMPMetadataPDFA extends XMPMetadata { /** * Constructor. * * @throws IOException If there is an error creating this metadata. */ public XMPMetadataPDFA() throws IOException { super(); init(); } /** * Constructor. * * @param doc The XML document that maps to the metadata. */ public XMPMetadataPDFA(Document doc) { super(doc); init(); } private void init() { // PDFA specific schemas nsMappings.put( XMPSchemaPDFAField.NAMESPACE, XMPSchemaPDFAField.class ); nsMappings.put( XMPSchemaPDFAId.NAMESPACE, XMPSchemaPDFAId.class ); nsMappings.put( XMPSchemaPDFAProperty.NAMESPACE, XMPSchemaPDFAProperty.class ); nsMappings.put( XMPSchemaPDFASchema.NAMESPACE, XMPSchemaPDFASchema.class ); nsMappings.put( XMPSchemaPDFAType.NAMESPACE, XMPSchemaPDFAType.class ); } /** * Load a a PDFA metadata. * * @param is An XML input stream * @return A PDFA metadata. * @throws IOException If there is an error loading the XML document. */ public static XMPMetadata load( InputSource is ) throws IOException { return new XMPMetadataPDFA( XMLUtil.parse( is ) ); } /** * Get the PDFAField schema. * * @return A PDFAField schema. * * @throws IOException If there is an error finding the scheam. */ public XMPSchemaPDFAField getPDFAFieldSchema() throws IOException { return (XMPSchemaPDFAField) getSchemaByClass(XMPSchemaPDFAField.class); } /** * Add a new PDFAField schema. * * @return The newly added PDFA schema. */ public XMPSchemaPDFAField addPDFAFieldSchema() { XMPSchemaPDFAField schema = new XMPSchemaPDFAField(this); return (XMPSchemaPDFAField) basicAddSchema(schema); } /** * Get the PDFA ID schema. * @return The PDFA ID schema. * @throws IOException If there is an error accessing the PDFA id schema. */ public XMPSchemaPDFAId getPDFAIdSchema() throws IOException { return (XMPSchemaPDFAId) getSchemaByClass(XMPSchemaPDFAId.class); } /** * Add a PDFA Id schema and return the result. * * @return The newly created PDFA Id schema. */ public XMPSchemaPDFAId addPDFAIdSchema() { XMPSchemaPDFAId schema = new XMPSchemaPDFAId(this); return (XMPSchemaPDFAId) basicAddSchema(schema); } /** * Get the PDFA property schema. * * @return The PDFA property schema. * * @throws IOException If there is an error accessing the PDFA property schema. */ public XMPSchemaPDFAProperty getPDFAPropertySchema() throws IOException { return (XMPSchemaPDFAProperty) getSchemaByClass(XMPSchemaPDFAProperty.class); } /** * Create a PDFA property schema. * * @return The newly created property schema. */ public XMPSchemaPDFAProperty addPDFAPropertySchema() { XMPSchemaPDFAProperty schema = new XMPSchemaPDFAProperty(this); return (XMPSchemaPDFAProperty) basicAddSchema(schema); } /** * Get the PDFA schema. * * @return The PDFA schema. * * @throws IOException If there is an error getting the PDFA schema. */ public XMPSchemaPDFASchema getPDFASchema() throws IOException { return (XMPSchemaPDFASchema) getSchemaByClass(XMPSchemaPDFASchema.class); } /** * Add a PDFA schema. * * @return The newly created PDFA schema. */ public XMPSchemaPDFASchema addPDFASchema() { XMPSchemaPDFASchema schema = new XMPSchemaPDFASchema(this); return (XMPSchemaPDFASchema) basicAddSchema(schema); } /** * Get the PDFA type schema. * * @return The PDFA type schema. * * @throws IOException If there is an error accessing the PDFA type schema. */ public XMPSchemaPDFAType getPDFATypeSchema() throws IOException { return (XMPSchemaPDFAType) getSchemaByClass(XMPSchemaPDFAType.class); } /** * Add a new PDFA type schema. * * @return The newly created PDFA type schema. */ public XMPSchemaPDFAType addPDFATypeSchema() { XMPSchemaPDFAType schema = new XMPSchemaPDFAType(this); return (XMPSchemaPDFAType) basicAddSchema(schema); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/XMPSchemaPDFAField.java0000644000000000000000000000351512645757434027130 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp.pdfa; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.w3c.dom.Element; /** * Define XMP properties used PDFA extension schema description schemas. * TODO 2 naked so far, implement * * @author Karsten Krieg (kkrieg@intarsys.de) * * @version $Revision: 1.1 $ */ public class XMPSchemaPDFAField extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://www.aiim.org/pdfa/ns/field"; /** * Construct a new blank PDFA schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPDFAField( XMPMetadata parent ) { super( parent, "pdfaField", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaPDFAField( Element element , String prefix) { super( element , prefix); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/XMPSchemaPDFAType.java0000644000000000000000000000350412645757434027024 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp.pdfa; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.w3c.dom.Element; /** * Define XMP properties used PDFA extension schema description schemas. * TODO 2 naked so far, implement * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.1 $ */ public class XMPSchemaPDFAType extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://www.aiim.org/pdfa/ns/type"; /** * Construct a new blank PDFA schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPDFAType( XMPMetadata parent ) { super( parent, "pdfaType", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaPDFAType( Element element, String prefix ) { super( element , prefix); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/XMPSchemaPDFASchema.java0000644000000000000000000000517012645757434027304 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp.pdfa; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.w3c.dom.Element; /** * Define XMP properties used PDFA extension schema description schemas. * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.1 $ */ public class XMPSchemaPDFASchema extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://www.aiim.org/pdfa/ns/schema"; /** * Construct a new blank PDFA schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPDFASchema( XMPMetadata parent ) { super( parent, "pdfaSchema", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaPDFASchema( Element element, String prefix ) { super( element , prefix); } /** * PDFA schema. * * @param schema The optional description of schema. */ public void setSchema( String schema ) { setTextProperty( "pdfaSchema:schema", schema); } /** * Get the PDFA schema. * * @return The optional description of schema. */ public String getSchema() { return getTextProperty( "pdfaSchema:schema" ); } /** * PDFA Schema prefix. * * @param prefix Preferred schema namespace prefix. */ public void setPrefix( String prefix) { setTextProperty( "pdfaSchema:prefix", prefix); } /** * Get the PDFA Schema prefix. * * @return Preferred schema namespace prefix. */ public String getPrefix() { return getTextProperty( "pdfaSchema:prefix" ); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/pdfa/XMPSchemaPDFAProperty.java0000644000000000000000000000353012645757434027726 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp.pdfa; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.w3c.dom.Element; /** * Define XMP properties used PDFA extension schema description schemas. * TODO 2 naked so far, implement * * @author Karsten Krieg (kkrieg@intarsys.de) * @version $Revision: 1.1 $ */ public class XMPSchemaPDFAProperty extends XMPSchema { /** * The namespace for this schema. */ public static final String NAMESPACE = "http://www.aiim.org/pdfa/ns/property"; /** * Construct a new blank PDFA schema. * * @param parent The parent metadata schema that this will be part of. */ public XMPSchemaPDFAProperty( XMPMetadata parent ) { super( parent, "pdfaProperty", NAMESPACE ); } /** * Constructor from existing XML element. * * @param element The existing element. * @param prefix The schema prefix. */ public XMPSchemaPDFAProperty( Element element , String prefix) { super( element , prefix); } }pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/xmp/XMPMetadata.java0000644000000000000000000005722112645757434025142 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.xml.transform.TransformerException; import org.apache.jempbox.impl.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.xml.sax.InputSource; /** * This class represents the top level XMP data structure and gives access to * the various schemas that are available as part of the XMP specification. * * @author Ben Litchfield * @version $Revision: 1.10 $ */ public class XMPMetadata { /** * Supported encoding for persisted XML. */ public static final String ENCODING_UTF8 = "UTF-8"; /** * Supported encoding for persisted XML. */ public static final String ENCODING_UTF16BE = "UTF-16BE"; /** * Supported encoding for persisted XML. */ public static final String ENCODING_UTF16LE = "UTF-16LE"; /** * The DOM representation of the metadata. */ protected Document xmpDocument; /** * The encoding of the XMP document. Default is UTF8. */ protected String encoding = ENCODING_UTF8; /** * A mapping of namespaces. */ protected Map> nsMappings = new HashMap>(); /** * Default constructor, creates blank XMP doc. * * @throws IOException * If there is an error creating the initial document. */ public XMPMetadata() throws IOException { xmpDocument = XMLUtil.newDocument(); ProcessingInstruction beginXPacket = xmpDocument .createProcessingInstruction("xpacket", "begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\""); xmpDocument.appendChild(beginXPacket); Element xmpMeta = xmpDocument.createElementNS("adobe:ns:meta/", "x:xmpmeta"); xmpMeta.setAttributeNS(XMPSchema.NS_NAMESPACE, "xmlns:x", "adobe:ns:meta/"); xmpDocument.appendChild(xmpMeta); Element rdf = xmpDocument.createElement("rdf:RDF"); rdf.setAttributeNS(XMPSchema.NS_NAMESPACE, "xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); xmpMeta.appendChild(rdf); ProcessingInstruction endXPacket = xmpDocument .createProcessingInstruction("xpacket", "end=\"w\""); xmpDocument.appendChild(endXPacket); init(); } /** * Constructor from an existing XML document. * * @param doc * The root XMP document. */ public XMPMetadata(Document doc) { xmpDocument = doc; init(); } private void init() { nsMappings.put(XMPSchemaPDF.NAMESPACE, XMPSchemaPDF.class); nsMappings.put(XMPSchemaBasic.NAMESPACE, XMPSchemaBasic.class); nsMappings .put(XMPSchemaDublinCore.NAMESPACE, XMPSchemaDublinCore.class); nsMappings.put(XMPSchemaMediaManagement.NAMESPACE, XMPSchemaMediaManagement.class); nsMappings.put(XMPSchemaRightsManagement.NAMESPACE, XMPSchemaRightsManagement.class); nsMappings.put(XMPSchemaBasicJobTicket.NAMESPACE, XMPSchemaBasicJobTicket.class); nsMappings.put(XMPSchemaDynamicMedia.NAMESPACE, XMPSchemaDynamicMedia.class); nsMappings.put(XMPSchemaPagedText.NAMESPACE, XMPSchemaPagedText.class); nsMappings.put(XMPSchemaIptc4xmpCore.NAMESPACE, XMPSchemaIptc4xmpCore.class); nsMappings.put(XMPSchemaPhotoshop.NAMESPACE, XMPSchemaPhotoshop.class); } /** * Will add a XMPSchema to the set of identified schemas. * * The class needs to have a constructor with parameter Element * * @param namespace * The namespace URI of the schmema for instance * http://purl.org/dc/elements/1.1/. * @param xmpSchema * The schema to associated this identifier with. */ public void addXMLNSMapping(String namespace, Class xmpSchema) { if (!(XMPSchema.class.isAssignableFrom(xmpSchema))) { throw new IllegalArgumentException( "Only XMPSchemas can be mapped to."); } nsMappings.put(namespace, xmpSchema); } /** * Get the PDF Schema. * * @return The first PDF schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaPDF getPDFSchema() throws IOException { return (XMPSchemaPDF) getSchemaByClass(XMPSchemaPDF.class); } /** * Get the Basic Schema. * * @return The first Basic schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaBasic getBasicSchema() throws IOException { return (XMPSchemaBasic) getSchemaByClass(XMPSchemaBasic.class); } /** * Get the Dublin Core Schema. * * @return The first Dublin schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaDublinCore getDublinCoreSchema() throws IOException { return (XMPSchemaDublinCore) getSchemaByClass(XMPSchemaDublinCore.class); } /** * Get the Media Management Schema. * * @return The first Media Management schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaMediaManagement getMediaManagementSchema() throws IOException { return (XMPSchemaMediaManagement) getSchemaByClass(XMPSchemaMediaManagement.class); } /** * Get the Schema Rights Schema. * * @return The first Schema Rights schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaRightsManagement getRightsManagementSchema() throws IOException { return (XMPSchemaRightsManagement) getSchemaByClass(XMPSchemaRightsManagement.class); } /** * Get the Job Ticket Schema. * * @return The first Job Ticket schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaBasicJobTicket getBasicJobTicketSchema() throws IOException { return (XMPSchemaBasicJobTicket) getSchemaByClass(XMPSchemaBasicJobTicket.class); } /** * Get the Dynamic Media Schema. * * @return The first Dynamic Media schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaDynamicMedia getDynamicMediaSchema() throws IOException { return (XMPSchemaDynamicMedia) getSchemaByClass(XMPSchemaDynamicMedia.class); } /** * Get the Paged Text Schema. * * @return The first Paged Text schema in the list. * * @throws IOException * If there is an error accessing the schema. */ public XMPSchemaPagedText getPagedTextSchema() throws IOException { return (XMPSchemaPagedText) getSchemaByClass(XMPSchemaPagedText.class); } /** * Add a new Media Management schema. * * @return The newly added schema. */ public XMPSchemaMediaManagement addMediaManagementSchema() { XMPSchemaMediaManagement schema = new XMPSchemaMediaManagement(this); return (XMPSchemaMediaManagement) basicAddSchema(schema); } /** * Add a new Rights Managment schema. * * @return The newly added schema. */ public XMPSchemaRightsManagement addRightsManagementSchema() { XMPSchemaRightsManagement schema = new XMPSchemaRightsManagement(this); return (XMPSchemaRightsManagement) basicAddSchema(schema); } /** * Add a new Job Ticket schema. * * @return The newly added schema. */ public XMPSchemaBasicJobTicket addBasicJobTicketSchema() { XMPSchemaBasicJobTicket schema = new XMPSchemaBasicJobTicket(this); return (XMPSchemaBasicJobTicket) basicAddSchema(schema); } /** * Add a new Dynamic Media schema. * * @return The newly added schema. */ public XMPSchemaDynamicMedia addDynamicMediaSchema() { XMPSchemaDynamicMedia schema = new XMPSchemaDynamicMedia(this); return (XMPSchemaDynamicMedia) basicAddSchema(schema); } /** * Add a new Paged Text schema. * * @return The newly added schema. */ public XMPSchemaPagedText addPagedTextSchema() { XMPSchemaPagedText schema = new XMPSchemaPagedText(this); return (XMPSchemaPagedText) basicAddSchema(schema); } /** * Add a custom schema to the root rdf. The schema has to have been created * as a child of this XMPMetadata. * * @param schema * The schema to add. */ public void addSchema(XMPSchema schema) { Element rdf = getRDFElement(); rdf.appendChild(schema.getElement()); } /** * Save the XMP document to a file. * * @param file * The file to save the XMP document to. * * @throws Exception * If there is an error while writing to the stream. */ public void save(String file) throws Exception { XMLUtil.save(xmpDocument, file, encoding); } /** * Save the XMP document to a stream. * * @param outStream * The stream to save the XMP document to. * * @throws TransformerException * If there is an error while writing to the stream. */ public void save(OutputStream outStream) throws TransformerException { XMLUtil.save(xmpDocument, outStream, encoding); } /** * Get the XML document as a byte array. * * @return The metadata as an XML byte stream. * @throws Exception * If there is an error creating the stream. */ public byte[] asByteArray() throws Exception { return XMLUtil.asByteArray(xmpDocument, encoding); } /** * Get the XML document from this object. * * @return This object as an XML document. */ public Document getXMPDocument() { return xmpDocument; } /** * Generic add schema method. * * @param schema * The schema to add. * * @return The newly added schema. */ protected XMPSchema basicAddSchema(XMPSchema schema) { Element rdf = getRDFElement(); rdf.appendChild(schema.getElement()); return schema; } /** * Create and add a new PDF Schema to this metadata. Typically a XMP * document will only have one PDF schema (but multiple are supported) so it * is recommended that you first check the existence of a PDF scheme by * using getPDFSchema() * * @return A new blank PDF schema that is now part of the metadata. */ public XMPSchemaPDF addPDFSchema() { XMPSchemaPDF schema = new XMPSchemaPDF(this); return (XMPSchemaPDF) basicAddSchema(schema); } /** * Create and add a new Dublin Core Schema to this metadata. Typically a XMP * document will only have one schema for each type (but multiple are * supported) so it is recommended that you first check the existence of a * this scheme by using getDublinCoreSchema() * * @return A new blank PDF schema that is now part of the metadata. */ public XMPSchemaDublinCore addDublinCoreSchema() { XMPSchemaDublinCore schema = new XMPSchemaDublinCore(this); return (XMPSchemaDublinCore) basicAddSchema(schema); } /** * Create and add a new Basic Schema to this metadata. Typically a XMP * document will only have one schema for each type (but multiple are * supported) so it is recommended that you first check the existence of a * this scheme by using getDublinCoreSchema() * * @return A new blank PDF schema that is now part of the metadata. */ public XMPSchemaBasic addBasicSchema() { XMPSchemaBasic schema = new XMPSchemaBasic(this); return (XMPSchemaBasic) basicAddSchema(schema); } /** * Create and add a new IPTC schema to this metadata. * * @return A new blank IPTC schema that is now part of the metadata. */ public XMPSchemaIptc4xmpCore addIptc4xmpCoreSchema() { XMPSchemaIptc4xmpCore schema = new XMPSchemaIptc4xmpCore(this); return (XMPSchemaIptc4xmpCore) basicAddSchema(schema); } /** * Create and add a new Photoshop schema to this metadata. * * @return A new blank Photoshop schema that is now part of the metadata. */ public XMPSchemaPhotoshop addPhotoshopSchema() { XMPSchemaPhotoshop schema = new XMPSchemaPhotoshop(this); return (XMPSchemaPhotoshop) basicAddSchema(schema); } /** * The encoding used to write the XML. Default value:UTF-8
See the * ENCODING_XXX constants * * @param xmlEncoding * The encoding to write the XML as. */ public void setEncoding(String xmlEncoding) { encoding = xmlEncoding; } /** * Get the current encoding that will be used to write the XML. * * @return The current encoding to write the XML to. */ public String getEncoding() { return encoding; } /** * Get the root RDF element. * * @return The root RDF element. */ private Element getRDFElement() { Element rdf = null; NodeList nodes = xmpDocument.getElementsByTagName("rdf:RDF"); if (nodes.getLength() > 0) { rdf = (Element) nodes.item(0); } return rdf; } /** * Load metadata from the filesystem. * * @param file * The file to load the metadata from. * * @return The loaded XMP document. * * @throws IOException * If there is an error reading the data. */ public static XMPMetadata load(String file) throws IOException { return new XMPMetadata(XMLUtil.parse(file)); } /** * Load a schema from an input source. * * @param is * The input source to load the schema from. * * @return The loaded/parsed schema. * * @throws IOException * If there was an error while loading the schema. */ public static XMPMetadata load(InputSource is) throws IOException { return new XMPMetadata(XMLUtil.parse(is)); } /** * Load metadata from the filesystem. * * @param is * The stream to load the data from. * * @return The loaded XMP document. * * @throws IOException * If there is an error reading the data. */ public static XMPMetadata load(InputStream is) throws IOException { return new XMPMetadata(XMLUtil.parse(is)); } /** * Test main program. * * @param args * The command line arguments. * @throws Exception * If there is an error. */ public static void main(String[] args) throws Exception { XMPMetadata metadata = new XMPMetadata(); XMPSchemaPDF pdf = metadata.addPDFSchema(); pdf.setAbout("uuid:b8659d3a-369e-11d9-b951-000393c97fd8"); pdf.setKeywords("ben,bob,pdf"); pdf.setPDFVersion("1.3"); pdf.setProducer("Acrobat Distiller 6.0.1 for Macintosh"); XMPSchemaDublinCore dc = metadata.addDublinCoreSchema(); dc.addContributor("Ben Litchfield"); dc.addContributor("Solar Eclipse"); dc.addContributor("Some Other Guy"); XMPSchemaBasic basic = metadata.addBasicSchema(); Thumbnail t = new Thumbnail(metadata); t.setFormat(Thumbnail.FORMAT_JPEG); t.setImage("IMAGE_DATA"); t.setHeight(new Integer(100)); t.setWidth(new Integer(200)); basic.setThumbnail(t); basic.setBaseURL("http://www.pdfbox.org/"); List schemas = metadata.getSchemas(); System.out.println("schemas=" + schemas); metadata.save("test.xmp"); } /** * This will get a list of XMPSchema(or subclass) objects. * * @return A non null read-only list of schemas that are part of this * metadata. * * @throws IOException * If there is an error creating a specific schema. */ public List getSchemas() throws IOException { NodeList schemaList = xmpDocument .getElementsByTagName("rdf:Description"); List retval = new ArrayList(schemaList.getLength()); for (int i = 0; i < schemaList.getLength(); i++) { Element schema = (Element) schemaList.item(i); boolean found = false; NamedNodeMap attributes = schema.getAttributes(); for (int j = 0; j < attributes.getLength(); j++) { Node attribute = attributes.item(j); String name = attribute.getNodeName(); String value = attribute.getNodeValue(); if (name.startsWith("xmlns:") && nsMappings.containsKey(value)) { Class schemaClass = nsMappings.get(value); try { Constructor ctor = schemaClass .getConstructor(new Class[] { Element.class, String.class }); retval.add((XMPSchema)ctor.newInstance(new Object[] { schema, name.substring(6) })); found = true; } catch(NoSuchMethodException e) { throw new IOException( "Error: Class " + schemaClass.getName() + " must have a constructor with the signature of " + schemaClass.getName() + "( org.w3c.dom.Element, java.lang.String )"); } catch(Exception e) { e.printStackTrace(); throw new IOException(e.getMessage()); } } } if (!found) { retval.add(new XMPSchema(schema, null)); } } return retval; } /** * Will return all schemas that fit the given namespaceURI. Which is only * done by using the namespace mapping (nsMapping) and not by actually * checking the xmlns property. * * @param namespaceURI * The namespaceURI to filter for. * @return A list containing the found schemas or an empty list if non are * found or the namespaceURI could not be found in the namespace * mapping. * @throws IOException * If an operation on the document fails. */ public List getSchemasByNamespaceURI(String namespaceURI) throws IOException { List result = new LinkedList(); Class schemaClass = nsMappings.get(namespaceURI); if (schemaClass == null) { return result; } Iterator i = getSchemas().iterator(); while (i.hasNext()) { XMPSchema schema = i.next(); if (schemaClass.isAssignableFrom(schema.getClass())) { result.add(schema); } } return result; } /** * This will return true if the XMP contains an unknown schema. * * @return True if an unknown schema is found, false otherwise * * @throws IOException * If there is an error */ public boolean hasUnknownSchema() throws IOException { NodeList schemaList = xmpDocument .getElementsByTagName("rdf:Description"); for (int i = 0; i < schemaList.getLength(); i++) { Element schema = (Element) schemaList.item(i); NamedNodeMap attributes = schema.getAttributes(); for (int j = 0; j < attributes.getLength(); j++) { Node attribute = attributes.item(j); String name = attribute.getNodeName(); String value = attribute.getNodeValue(); if (name.startsWith("xmlns:") && !nsMappings.containsKey(value) && !value.equals(ResourceEvent.NAMESPACE)) { return true; } } } return false; } /** * Tries to retrieve a schema from this by classname. * * @param targetSchema * Class for targetSchema. * * @return XMPSchema or null if no target is found. * * @throws IOException * if there was an error creating the schemas of this. */ public XMPSchema getSchemaByClass(Class targetSchema) throws IOException { Iterator iter = getSchemas().iterator(); while (iter.hasNext()) { XMPSchema element = (XMPSchema) iter.next(); if (element.getClass().getName().equals(targetSchema.getName())) { return element; } } // not found return null; } /** * Merge this metadata with the given metadata object. * * @param metadata The metadata to merge with this document. * * @throws IOException If there is an error merging the data. */ public void merge(XMPMetadata metadata) throws IOException { List schemas2 = metadata.getSchemas(); for (Iterator iterator = schemas2.iterator(); iterator.hasNext();) { XMPSchema schema2 = iterator.next(); XMPSchema schema1 = getSchemaByClass(schema2.getClass()); if (schema1 == null) { Element rdf = getRDFElement(); rdf.appendChild(xmpDocument.importNode(schema2.getElement(), true)); } else { schema1.merge(schema2); } } } } pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/impl/0000755000000000000000000000000012645757434022320 5ustar rootrootpdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/impl/XMLUtil.java0000644000000000000000000003403612645757434024467 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.impl; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.io.StringWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.jempbox.xmp.Elementable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.InputSource; /** * This class with handle some simple XML operations. * * @author Ben Litchfield * @author Christopher Oezbek * * @version $Revision: 1.4 $ */ public class XMLUtil { /** * Utility class, should not be instantiated. * */ private XMLUtil() { } /** * This will parse an XML stream and create a DOM document. * * @param is The stream to get the XML from. * @return The DOM document. * @throws IOException It there is an error creating the dom. */ public static Document parse( InputStream is ) throws IOException { try { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); // prevents validation messages polluting the console builder.setErrorHandler(null); return builder.parse( is ); } catch( Exception e ) { IOException thrown = new IOException( e.getMessage() ); throw thrown; } } /** * This will parse an InputSource and create a DOM document. * * @param is The stream to get the XML from. * @return The DOM document. * @throws IOException It there is an error creating the dom. */ public static Document parse( InputSource is ) throws IOException { try { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); // prevents validation messages polluting the console builder.setErrorHandler(null); return builder.parse( is ); } catch( Exception e ) { IOException thrown = new IOException( e.getMessage() ); throw thrown; } } /** * This will parse an XML stream and create a DOM document. * * @param fileName The file to get the XML from. * @return The DOM document. * @throws IOException It there is an error creating the dom. */ public static Document parse( String fileName ) throws IOException { try { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); // prevents validation messages polluting the console builder.setErrorHandler(null); return builder.parse( fileName ); } catch( Exception e ) { IOException thrown = new IOException( e.getMessage() ); throw thrown; } } /** * Create a new blank XML document. * * @return The new blank XML document. * * @throws IOException If there is an error creating the XML document. */ public static Document newDocument() throws IOException { try { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); return builder.newDocument(); } catch( Exception e ) { IOException thrown = new IOException( e.getMessage() ); throw thrown; } } /** * Get the first instance of an element by name. * * @param parent The parent to get the element from. * @param elementName The name of the element to look for. * @return The element or null if it is not found. */ public static Element getElement( Element parent, String elementName ) { Element retval = null; NodeList children = parent.getElementsByTagName( elementName ); if( children.getLength() > 0 ) { retval = (Element)children.item( 0 ); } return retval; } /** * Get the integer value of a subnode. * * @param parent The parent element that holds the values. * @param nodeName The name of the node that holds the integer value. * * @return The integer value of the node. */ public static Integer getIntValue( Element parent, String nodeName ) { String intVal = XMLUtil.getStringValue( XMLUtil.getElement( parent, nodeName ) ); Integer retval = null; if( intVal != null ) { retval = new Integer( intVal ); } return retval; } /** * Set the integer value of an element. * * @param parent The parent element that will hold this subelement. * @param nodeName The name of the subelement. * @param intValue The value to set. */ public static void setIntValue( Element parent, String nodeName, Integer intValue ) { Element currentValue = getElement( parent, nodeName ); if( intValue == null ) { if( currentValue != null ) { parent.removeChild( currentValue ); } else { //it doesn't exist so we don't need to remove it. } } else { if( currentValue == null ) { currentValue = parent.getOwnerDocument().createElement( nodeName ); parent.appendChild( currentValue ); } XMLUtil.setStringValue( currentValue, intValue.toString() ); } } /** * Get the value of a subnode. * * @param parent The parent element that holds the values. * @param nodeName The name of the node that holds the value. * * @return The value of the sub node. */ public static String getStringValue( Element parent, String nodeName ) { return XMLUtil.getStringValue( XMLUtil.getElement( parent, nodeName ) ); } /** * Set the value of an element. * * @param parent The parent element that will hold this subelement. * @param nodeName The name of the subelement. * @param nodeValue The value to set. */ public static void setStringValue( Element parent, String nodeName, String nodeValue ) { Element currentValue = getElement( parent, nodeName ); if( nodeValue == null ) { if( currentValue != null ) { parent.removeChild( currentValue ); } else { //it doesn't exist so we don't need to remove it. } } else { if( currentValue == null ) { currentValue = parent.getOwnerDocument().createElement( nodeName ); parent.appendChild( currentValue ); } XMLUtil.setStringValue( currentValue, nodeValue ); } } /** * This will get the text value of an element. * * @param node The node to get the text value for. * @return The text of the node. */ public static String getStringValue( Element node ) { String retval = ""; NodeList children = node.getChildNodes(); for( int i=0; i The impl package contains internal implementation classes for JempBox. pdfbox-1.8.11/jempbox/src/main/java/org/apache/jempbox/impl/DateConverter.java0000644000000000000000000002311612645757434025733 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.impl; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.SimpleTimeZone; /** * This class is used to convert dates to strings and back using the PDF * date standards. Date are described in PDFReference1.4 section 3.8.2 * * @author Ben Litchfield * @author Christopher Oezbek * * @version $Revision: 1.6 $ */ public class DateConverter { //The Date format is supposed to be the PDF_DATE_FORMAT, but not all PDF documents //will use that date, so I have added a couple other potential formats //to try if the original one does not work. private static final SimpleDateFormat[] POTENTIAL_FORMATS = new SimpleDateFormat[] { new SimpleDateFormat("EEEE, dd MMM yyyy hh:mm:ss a"), new SimpleDateFormat("EEEE, MMM dd, yyyy hh:mm:ss a"), new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"), new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"), new SimpleDateFormat("MM/dd/yyyy hh:mm:ss"), new SimpleDateFormat("MM/dd/yyyy"), new SimpleDateFormat("EEEE, MMM dd, yyyy"), // Acrobat Distiller 1.0.2 for Macintosh new SimpleDateFormat("EEEE MMM dd, yyyy HH:mm:ss"), // ECMP5 new SimpleDateFormat("EEEE MMM dd HH:mm:ss z yyyy"), // GNU Ghostscript 7.0.7 new SimpleDateFormat("EEEE, MMM dd, yyyy 'at' hh:mma") // Acrobat Net Distiller 1.0 for Windows }; private DateConverter() { //utility class should not be constructed. } /** * This will convert a string to a calendar. * * @param date The string representation of the calendar. * * @return The calendar that this string represents. * * @throws IOException If the date string is not in the correct format. */ public static Calendar toCalendar( String date ) throws IOException { Calendar retval = null; if( date != null && date.trim().length() > 0 ) { //these are the default values int year = 0; int month = 1; int day = 1; int hour = 0; int minute = 0; int second = 0; //first string off the prefix if it exists try { SimpleTimeZone zone = null; if( date.startsWith( "D:" ) ) { date = date.substring( 2, date.length() ); } date = date.replaceAll("[-:T]", ""); if( date.length() < 4 ) { throw new IOException( "Error: Invalid date format '" + date + "'" ); } year = Integer.parseInt( date.substring( 0, 4 ) ); if( date.length() >= 6 ) { month = Integer.parseInt( date.substring( 4, 6 ) ); } if( date.length() >= 8 ) { day = Integer.parseInt( date.substring( 6, 8 ) ); } if( date.length() >= 10 ) { hour = Integer.parseInt( date.substring( 8, 10 ) ); } if( date.length() >= 12 ) { minute = Integer.parseInt( date.substring( 10, 12 ) ); } if( date.length() >= 14 ) { second = Integer.parseInt( date.substring( 12, 14 ) ); } if( date.length() >= 15 ) { char sign = date.charAt( 14 ); if( sign == 'Z' ) { zone = new SimpleTimeZone(0,"Unknown"); } else { int hours = 0; int minutes = 0; if( date.length() >= 17 ) { if( sign == '+' ) { //parseInt cannot handle the + sign hours = Integer.parseInt( date.substring( 15, 17 ) ); } else { hours = -Integer.parseInt( date.substring( 14, 16 ) ); } } if( sign=='+' ) { if( date.length() >= 19 ) { minutes = Integer.parseInt( date.substring( 17, 19 ) ); } } else { if( date.length() >= 18 ) { minutes = Integer.parseInt( date.substring( 16, 18 ) ); } } zone = new SimpleTimeZone( hours*60*60*1000 + minutes*60*1000, "Unknown" ); } } if( zone == null ) { retval = new GregorianCalendar(); } else { retval = new GregorianCalendar( zone ); } retval.clear(); retval.set( year, month-1, day, hour, minute, second ); } catch( NumberFormatException e ) { // remove the arbitrary : in the timezone. SimpleDateFormat // can't handle it if (date.substring(date.length()-3,date.length()-2).equals(":") && (date.substring(date.length()-6,date.length()-5).equals("+") || date.substring(date.length()-6,date.length()-5).equals("-"))) { //thats a timezone string, remove the : date = date.substring(0,date.length()-3) + date.substring(date.length()-2); } for( int i=0; retval == null && i\n" + " " + ">" + " " + " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">" + " The Mona Lisa\n" + " A painting by ...\n" + " \n" + " \n" + "
"; XMPMetadata xmp = XMPMetadata.load(new InputSource(new StringReader(xmpmeta))); XMPSchemaDublinCore dc = xmp.getDublinCoreSchema(); assertEquals("The Mona Lisa", dc.getTitle()); assertEquals("A painting by ...", dc.getDescription()); } public void testExiv2Xmp() throws IOException { // XMP block as created by exiv2 String xmpmeta = "\n" + " \n" + " \n" + " \n" + " \n" + " Dublin Core description\n" + " \n" + " \n" + " \n" + " \n" + ""; XMPMetadata xmp = XMPMetadata.load(new InputSource(new StringReader(xmpmeta))); assertEquals("Dublin Core description", xmp.getDublinCoreSchema().getDescription()); } public void testDescriptionFromNodeText() throws IOException { // From a jpeg, valid according to http://www.w3.org/RDF/Validator/ String xmpmeta = "\n" + " \n" + " \n" + " exif\n" + " \n" + " \n" + " Dublin Core description\n" + " \n" + " \n" + ""; XMPMetadata xmp = XMPMetadata.load(new InputSource(new StringReader(xmpmeta))); assertEquals("Dublin Core description", xmp.getDublinCoreSchema().getDescription()); } } pdfbox-1.8.11/jempbox/src/test/java/org/apache/jempbox/xmp/package.html0000644000000000000000000000171212645757434024500 0ustar rootroot This package contains tests for the org.jempbox.xmp package. pdfbox-1.8.11/jempbox/src/test/java/org/apache/jempbox/xmp/XMPSchemaTest.java0000644000000000000000000003031112645757434025504 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import java.io.IOException; import java.util.Calendar; import java.util.List; import java.util.TimeZone; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import junit.framework.TestCase; import org.apache.jempbox.impl.DateConverter; import org.apache.jempbox.xmp.XMPMetadata; import org.apache.jempbox.xmp.XMPSchema; import org.w3c.dom.Element; /** * Tests for the XMPSchema class. * * @author $Author: benlitchfield $ * @version $Revision: 1.2 $ ($Date: 2007/02/28 02:30:30 $) * */ public class XMPSchemaTest extends TestCase { /** * Check whether the schema correctly sets the rdf:Description element. * * @throws IOException Signals an error with the XMP processing. * @throws ParserConfigurationException Signals an error with the XMP processing. */ public void testRDFDescription() throws IOException, ParserConfigurationException { // Check constructor using an element XMPMetadata xmp = new XMPMetadata(); XMPSchema basic = new XMPSchema(xmp, "test", "http://test.com/test"); assertNotNull(basic.getElement()); assertEquals("rdf:Description", basic.getElement().getTagName()); // Then Check using the Document Builder Factory DocumentBuilderFactory builderFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Element e = builder.newDocument().createElement("rdf:Description"); XMPSchema schema = new XMPSchema(e, "test"); assertEquals(e, schema.getElement()); assertEquals("rdf:Description", schema.getElement().getTagName()); } /** * Test that text properties are correctly handeled. * * @throws IOException Signals an error with the XMP processing. */ public void testTextProperty() throws IOException { XMPMetadata xmp = new XMPMetadata(); XMPSchema schema = new XMPSchema(xmp, "test", "http://test.com/test"); schema.setTextProperty("test:title", "The advanced Flux-Compensation for Delawney-Separation"); Element e = schema.getElement(); assertEquals("The advanced Flux-Compensation for Delawney-Separation", e.getAttribute("test:title")); assertEquals("The advanced Flux-Compensation for Delawney-Separation", schema.getTextProperty("test:title")); schema.setTextProperty("test:title", "Bacon's Dictum and Healey's Heaven"); e = schema.getElement(); assertEquals("Bacon's Dictum and Healey's Heaven", e .getAttribute("test:title")); assertEquals("Bacon's Dictum and Healey's Heaven", schema .getTextProperty("test:title")); schema .setTextProperty( "test:abstract", " The abstract\n can go \n \n on several" + " \n lines with \n many \n\n empty ones in \n between."); assertEquals( " The abstract\n can go \n \n on several" + " \n lines with \n many \n\n empty ones in \n between.", schema.getTextProperty("test:abstract")); } /** * Test that integer properties are correctly handled. * * @throws IOException Signals an error with the XMP processing. */ public void testIntegerProperty() throws IOException { XMPMetadata xmp = new XMPMetadata(); XMPSchema schema = new XMPSchema(xmp, "test", "http://test.com/test"); schema.setIntegerProperty("test:intvalue", new Integer(14)); Element e = schema.getElement(); assertEquals("14", e.getAttribute("test:intvalue")); assertEquals(new Integer(14),schema.getIntegerProperty("test:intvalue")); schema.setIntegerProperty("test:intvalue",new Integer(16)); e = schema.getElement(); assertEquals("16", e.getAttribute("test:intvalue")); assertEquals(new Integer(16), schema.getIntegerProperty("test:intvalue")); } /** * Check bag properties. * * @throws IOException Signals an error with the XMP processing. */ public void testBags() throws IOException { XMPMetadata xmp = new XMPMetadata(); XMPSchema schema = new XMPSchema(xmp, "test", "http://test.com/test"); schema.addBagValue("author", "Tom DeMarco"); schema.addBagValue("author", "Kent Beck"); { List l = schema.getBagList("author"); assertEquals(2, l.size()); assertTrue(l.get(0).equals("Tom DeMarco") || l.get(1).equals("Tom DeMarco")); assertTrue(l.get(0).equals("Kent Beck") || l.get(1).equals("Kent Beck")); } { schema.removeBagValue("author", "Kent Beck"); List l = schema.getBagList("author"); assertEquals(1, l.size()); assertTrue(l.get(0).equals("Tom DeMarco")); } { // Already removed schema.removeBagValue("author", "Kent Beck"); List l = schema.getBagList("author"); assertEquals(1, l.size()); assertTrue(l.get(0).equals("Tom DeMarco")); } { // Duplicates allowed! schema.addBagValue("author", "Tom DeMarco"); List l = schema.getBagList("author"); assertEquals(2, l.size()); assertTrue(l.get(0).equals("Tom DeMarco")); assertTrue(l.get(1).equals("Tom DeMarco")); } { // Removes both schema.removeBagValue("author", "Tom DeMarco"); List l = schema.getBagList("author"); assertEquals(0, l.size()); } } /** * Test adding and removing from a sequence list. * * @throws IOException Signals an error with the XMP processing. */ public void testSeqList() throws IOException { XMPMetadata xmp = new XMPMetadata(); XMPSchema schema = new XMPSchema(xmp, "test", "http://test.com/test"); schema.addSequenceValue("author", "Tom DeMarco"); schema.addSequenceValue("author", "Kent Beck"); { List l = schema.getSequenceList("author"); assertEquals(2, l.size()); assertEquals("Tom DeMarco", l.get(0)); assertEquals("Kent Beck", l.get(1)); } { schema.removeSequenceValue("author", "Tom DeMarco"); List l = schema.getSequenceList("author"); assertEquals(1, l.size()); assertTrue(l.get(0).equals("Kent Beck")); } { // Already removed schema.removeSequenceValue("author", "Tom DeMarco"); List l = schema.getSequenceList("author"); assertEquals(1, l.size()); assertTrue(l.get(0).equals("Kent Beck")); } { // Duplicates allowed! schema.addSequenceValue("author", "Kent Beck"); List l = schema.getSequenceList("author"); assertEquals(2, l.size()); assertTrue(l.get(0).equals("Kent Beck")); assertTrue(l.get(1).equals("Kent Beck")); } { // Remvoes all schema.removeSequenceValue("author", "Kent Beck"); List l = schema.getSequenceList("author"); assertEquals(0, l.size()); } } /** * Compares two dates. * * @param expected The expected date. * @param actual The actual date. */ public void assertEquals(Calendar expected, Calendar actual) { assertEquals(expected.get(Calendar.YEAR), actual.get(Calendar.YEAR)); assertEquals(expected.get(Calendar.MONTH), actual.get(Calendar.MONTH)); assertEquals(expected.get(Calendar.DAY_OF_MONTH), actual.get(Calendar.DAY_OF_MONTH)); assertEquals(expected.get(Calendar.HOUR), actual.get(Calendar.HOUR)); assertEquals(expected.get(Calendar.MINUTE), actual.get(Calendar.MINUTE)); assertEquals(expected.get(Calendar.SECOND), actual.get(Calendar.SECOND)); assertEquals(expected.get(Calendar.ZONE_OFFSET) + expected.get( Calendar.DST_OFFSET ), actual.get(Calendar.ZONE_OFFSET) + actual.get( Calendar.DST_OFFSET )); assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis()); } /** * Test ISO-8601 date conversion. * * @throws IOException If the conversion did not work as expected. */ public void testDateConversionNegativeTimeZone() throws IOException { Calendar c1 = Calendar.getInstance(); c1.setTimeZone( TimeZone.getTimeZone("GMT-5")); c1.set(Calendar.MILLISECOND, 0); String convertedDate = DateConverter.toISO8601(c1); Calendar converted = DateConverter.toCalendar( convertedDate ); assertEquals( c1, converted); } /** * Test ISO-8601 date conversion. * * @throws IOException If the conversion did not work as expected. */ public void testDateConversionPositiveTimeZone() throws IOException { Calendar c1 = Calendar.getInstance( TimeZone.getTimeZone("Australia/Sydney ") ); c1.clear(); c1.set(2007, 1, 27, 13, 12, 15); String convertedDate = DateConverter.toISO8601(c1); Calendar converted = DateConverter.toCalendar( convertedDate ); assertEquals( c1, converted); } /** * Tests adding and removing from a date list. * * @throws IOException Signals an error with the XMP processing. */ public void testDateList() throws IOException { XMPMetadata xmp = new XMPMetadata(); XMPSchema schema = new XMPSchema(xmp, "test", "http://test.com/test"); Calendar c1 = Calendar.getInstance(); c1.set(1999, 11, 31, 0, 0, 0); c1.set(Calendar.MILLISECOND, 0); Calendar c2 = Calendar.getInstance(); c2.set(2000, 11, 31, 0, 0, 0); c2.set(Calendar.MILLISECOND, 0); // System.out.println( DateConverter.toISO8601(c1)); schema.addSequenceDateValue("test:importantDates", c1); schema.addSequenceDateValue("test:importantDates", c2); List l = schema.getSequenceDateList("test:importantDates"); assertEquals(2, l.size()); assertEquals(c1, (Calendar) l.get(0)); assertEquals(c2, (Calendar) l.get(1)); schema.removeSequenceDateValue("test:importantDates", c1); l = schema.getSequenceDateList("test:importantDates"); assertEquals(1, l.size()); assertEquals(c2, (Calendar) l.get(0)); // Already removed schema.removeSequenceDateValue("test:importantDates", c1); l = schema.getSequenceDateList("test:importantDates"); assertEquals(1, l.size()); assertEquals(c2, (Calendar) l.get(0)); // Duplicates Allowed schema.addSequenceDateValue("test:importantDates", c2); l = schema.getSequenceDateList("test:importantDates"); assertEquals(2, l.size()); assertEquals(c2, (Calendar) l.get(0)); assertEquals(c2, (Calendar) l.get(1)); // Remvoes all schema.removeSequenceDateValue("test:importantDates", c2); l = schema.getSequenceDateList("test:importantDates"); assertEquals(0, l.size()); } } pdfbox-1.8.11/jempbox/src/test/java/org/apache/jempbox/xmp/AllTests.java0000644000000000000000000000305012645757434024612 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jempbox.xmp; import junit.framework.Test; import junit.framework.TestSuite; /** * Suite for all tests in test.jempbox.xmp. * * @author $Author: coezbek $ * @version $Revision: 1.1 $ ($Date: 2006/12/30 17:27:46 $) * */ public class AllTests { /** * Hide constructor. */ protected AllTests() { } /** * Method returns a test representing all tests in the package * test.jempbox.xmp. * * @return The test representing all tests in the current package. */ public static Test suite() { TestSuite suite = new TestSuite("Test for test.jempbox.xmp"); // $JUnit-BEGIN$ suite.addTestSuite(XMPSchemaTest.class); // $JUnit-END$ return suite; } } pdfbox-1.8.11/jempbox/jempbox-checkstyle.xml0000644000000000000000000001640312645757434017575 0ustar rootroot pdfbox-1.8.11/jempbox/pom.xml0000644000000000000000000000372412645757434014572 0ustar rootroot 4.0.0 org.apache.pdfbox pdfbox-parent 1.8.11 ../parent/pom.xml jempbox bundle Apache JempBox The Apache JempBox library is an open source Java tool that implements Adobe's XMP(TM) specification. JempBox is a subproject of Apache PDFBox. 2008 junit junit 4.8.1 test org.apache.felix maven-bundle-plugin true pdfbox-1.8.11/jempbox/README.txt0000644000000000000000000000330012645757434014741 0ustar rootroot==================================================== Apache JempBox ==================================================== The Apache JempBox library is an open source Java tool for working with XMP metadata. You need Java 5 (or higher) and Maven 2 to build JempBox. The recommended build command is: mvn clean install The default build will compile the Java sources and package the binary classes into a jar package. See the Maven documentation for all the other available build options. See the issue tracker at https://issues.apache.org/jira/browse/PDFBOX (component JempBox) for the full list of known issues and requested features. JempBox is a subproject of Apache PDFBox. PDFBox is a project of the Apache Software Foundation. License (see also LICENSE.txt) ============================== Collective work: Copyright 2014 The Apache Software Foundation. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pdfbox-1.8.11/jempbox/eclipse-formatter.xml0000644000000000000000000006612412645757434017427 0ustar rootroot pdfbox-1.8.11/pdfbox/0000755000000000000000000000000012645757666013074 5ustar rootrootpdfbox-1.8.11/pdfbox/src/0000755000000000000000000000000012645757432013652 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/0000755000000000000000000000000012645757432014576 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/0000755000000000000000000000000012645757432016610 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/org/0000755000000000000000000000000012645757432017377 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/org/apache/0000755000000000000000000000000012645757432020620 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/0000755000000000000000000000000012645757432022102 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/0000755000000000000000000000000012645757434024116 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/FontMapping.properties0000644000000000000000000000252312645757432030456 0ustar rootroot# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This file contains well known font substitutions. # If a needed font isn't embedded in the pdf and not available in the running environment # it will be substituted with an other suitable font, if available # # # These are some well known mappings for some frequently used fonts # Arial=Helvetica Arial,Bold=Helvetica,Bold Arial,Italic=Helvetica,Italic Arial,Bold,Italic=Helvetica,Bold,Italic SymbolMT=Symbol ArialMT=Arial ArialMT,Bold=Arial,Bold ArialMT,Italic=Arial,Italic ArialMT,Bold,Italic=Arial,Bold,Italic TimesNewRomanPSMT=Verdana TimesNewRomanPSMT,Bold=Verdana,Bold pdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/PageDrawer.properties0000644000000000000000000001225412645757432030257 0ustar rootroot# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # this Table is a correspondance Map of the PDF stream operators with concretes class of the # OperatorProcessor abstract class for the stategy pattern used in the # org.apache.pdfbox.util.PDFStreamEngine class. # To change the behaviour of the system, remplace the class name by a new class name. b=org.apache.pdfbox.util.operator.pagedrawer.CloseFillNonZeroAndStrokePath B=org.apache.pdfbox.util.operator.pagedrawer.FillNonZeroAndStrokePath b*=org.apache.pdfbox.util.operator.pagedrawer.CloseFillEvenOddAndStrokePath B*=org.apache.pdfbox.util.operator.pagedrawer.FillEvenOddAndStrokePath #BDC org.apache.pdfbox.util.operator.NotImplemented ##Begin Marked Content -- section 10.5 BI=org.apache.pdfbox.util.operator.pagedrawer.BeginInlineImage #BMC org.apache.pdfbox.util.operator.NotImplemented ##Begin Marked Content -- section 10.5 BT=org.apache.pdfbox.util.operator.BeginText #BX org.apache.pdfbox.util.operator.NotImplemented c=org.apache.pdfbox.util.operator.pagedrawer.CurveTo cm=org.apache.pdfbox.util.operator.Concatenate CS=org.apache.pdfbox.util.operator.SetStrokingColorSpace cs=org.apache.pdfbox.util.operator.SetNonStrokingColorSpace d=org.apache.pdfbox.util.operator.pagedrawer.SetLineDashPattern #d0 org.apache.pdfbox.util.operator.NotImplemented #d1 org.apache.pdfbox.util.operator.NotImplemented Do=org.apache.pdfbox.util.operator.pagedrawer.Invoke #DP org.apache.pdfbox.util.operator.NotImplemented ##Marked Content Point-- section 10.5 #El org.apache.pdfbox.util.operator.NotImplemented #EMC org.apache.pdfbox.util.operator.NotImplemented ##End Marked Content -- section 10.5 ET=org.apache.pdfbox.util.operator.EndText #EX org.apache.pdfbox.util.operator.NotImplemented f=org.apache.pdfbox.util.operator.pagedrawer.FillNonZeroRule F=org.apache.pdfbox.util.operator.pagedrawer.FillNonZeroRule f*=org.apache.pdfbox.util.operator.pagedrawer.FillEvenOddRule G=org.apache.pdfbox.util.operator.SetStrokingGrayColor g=org.apache.pdfbox.util.operator.SetNonStrokingGrayColor gs=org.apache.pdfbox.util.operator.SetGraphicsStateParameters h=org.apache.pdfbox.util.operator.pagedrawer.ClosePath #i org.apache.pdfbox.util.operator.NotImplemented #ID org.apache.pdfbox.util.operator.NotImplemented j=org.apache.pdfbox.util.operator.pagedrawer.SetLineJoinStyle J=org.apache.pdfbox.util.operator.pagedrawer.SetLineCapStyle K=org.apache.pdfbox.util.operator.SetStrokingCMYKColor k=org.apache.pdfbox.util.operator.SetNonStrokingCMYKColor l=org.apache.pdfbox.util.operator.pagedrawer.LineTo m=org.apache.pdfbox.util.operator.pagedrawer.MoveTo M=org.apache.pdfbox.util.operator.pagedrawer.SetLineMiterLimit #MP org.apache.pdfbox.util.operator.NotImplemented ##Marked Content Point-- section 10.5 n=org.apache.pdfbox.util.operator.pagedrawer.EndPath q=org.apache.pdfbox.util.operator.GSave Q=org.apache.pdfbox.util.operator.GRestore re=org.apache.pdfbox.util.operator.pagedrawer.AppendRectangleToPath RG=org.apache.pdfbox.util.operator.SetStrokingRGBColor rg=org.apache.pdfbox.util.operator.SetNonStrokingRGBColor #ri org.apache.pdfbox.util.operator.NotImplemented s=org.apache.pdfbox.util.operator.CloseAndStrokePath S=org.apache.pdfbox.util.operator.pagedrawer.StrokePath SC=org.apache.pdfbox.util.operator.SetStrokingColor sc=org.apache.pdfbox.util.operator.SetNonStrokingColor SCN=org.apache.pdfbox.util.operator.SetStrokingColor scn=org.apache.pdfbox.util.operator.SetNonStrokingColor sh=org.apache.pdfbox.util.operator.pagedrawer.SHFill T*=org.apache.pdfbox.util.operator.NextLine Tc=org.apache.pdfbox.util.operator.SetCharSpacing Td=org.apache.pdfbox.util.operator.MoveText TD=org.apache.pdfbox.util.operator.MoveTextSetLeading Tf=org.apache.pdfbox.util.operator.SetTextFont Tj=org.apache.pdfbox.util.operator.ShowText TJ=org.apache.pdfbox.util.operator.ShowTextGlyph TL=org.apache.pdfbox.util.operator.SetTextLeading Tm=org.apache.pdfbox.util.operator.SetMatrix Tr=org.apache.pdfbox.util.operator.SetTextRenderingMode Ts=org.apache.pdfbox.util.operator.SetTextRise Tw=org.apache.pdfbox.util.operator.SetWordSpacing Tz=org.apache.pdfbox.util.operator.SetHorizontalTextScaling v=org.apache.pdfbox.util.operator.pagedrawer.CurveToReplicateInitialPoint w=org.apache.pdfbox.util.operator.pagedrawer.SetLineWidth W org.apache.pdfbox.util.operator.pagedrawer.ClipNonZeroRule W* org.apache.pdfbox.util.operator.pagedrawer.ClipEvenOddRule y=org.apache.pdfbox.util.operator.pagedrawer.CurveToReplicateFinalPoint \'=org.apache.pdfbox.util.operator.MoveAndShow \"=org.apache.pdfbox.util.operator.SetMoveAndShow pdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/PDFTextStripper.properties0000644000000000000000000000463012645757432031244 0ustar rootroot# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This table is maps PDF stream operators to concrete OperatorProcessor # subclasses that are used by the PDFStreamEngine class to interpret the # PDF document. The classes configured here allow the PDFTextStripper # subclass of PDFStreamEngine to extract text content of the document. BT = org.apache.pdfbox.util.operator.BeginText cm = org.apache.pdfbox.util.operator.Concatenate Do = org.apache.pdfbox.util.operator.Invoke ET = org.apache.pdfbox.util.operator.EndText gs = org.apache.pdfbox.util.operator.SetGraphicsStateParameters q = org.apache.pdfbox.util.operator.GSave Q = org.apache.pdfbox.util.operator.GRestore T* = org.apache.pdfbox.util.operator.NextLine Tc = org.apache.pdfbox.util.operator.SetCharSpacing Td = org.apache.pdfbox.util.operator.MoveText TD = org.apache.pdfbox.util.operator.MoveTextSetLeading Tf = org.apache.pdfbox.util.operator.SetTextFont Tj = org.apache.pdfbox.util.operator.ShowText TJ = org.apache.pdfbox.util.operator.ShowTextGlyph TL = org.apache.pdfbox.util.operator.SetTextLeading Tm = org.apache.pdfbox.util.operator.SetMatrix Tr = org.apache.pdfbox.util.operator.SetTextRenderingMode Ts = org.apache.pdfbox.util.operator.SetTextRise Tw = org.apache.pdfbox.util.operator.SetWordSpacing Tz = org.apache.pdfbox.util.operator.SetHorizontalTextScaling w = org.apache.pdfbox.util.operator.SetLineWidth \' = org.apache.pdfbox.util.operator.MoveAndShow \" = org.apache.pdfbox.util.operator.SetMoveAndShow # The following operators are not relevant to text extraction, # so we can silently ignore them. b B b* B* BDC BI BMC BX c CS cs d d0 d1 DP El EMC EX f F f* G g h i ID j J K k l m M MP n re RG rg ri s S SC sc SCN scn sh v W W* y pdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/additional_glyphlist.txt0000644000000000000000000000673312645757432031075 0ustar rootroot# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Format: Semicolon-delimited fields: # (1) glyph name # (2) Unicode scalar value # # These mappings are missing in the original copy of the adobe glyphlist.txt # angbracketleft;3008 angbracketright;3009 circlecopyrt;00A9 controlNULL;0000 # # TeX-related mappings using named values # angbracketleftbig;2329 angbracketleftBig;2329 angbracketleftbigg;2329 angbracketleftBigg;2329 angbracketrightBig;232A angbracketrightbig;232A angbracketrightBigg;232A angbracketrightbigg;232A arrowhookleft;21AA arrowhookright;21A9 arrowlefttophalf;21BC arrowleftbothalf;21BD arrownortheast;2197 arrownorthwest;2196 arrowrighttophalf;21C0 arrowrightbothalf;21C1 arrowsoutheast;2198 arrowsouthwest;2199 backslashbig;2216 backslashBig;2216 backslashBigg;2216 backslashbigg;2216 bardbl;2016 bracehtipdownleft;FE37 bracehtipdownright;FE37 bracehtipupleft;FE38 bracehtipupright;FE38 braceleftBig;007B braceleftbig;007B braceleftbigg;007B braceleftBigg;007B bracerightBig;007D bracerightbig;007D bracerightbigg;007D bracerightBigg;007D bracketleftbig;005B bracketleftBig;005B bracketleftbigg;005B bracketleftBigg;005B bracketrightBig;005D bracketrightbig;005D bracketrightbigg;005D bracketrightBigg;005D ceilingleftbig;2308 ceilingleftBig;2308 ceilingleftBigg;2308 ceilingleftbigg;2308 ceilingrightbig;2309 ceilingrightBig;2309 ceilingrightbigg;2309 ceilingrightBigg;2309 circledotdisplay;2299 circledottext;2299 circlemultiplydisplay;2297 circlemultiplytext;2297 circleplusdisplay;2295 circleplustext;2295 contintegraldisplay;222E contintegraltext;222E coproductdisplay;2210 coproducttext;2210 floorleftBig;230A floorleftbig;230A floorleftbigg;230A floorleftBigg;230A floorrightbig;230B floorrightBig;230B floorrightBigg;230B floorrightbigg;230B hatwide;0302 hatwider;0302 hatwidest;0302 intercal;1D40 integraldisplay;222B integraltext;222B intersectiondisplay;22C2 intersectiontext;22C2 logicalanddisplay;2227 logicalandtext;2227 logicalordisplay;2228 logicalortext;2228 parenleftBig;0028 parenleftbig;0028 parenleftBigg;0028 parenleftbigg;0028 parenrightBig;0029 parenrightbig;0029 parenrightBigg;0029 parenrightbigg;0029 prime;2032 productdisplay;220F producttext;220F radicalbig;221A radicalBig;221A radicalBigg;221A radicalbigg;221A radicalbt;221A radicaltp;221A radicalvertex;221A slashbig;002F slashBig;002F slashBigg;002F slashbigg;002F summationdisplay;2211 summationtext;2211 tildewide;02DC tildewider;02DC tildewidest;02DC uniondisplay;22C3 unionmultidisplay;228E unionmultitext;228E unionsqdisplay;2294 unionsqtext;2294 uniontext;22C3 vextenddouble;2225 vextendsingle;2223 # # TeX-related mappings using hexadecimal or decimal values # x1b;FB00 x1c;FB01 x1d;FB02 x1e;FB03 x8a;0141 xff;00DF a27;FB00 a28;FB01 a29;FB02 a30;FB03 a138;0141 a255;00DFpdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/pdfbox.properties0000644000000000000000000000146012645757432027515 0ustar rootroot# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. pdfbox.version=${project.version} pdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/ttf/0000755000000000000000000000000012645757432024711 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/resources/org/apache/pdfbox/resources/ttf/ArialMT.ttf0000644000000000000000000020061412645757432026724 0ustar rootrootOS/2_cpVPCLTъ^6cmaplXcvt 9fpgm&`gaspH glyf tA&~hdmx4!Hhead݄T6hheaEoL$hmtx Ǝ0kernRՙ-loca=maxpG:, nameټȵpostZ/prep; h::_:: dM0l   p t  &   Y &  &   c . 5 `  s 0 & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5fqu-J3T99NR7s`s3VV9s3D{o{RoHT3fs +b-{T#\q#H99`#fy```{w``b{{Rffw;{J/}oo5jo{-{T7fD)fs@%2%%A:B2SAS//2ݖ}ٻ֊A}G}G͖2ƅ%]%]@@%d%d%A2dA  d   A(]%]@%..%A  %d%@~}}~}}|d{T{%zyxw v utsrqponl!kjBjSih}gBfedcba:`^ ][ZYX YX WW2VUTUBTSSRQJQP ONMNMLKJKJIJI IH GFEDC-CBAK@?>=>=<=<; <@; :987876765 65 43 21 21 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $#"!! d d BBBdB-B}d       -d@--d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-ff@ /10!%!!fsr)5 @@ <2991/0K TX @ 878Y P ]%3#3#5qeM@1<20KTKT[X@878Y@0 @ P ` p ]#!#o$++`@1      91/<<<<<<<2220@   ]!! !3!!!!#!#!5!!5!T%Dh$ig8R>hggh`TifaabbNm!(/@U" '&( /)/))/B" ) *!#*- ) " & 0<<<1/299990KSX99Y"K TX0@00878YK TKT[KT[X000@878Y#.'5.546753.'>54&dijfod]SS\dtzq{---@A$*.U# jXV`OnZXhq) #'3@6$%&%&'$'B .$ &($4'!%   ! + 1 49912<0KSXY"K TK T[K T[KT[KT[K T[X4@44878Y"32654&'2#"&546"32654&%3#2#"&546WccWUccUVcbWWcd1Zܻۻa ۻۼ 0@      !         B  (('+'$ .  .'.'!!199999991/9990KSX99999999Y"2]@ " ) **&:4D ^YZ UZZY0g{ "-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z 2229]]3267 >73#'#"5467.54632.#"[UԠ_I{;B h]hΆ02޸SUWDi;#QX?@Yr~YW׀c?}<$$/1oX3goB@ 10KTKT[X@878Y@ @P`p]#o+{ O@  29910KTX@878YKTX@878Y#&547{>;o @ <99103#654<:=JN@,       <2<2991<22990%#'%%73%g:r:g:PrPbybcy #@   <<1/<<0!!#!5!-Ө-Ӫ--@ 1073#ӤR@d10!!d1/073#B-@B/9910KSXY"3#m #@  10"32'2#"  P3343ssyzZ K@B  1/20KSXY"KTX  @878Y]7!5%3!!JeJsHHժJ@'B   91/20KSX9Y"KTKT[KT[X@878Y@2UVVzzvtvust]]%!!567>54&#"5>32Ls3aM_xzXE[w:mIwBC12\ps({@.    #)&  )99190KTKT[X)@))878Y@ daa d!]!"&'532654&+532654&#"5>32?^jTmǹSrsY %Đ%%12wps{$& Ѳ|d @   B    <291/<290KSXY"K TK T[X@878Y@* *HYiw+&+6NO O Vfuz ]] !33##!55^%3`du@#    190KTKT[X@878YKTX@878Y!!>32!"&'532654&#",X,$^hZkʭQTժ 10$& $X@$  "% " !%190@]]"32654&.#">32# !2 LL;kPL;y$&W]ybhc@B991/0KSXY"KTX@878Y@X9Hg]]!#!3V+ #/C@% '-'0 $*$ !0991990"32654&%&&54632#"$54632654&#"HŚV г "Əُattt$X@# %!"" %190@]]7532#"543 !"&2654&#"LK:lL>$& V\s[#@<21/073#3### %@  <2103#3#ӤR#٬@^M@*B$#29190KSXY" 5Ѧ`@ #<210!!!!^O@+B$#<9190KSXY"55//m$p@+$     &%99991/9990K TX%@%%878Yy z z ]%3##546?>54&#"5>32ſ8ZZ93lOa^gHZX/'eVY5^1YnFC98ŸLVV/5<4q L@2  L4307$7CM34( (+(I+*(I,=M<9912990K TK T[KT[KT[KT[XMMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32|{zy!orqp ˘s'6@   0210].# !267# !2'ffjzSb_^^_HHghG.@   2 99991/0`]3 !%! )5BhPa/w.,~ .@   21/0 ]!!!!!!9>ժF# )@ 21/0 ]!!!!#ZpPժH7s9@ 43 1990%!5!# !2&&# !26uu^opkSUmnHF_`%; ,@ 8  221/<20P ]3!3#!#"d+991/0KTX@878Y@ 0@P`]3#+f M@  9 991990KTX  @878Y@ 0 @ P ` ]3+53265M?nj @(B  291/<290KSXY"]@ ((764GFCUgvw    (+*66650 A@E@@@ b`hgwp  ,]q]q3! !#3wH1j%@ :1/0@ 0P]3!!_ժ @4  B    >  91/<290KSXY"p]@V   && & 45 i|{y   #,'( 4<VY ej vy ]]! !###-}-+3 y@B6 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!#j+s #@  310"32' ! ':xyLHH[[bb:@   ? 291/0@ ?_]32654&#%!2+#8/ϒs R@*  B     39991990KSX9Y""32#'# ! '? !#y;:xLHHab[T@5  B    ?  299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#! 32654&#A{>ٿJx~hb؍O'~@<    B %( "-"(9999190KSX99Y")])/)O)].#"!"&'532654&/.54$32Hs_wzj{r{i76vce+ٶ0/EF~n|-&J@@@1/20K TX@878Y@  @ p ]!!#!ժ+)K@   8A1299990KTX@878Y]332653! ˮ®u\*$h@'B91/290KSXY"P]@b*GGZ} *&&))% 833<<7HEEIIGYVfiizvvyyu)]]!3 3J+D {@I      B     91/<2290KSXY"]@  ($ >>4 0 LMB @ Yjkg ` {|      !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx   []]3 3 3# #D:9:9+=; ]@F      B    91/<290KSXY"K TK T[KT[X  @878Y@ '' 486 KX[fkww       &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x   @]]3 3 # #su \Y+3{@(B@@ 91/290KSXY" ]@<5000F@@@QQQe &)78@ ghxp ]]3 3#f9\ @BB 991/0KSXY"K TK T[X @ 878Y@@ )&8HGH    / 59? GJO UYfio wx ]]!!!5!sP=g՚oXS@C210K TX@878YKTKT[X@878Y!#3!XB-@B/9910KSXY"#mo<@C<10KTKT[X@878Y!53#5oXޏ@ 91290##HHu-10!5f1@ D10K TKT[X@878Y #ofv{-{ %@'   #   E&22991/9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p' !"'''000 0!@@@ @!PPP P!``` `!ppp p! !]]"326=7#5#"&5463!54&#"5>32߬o?`TeZ3f{bsٴ)Lfa..'' 8@  G F221/0`]4&#"326>32#"&'#3姒:{{:/Rdaadq{?@  HE210@ ].#"3267#"!2NPƳPNM]-U5++++$$>:#qZ8@G E221/0`]3#5#"3232654&#":||ǧ^daDDaq{p@$   KE9190@)?p?????,// , ooooo ]q]!3267# 32.#" ͷjbck)^Z44*,8 Cė/p@     L<<991/22990K TX@878YKTX@878Y@P]#"!!##535463cM/ѹPhc/яNqVZ{ (J@#  &#' & G E)221/990`***]4&#"326!"&'5326=#"3253aQQR9||9=,*[cb::bcd4@  N  F21/<90`]#4&#"#3>32d||Bu\edy+@F<21/0@  @ P ` p ]3#3#`Vy D@   O  F<2991990@ @P`p]3+532653#F1iL`a( @)B F 291/<90KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹi#y"F1/0@ @P`p]3#{"Z@&   PPF#291/<<<290@0$P$p$$$$$$$ ]>32#4&#"#4&#"#3>32)Erurw?yz|v\`gb|d{6@  N  F21/<90`]#4&#"#3>32d||Bu\`edqu{ J@  QE10@#?{{   {  {]"32654&'2#"s98V{>@ GF2210@ `]%#3>32#"&4&#"326s:{{8 daaqVZ{ >@   GE2210@ `]32654&#"#"3253#/s:||:/daDDadJ{0@    F21/90P].#"#3>32JI,:.˾`fco{'@<  S  SB %( R"E(9999190KSX99Y"']@m   . , , , ; ; ; ; $( ( *//*(() )!$'      '/)?)_))))))]]q.#"#"&'532654&/.54632NZb?ĥZlfae@f?((TT@I!*##55YQKP%$78@  F<<2991/<2990]!!;#"&5#53w{KsբN`>X`6@    NF21/290`]332653#5#"&||Cua{fc=`@'B91/290KSXY"K TX@878YKTKT[X@878Y@Hj{  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz>]]3 3#=^^\`TV5` @IU U U U   B     91/<2290KSXY"K TKT[KT[KT[K T[X  @878YK TK T[KT[X @ 878Y@" 5 IIF @ [[U P nnf yy          %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } @/   y]]333# #V`jjj;y` Z@F      B   91/<290KSXY"K TKT[KT[KT[X  @878YKTX @ 878Y@   & =1 UWX f vzvt        )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x  /]] # # 3 dkr))`HJq=V`@C        B     9129990KSX2Y"K TKT[X@878YKTX@878Y@     # 5 I O N Z Z j        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx   e]]+5326?3 3N|lLT3!;^^hzHTNlX` @B 2991/0KSXY"K TK T[X @ 878YKTX  @878Y@B&GI  + 690 @@E@@CWY_ ``f``b ]]!!!5!qjL}e`ۓ%$@4 %   !  % $  C %<<29999999199999990K TX%%%@878Y&]#"&=4&+5326=46;#"3>l==k>DV[noZVtsݓXX10#$@6%   #%#C %<2<9999999199999990K TX%@%%878YKTX%%%@878Y&]326=467.=4&+532;#"+FUZooZUF?l>>l?VWstݔ1#@  1990#"'&'&'&#"56632326ian ^Xbian ^V1OD;>MSOE<>LhN'$uhm !@T   !!  ! !!!B     !  VV!"2299999991/<9990KSXY" #]@  s P#f iu {yyv v!# ]]4&#"326!.54632#!#TY?@WX??Y!X=>sr?<҈_Z?YWA?XXN)sIsrFv)su''&-k'(u3^'1usN'2'u)N'8u{-f'DR{-f'DCR{-f'DR{-'DR{-7'DR{-'DRqu{'Fqf'Hqf'HCqf'Hq'Hof'f'C\f'F'd7'Qquf'Rsquf'RCsquf'Rsqu'Rsqu7'RsXf'X{Xf'XC{Xf'X{X'X{9; '@  YW Y <<1<203!!#!5!oo\]u=  @  Z[Z10"32654&'2#"&546PnnPPnoO@v+..ooPOmmOOp1.-rB#!Q@+     "  "<<<221<9990%&&'667#&73JDFHAMf fIX⸹)**'# 32!b`@!    <<1/2<2990K TX@878Y66].#"!!!!53#535632NL=ty-=))׏/я\= >@54&.#"#"&'532654/.5467.54632{?>?>S8alӃ\]>9̭IXW:fqր][;;ȦI.Z.L-[.K''PGZsweZ54m@''TLf{xf[1,pE3!   \ 104632#"&3~|}}||};9 %@]] 91290!###&&54$yfNݸ/@0-'!  **.  !' $'$-F099991/990@@'(     ! "&  : :!MM I!I"jj  ]]4632#"&'532654&/.5467.#"#:A9`@IPAtx;e\`Wqqs`/Q*%jd_[?T>7;[gp/8L`@6EBC?2H09JC 9 $HE301BKL?gwyVpMI`3D/IC@&=>:A$104G$ 7aD=0^* D^ J21/02#"$'&5476$"32676654&'&&&&#"3267#"&54632mmllmmmmllmm^^``^^⃄^]]^\^BB@zBCFInmmmmnnmmmmng^^^傁^^__^]⃅]^^! "'F >@!    b b cbc91<<2<<903#######5Jq7rqr/B^^sRf1@ D10K TKT[X@878Y3#fF)@dd1<20K TK T[X@878YK TK T[KT[KT[X@878YKTKT[X@878Y@````pppp]3#%3#^y'>@"     <291<2<<990!!!!!'7!5!7!}/H{};fըfӪH@9  B     <291/<0KSXY"]@gww  ]!!!!!!#!59=qժF՞f +@< +,  )&  *&& &,+,* # )#3,99999999199999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''3>_'y=_''NOy;WfNPƀ[gX@CHp@CpDfbMKYg[KKX /@- !$'!!0 $*0999919990@     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV !"&'()]]32654&#".#"326#"&54632>32#"&1TevYR1UfvYRF^_HDa^/XZie7XXjeߦ~᧯w .@     <2<21/<<0!!#!5!!!-Ө-}} T@.B $# <2291/90KSXY" 5!!@po V@/B$ # <<291/90KSXY"55!5AǪR@F  B     fe f e<2299991/2<2<290KSXY"K TX@878Y@(' ' ')((79  ]]!#!5!5'!5!3 3!!!c`Tþ{yT9{3{JD{3V` M@%  !   NF!2912<990"`""]3326533267#"&'#"&'#% )I#ER2bf*V H<9 NPOONNh-)b@'! '!* $$*9991990K TK T[KT[KT[KT[X*@**878Y>54&#"#"&54632#"&54324&#"32IH7$$0e՘ݢe WOmVPmmWKt,>bFأ[t}t{w; ]@    91990@0QVPZ spvupz  Z pp{ t  ]]!! !!5 7AJI3!wq@gg120!#!# }/#@1 " $ #" #h#$9999991/<229990K TX$$$@878Y@V             ##(]]#3267#"&5467!##"#>3!i/7.%7vy"Pµ)6< yJ\:1fd.xo@E}/%&@  & iji&1026732#"&'&&#"#"&546327j Pd@7*8  kOeD=!0 l9TA6?&#Hn!bSA8?Ss;)_@3(%%  * "(kl"k *22999199990!!#5#"&5463354&#"56632"32655P,]uu>DIE~bRhP{@p?Dq[[""CO@Mr`d.@  klk 9910!!2#"&546"32654&PXγгi~hi}|P{ݿܾsN@@"   mm  9991/<20%!5654#"!5!&5! Dz?1/aL"a*>w؍{o{3>@C'-%= 4%:.-*1 %?47&%7& =&-7"E?<9999912<<29990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0+0@@@@@@@@@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/,-./]q].#">32!3267#"&'#"&5463!54&#"5>32"326=DJԄ ̷hddjMI؏`TeZ߬o0Z^Z55*,ywxx..''`f{bsٴ)H +@<+,&  )&  *&& &,+,* # #Q)E,22999999199999990@p(?-YVUV jf!{    { z{ {!"#$%{&%--&YVUZ(ifej(ztvz($$]] 32654&'.#".5327#"&'')gA\*g>}66]C_56`?`!*(Ou))Hn.Mw834OMx43N $@/  !# #%" " "!& %999919990KTKT[KT[X%%%@878Y@ ttttv]33267#"&546?>7>5#537ZZ:3mN`^gIYX0&DeWX5^1YnFC98ŸLVV/5<65 b@ <2991/0K TX @ 878YKTKT[KT[X  @878Y P ]#53#3+e^@ 10!#!^=} *@    91903##'%\sB}}`s-Pb;V#@@   B   !$  $912299990KSX29Y"K TX$$$@878Y.#"!!#"&'53267#5!>32&P,`r<::d/4a/am"?$Ɨ5dzɏ!!J;?@.9*-" *19" <-<<219999990#"'&'&'&#"56632326#"'&'&'&#"56632326ian ^Xbian ^Vgian ^Xbian ^VoNE;=LTNE;=KڲOE;=LSNE;=K`8@91/90@cmpxyvn]] !3!^DC?%# @I    B   o o n<2991<2990KSXY"55%-+#-+#RRH# @I  B   o op<<991<2990KSXY"5%5+-+-#^R^  ^R^   #@   1/<<220%3#%3#%3#hk'$uh^'$us^'2'us ;@   299991/220!!!!! !# !39OAg@AժF|pm|q{'3@1 . ("%4"1 K1 Q+E499912<2290@%?5_5p55555????? ooooo ]q].#"!3267#"&'#"32>32%"32654& H ̷jbdjQGьBN5Z44*,nmnm98olkp݇y/10!!yy/10!!ym '@   1<20#53#53ӤRӤR??m '@   1<203#%3#ӤRӤRլ@@@ 10#53ӤR?@ q103#ӤR՘?o )@ r <<103#3#!!oA#u"@91990  9%-=V'\^N'<su+@B10KSXY"3#-\^R#/@I -'! - -'!0 *$0* $ $(st*(s099999999919999999907'#"&''7&&5467'766324&#"326{r%$&(r;t=:x=q%%&&s7t@?s9q(&%%s>v:@t8s'%$|pprs#G@%Bon29190KSXY"5s-+#R#I@&Bop<9190KSXY"5+-#^R^  /J@(   L<2<2991/<22990K TX@878YKTX@878Y@0P]]#!##53546;#"3#JcM`/яNPhc/J@!    L<<991/<22990K TX@878YKTX@878Y@0P ]!#!"!!##53546JcM/ѹ{Phc/яN9;>@   Y W Y <<2<<2122220%!#!5!!5!3!!!oooo\\HF103#F@ 10%3#ӤR@m '@    1<20%3#%3#ӤRfӤR@@q L #'3?K@D$%&%&'$'B@ .(F4 :&$L%IC'1+C =  1 =I 7+ ! L9912<<2220KSXY"KTK T[K T[K T[K T[KT[XL@LL878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&WddWUccUt%ZVcbWWcdWccWUccܻۻۻۼܻۻhm'$um'(uhk'$uN'(uk'(uk',/u`m',/uXN',/u;k',/usk'2'usm'2'usk'2'u)k'8u)m'8u)k'8uy` F1/0@ @P`p]3#`?f7@ u91290K TKT[X@878Y3#'#fJ7c@$   VwVv99991<<99990K TK T[X@878Y'.#"#>3232673#"&9! &$}f[&@%9! &$}f[&@Z7IR!7IRb+/10K TKT[X@878Y!!V)9H W@ VV1<0K TX@878YKTKT[KT[X@878Y332673#"&v aWV` v HKKJLDf,@ d10K TX@878Y3# _@ V xV10K TK T[X@878YK TK T[K T[X@878Y4&#"3267#"&54632X@AWWA@Xzssss?XW@AWX@sss#u@  ' 1/90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ 0.W=fB@991<20K TKT[X@878Y3#3#߉fxLu @   '1/90!33267#"&546w-+76 >&Dzs5=X.. W]0i?f7@ u91<90K TKT[X@878Y373xu ?@   : y<<991/900P]3%!!'79Pw^Mo;jnH ^@  z z <<991/90KTX @ 878Y@ @ P ` sz p ]37#'7Ǹ}Lɸ{JZjXjm'6uof'V\m'=uXf']@ <210##    g@    2  y<291/220@(   ]]! )#53!!3 !iP`P5~.,qu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ## #)&' ! (%#" QE)999999919990KSXY"?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x"**']].#"32654&#"5432''%'3%F2X)6 ~r4*!M!ü޼z&77kc\̑oabk'<su=Vf'\^ =@   ? 2291/0@ ?_]332+#32654&#'ђV>@ GF2210@ `]%#3>32#"&4&#"326s:{{8daa-10!!ת? @M    B   <291<290KSXY" '77w55v8vL57y5yy5 ,@   |]|| 12035733! c)t'+n^J@$}}B ~9190KSX2Y"!!56754&#"56632 "?XhU4zHM98rn81^BQ##{l0b(H@'    #)~&~ )999190#"&'532654&##532654&#"56632 \e9}F4wCmxolV^^ad_(fQI7Z`mR|yOFJLl?<:=svcE`''5 d?''5db''5 dsm'* uqVZH'JP', /uu'6ou{'Vs'k'&-uqf'Fs'm'&-uqf'Fq$J@$ "    GE%<<1/<20`&&&]!5!533##5#"3232654&#"F:||ǧN}}daDDad10!!dHF103#F1@: "+ /) 2+"!)#&  , & &*!/<29999999999122<20K TK T[K T[KT[KT[KT[X222@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-  !"#$%&'()*+,-2   USjg ]].#"!!!!3267#"#734&5465#7332[f A78 ʝf[Y`(77(6bbiZȻ{.# .{ZiHH"{/ #/{"G)@ dd1<20KTKT[X@878YKTK T[KT[X@878YKTKT[X@878YKTX@878Y@````pppp]3#%3#^ys@B10KSXY"K TX@878YKTX@878Y@ %%6FVjg //]]3#7Ju@!  VV 99991<2990K TX@878YKTX@878Y ]'.#"#4632326=3#"&9 $(}gV$=09" (}gT";9! 2-ev 3)dw @B10KSXY"K TX@878YKTX@878Y@*$$5CUU//]]#ę1w@ 91<90K TX@878YKTX@878YKTX@878Y@ //- ]3#'#Ӌ1@ 91290K TK T[K T[K T[X@878YKTX@878YKTX@878Y@ "  ]373Ӌ ? @   ] <291<290KTKT[KT[KT[K T[K T[X@878YKTKT[X@878Y@T /9IFYi       "5GK S[ e]] !33##5!55bf]my9 j@ VV120K TX@878YKTX@878YKTKT[X@878Y332673#"&v cSRav 6978w{zf103#  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f55q=3=dd?y}s)3s\\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3XyysLs{{{{{{fqqqqq9999qqqqq9\3 'sLfR#hd+/s`N{H?55=ZyyLss/q%%=V^33 / /9% qyy\\\\;LsLsLs9#LF+o{\3X3 q=55^5bb3sq\+osfqsfqqds 5?+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""XO!nE~Le  R s  X : i  = z /Eu)pP@"m#{CwRw [ r !5!B!!!" ""#"0"="J"W"d"q"~"""""""""## ##'#4#A#N#[#h##$4$%3%S%&&'K''((X()_*%*\**+z+,D,,-P-..R./0A011!1P12H2z23F3p3p3}3334z44445595g55556[667C77888J999)969C9P9]9j9w99999999::{::;;^;;;<"<_<<<<<<=c>;>H>U>>>?a??@:@K@\@m@z@@@@@@@@A@AVAkBEBBC_CCDUDE*E?- x$%&')*K+-r./2934K57D9:;< =IQR&UYZ\bdg9xy&z&{&|&}&9 999 K$$$$$9$&$*$2$4$6$7a$8$9}$:$;$-Rfpgmp9)gasp glyf4h)&hdmxEHheadO$6hhea. $hmtxy,kernlocaXz[maxp} nameYͿpostx<prep|a!\::N:: R^0p   t t  &   ; 0  0   C , [ `   0 & Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera Sans BoldRelease 1.10BitstreamVeraSans-BoldCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera Sans BoldRelease 1.10BitstreamVeraSans-BoldCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comf3f=ffTbfTfmf3bq%fHZfm99Xm=fuff9{{X3fLfLJ#DDf?;Pw /X#/553X sf+j-j!f#^`3B3\fy```{j\{`bXP1L`%!JJ7{'}3Xy9bsA&%$!:$#"!:"!: d}}      Y    & Y @ &  .A@}>,,G}G  @ 2 d۠d%%%   %ё%Д #&̑ɻ]ɻɀ@%]@%dĐ::2  }& @ ]%]@..@   K%%%2 ~}|{zywvwvututsr}qpo,o,nmlkjihc h2gf2ed ed d@cb c b a`a``_ ^]\\[Z[ZZYXWV@VUTSRQRQQPOPONONMLKLKJKJIJIHGFGFEDCDCBA%BAA%@?@?>?>=< =< ;d:987656%54554 4432 33@2 10100/ .-,:-,%,:+d*d)(''& %$#@+$#" "!!@  %@ K}K%%dd   2     @   @d  d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX (EDY!-,%E`D-,KSX%%EDY!!-,ED-ff&&/10!%!!fsr) @ <2991/0!!!!h33h^h@1<20###h++)K@1     91/<2<<22<<220!3!!!!#!#!5!!5!!!`aaE````HFR`PF#*1s@? %$ + ,#,, (/($ +/ 2<<991/99999990#&&''&&546773&&'6654&}osy!dede GUNWWP-.);?7* "*/(BE5;CBBDCB '3c@5  % ."( 41+  1 +%49912<0KSXY""32654&'2#"&546#3!2#"&546"32654&3GNMHHLMGֺ%պպHNNHHMNh{rs{{sr{ؽ۽ ٽڽ٨|rs}}sr|{&06@Y     ,-./+0()'%0' - -! '*$ 0$*$  *  199999991/99990KSX999Y"']@   ' 0   0%/ / %&? ? @K K K/K0ZZUZ Z U(\.\0X2_2dig`i i d&2, ' '* 9 5005@J I'I(WW\ ['ggl ]] >7!!'# 5467.54632.#"3267577oc%Xbi*([k^PMU1ABwCt2>FnkmFDےj5j:0.;6"W/wGs))@ 10#+ @ 29910!&547!י);: @   29910654'!)?C)9F@(      <2<29912290%#'%%73%JLLNLNMXX "@   <<1/<<0!!#!5!    m9@ 10!#hduo10!!ot91/0!!h}B/99103#mb/ #@  10&#"326! ! i||jj|{j@'&@mstm (@  1/20!%!!!T[nT HH5@)% 9991/2990KSX9Y"K TX@878Y@&**"""555BJFF]]!!>54&#">3 N!IFuZzz )~B~DiMLH+-zӱ(L@+  #)& )999190!"&'32654&##532654&#"663 sqlg~]^rl#!%'%%)67jcfi[]V^*) \3 C@ !  ! %    <291/<290KSXY"!!3#!!Z@jRJ=@"  " 190!!663 !"&'32654&#"v,Y00{zaSl 12/FFuv+-# $7@ "% %$%190"32654&&&#"6632! !2eeeefeev_PB[uEgჃ-+11ir E@%91/0KSXY"]@ &5F]!!!e'1} #/G@( '-0 $*& '&!$0991990"32654&%&&54$! ! $54632654&#"lttlkrr|כc\ZbbZ\cvnnuunou)ž)*ސUY``YY_`j$7@  %%" $%19073267#"54! !"&2654&#"\RDZ9$@ieffeeff!++22 "vYN`@<21/0!!!!ii`}}N` %@  <210!#!!idiu}=@29190 5<'@ <210!!!!=@<91905511J!H@'    "<299991/9990!546776654&#"6632!!Bj@95`VQfy]N^@D*i1Rb:4\.FOCB:*(ǿbY9>K-o Ml@: 40LM3 30 07$CN34L **)(I(*)4=N<991299999032654&#"#"&54632536654&'&$#"3267#"$'&5476$32!#?iZYjkZXiYثY|:;_tZked~Yk}٘~~On{KM'{zyZGOPGKɝdIz=;bɵdbg^Pag}}IJ}|b~ ' @@     %    91/<90KSXY"K TX  @878Y@ / V f  t   %* IFGH XYVWhifg` t{zu{t      /]]!!!!!F_}))}+%R P@%    !299991/90@ ""/"P"]2654&+2654&+)! [^^[tutuH|B7fPNMQsbcaay$ռmf\;@    - +21990/_]%# !2.#"3267\j}Lu}jksskR78ef87IDDI9.@  -. 99991/0P]32654&#! )=TMwiffixjq#ateeta 0@   21/0 P p ]!!!!!!rg +@ 21/0 P p ]!!!!!rgfK@%    1 3/-+19990_]%# !2.#"3267#!ʥLy}|@   221/<<0@P ` p ]!!!!!!89+y=71/0KTKT[X@878Y@P]!!+f= L@   991990KTKT[X  @878Y @ P ]!!#3265N3IO@UZfi ]]!!!!mR+ff 2@  -7-+10@ /?]"3254 ! f°±hhgddjk 1@   - 299991/0]! !#!32654&#1pzzp_mddlffb@   - 7-+999190@,  '/V S f ` w w p  Y Y YXj i x ]]# ! !"3254fgk-¾lkh\@2%       29991/<9990KSX9Y"]@66EEVVPee`]2654&+!! !.#yiiyL'O}@f7q^?ZgfX֔-XspR-'@*% %( "(999919990@Tp)9999 JJJ X ]\^^ Z!joooh o n!t t t || |!  !  !(]].#"!"$'32654&/.54$!2{hYuӎ⏏ |~[ {78LP@881/20K TKT[X@878Y@ ]!!!! `N3@   91290@p]!3265!! yy6= '@'%91/290KSXY"K TKT[X@878Y@,  GGHHEJWX]]! !! 5N+= x@J 6  6 6 6   %     91/<2290KSXY"K TK T[K T[K T[X  @878Y@  % :?:?3 0 0 @ @ @ ^^a          '('(%* /66220002 4 6 ?IFHE J ]]ZZUURRRZ U ] ooonhheh k n i o wwx v x   K]]! ! !! !=qsnDD==+o' @E    %     91/<290KSXY"K TKT[KT[X  @878Y@X  /& <3 _P      ++%$%+ :55: P ejo  ]] ! ! ! !omGF@(%:: 91/290KSXY"K TK T[KT[X  @878Y@, %%0@P` %*5:0 O o ]]! !!TTu\q w@% 991/0KSXY"K TK T[X  @878Y@ %)69? FHO V_ o ]!!!5!s8!7@210!!!!mB/99103m@210!5!!5!m`@ 91290##fg--/10!5۾^fN10K TKT[X@878YK TX@878Y] #yfxX{ %@*   # # = ;&229991/9990@L/'= =!?'M M!] ]!n n!~ ~!p' ! ! ! !20C@SPc`]]"326=%!5#"&54$!354&#">3 pq[QeiH"ӆsUst/ LJDMm)f]ˢŸUO..^ 8@ B@ 221/0O`]%2654&#">32#"&'!!syyss{{{Ju uJf稠b]]bX5{7@ B ;210_].#"3267# !25IOT@TWV/X=202177\8@ @B ;221/0O`]!!5#"322654&#"hJu tsyysryyXc\II]ɨX {C@!    D ;9190/?]!3267# ! 4&#" q}K"=w`h3f~~CD015:“f}un'`@    E <<991/22990K TKT[X@878Y@ ]#"!!!#35463L<27DN`N\Fy(K@& #& @ B;)221/990O*`*]%#"54325!!"&'3265"32654&Ju uJhic^[o|xsp||b\CA\c !655@   G 21/<9990`]!54&'.#"!!>32 H.pfQnVon#'b])@ <21/0@ P ` p ]!!!!ff`F =@    <2991990@ P`p]!+53265!!fͱ>fLf`\y @   291/<90@`;IIZ]X_ogvv{:DGJV]g`ewpv|]]!! !!fNNK- 1/0@ P`p]!!f{%t@)   #  H H &<991/<<<29990KTX&&&@878Y@'0'P'p'''']>32!>54&#"!4&#"!!>32DpFNfo@RgphBgthmVH wkHk`_`p{5@   G 21/<9990`]!54&'.#"!!>32 H.pfQnVon#'`b]X'{ -@  BLB;107?G]"32654& ! w}}wu||u!EG{88V^{;@B @ 2210O`]%!!>32#"&"32654&fJu us{{ssyy b]]7\Vy ;@  @B;2210O`]"32654&#"325!!ryyrsyyyJu uJhw+c\IG\c{C@     21/990KTX@878Y.#"!!>32/]/fE}*(/`nejb{'@@  6  6% %( SRP"M(9999190KSX99Y" ]@^ #  ,. . . . . ) 9; ; ; : : K J J J H w w  %  7 ?)_) ]].#"!"&'32654&/.54632s_fcKa?o}ktijIm?c=0035+. ###44:90/ x@    T<<991/<2990KTKT[KT[KT[X@878Y@??PPP`` ]]!!;!"&5#33q>\Ա%N7>`;@  G 291/29990`]!3265!!5#"&hG.pfQmp[.w#&)b]`@'%91/290KSXY"K TKT[X@878Y@| 0@Vf  &$+)64990FFII`x$]]! !!fgGw`H` @J 4  4 4 4   %     91/<2290KSXY"K TK T[K T[X  @878Y@ 550 G @ @ _ l        &$+)*+ $ % /554;::78 ?GIFHGH YVV[ T Y _f`b```d ` upspppt p      []]!!!! !H\+\yy` ` @F    %    91/<290KSXY"K TKT[KT[KT[X  @878Y@  / 3< CL R\ bl sz         2     $++$ 4;;4 0 DKKD o       :]] !! ! !l{{l=#LbF`A@C %    9129990KSX9Y"K TKT[KT[X@878Y@ @Pet $$$5586699EEJJEEge    9]]! !+5326?f-f)Gp[S `6:K\F` @% 2991/0KSXY"K TK T[X  @878Y@DYVifyv &)/ 9? J_ ]]!!!5!uNN`f$^@1 %   ! % $  %<<29999999199999990#"&554&##5326554633#"3l==lEUZnoYUmutWW10#$`@2%   #%# %<2<999999919999999032655467&&554&##53233#"##FUZooZUFl==lmWW͖tuR#@  1990#"'&'&'&#"56632326j`k^Xbk`k^VRPE:=MSPE:=K 'k'$u 'm!{@S!! ! !%! !  UU "9999999991/<9990KSXY"K TX"""@878Y@/!/!:!o! !! # ///  /// "+ #EKUZ` ` ` ooo``ooo`fi `#tuyz{t    D]] !!!.54632%32654&#"!}^_}vtwM66MN56MJH"K+uu/L{6MM66MMRfo\'&sk'(um'15uffk'2Nuk'8'uXf'DXf'DCXf'DX1'DX9'DX'DXo5{'FX f'HX f'HCX f'HX 1'Hf'wf'Cwf'w<1'w9'QX'f'RX'f'RCX'f'RX'1'RX'9'Rf'Xf'XCf'X1'X5; *@  WV W <<1220!!!!!5!VJ#!/dL @  XYX10"32654&'2#"&546HdcIHdeGBz0/11-0|D\dHHbcGHd3/0xDCy-03#W@.    !$   B$<<222991<9990&&##667###$4%3NMMNJAY9S: GZ,lm*902i2/  (.##}@@!   <<1/222990&&#"!!!!3#5356!2FMvqu\'&} F=3?k@8@1:4 %+1@ =!+%74:!=\.!\=[.7[(@9999991999990&&#"#"&'532654'&'&&5467&&546326654&uc9KL ҟquMKUfs9AN$ˠoqKATDC{AF''1/CO Y}u0)qI)+2(FJWh33oKL2CbBO4Cj'` ]104676632#"&'&&'535II245633JI326J235624IJ336633;d &@ ^^9120!###&&54$\fN۲h0j@4.(" !++/"!(%  a%.(a_ . 199991/990@ /2O2p22]4$! #"&'532654&/.5467.#"! 1]EtkAJ8s6HX7bFXT`[efZG NJ%94%@uH9/D7'1Zt2UYnm 4Lb@8-*+'0!5 2+A'*,$0-+$!1g3f$cX;eX3cGM299991/29990"32676654&'&&#32654&'2#'&&###2#"$'&5476$yWWWWWVy{WWWWWXϲ##NOM+i`)Gok&: 1mmllmmmmllmm3WWWzyWVVUWWyzWXV5442wyVpP:NAD7nmmmmnnmmmmn1IH@(  2&>f,X c8e XhDJ21/990&&#"3267#"&54632'"32676654&'&&'2#"$'&5476$+9o9q~r@s.A>EyWWWWWVy{WWWWWXymmllmmmmllmmf%#rs~$#WWWzyWVVUWWyzWXVnmmmmnnmmmmn'R v@>  %    ji i ji91<<2<<9990KSXY"73#######5ww㪉LqKBMmf710K TKT[X@878Y]!#f;;1\@1<20K TK T[KT[KT[X@878YK TX@878Y3#%3#1 =@!      <291<2<2.990!3!!!'7#5!7!^P1}@7%     /<291/<90KSXY"K TK T[X@878Y@&W ] !!!!!!!!!{y}sfb^- +@> +,   )*&& &,+,* # )-#7-+,99999999199999990@p- -*'&!/-976!9)?-GYVT!Y(Y)jege!j%j($'))68)KFE I)Z^SVV T!V"[(j ejlaf c!k(x ]]3254&/.#".5!27!"&''\4SM3RJJgfqMLhfqs>;Du1:9@q.dkKMscdOOq /B@#  $'!-!0 $k*k099991<999032654&#"&&#"326#"&546326632#"&+vIZqgLHw+tKZqfMGzDaƯZcG_ů[1CDeOMeeCCdOMeia~q~n .@   l l <2<21/<<0!!#!5!!!  bb '@    <2291/90%!55PN '@   <<291/907!!55%y@B  %     nm n m<2<2999991/2<<<290KSXY"]@, $+6:FI   0@ ]]!!!5!5'!5!! !!!!N9:1k$! %j1`BV3VBT` :@!  !   !2912<990!3265!3267#"&'#"&'idfgdh!'!5]-Yq#/YJhT utqqtG8 KSOO/0;R)8@'! '!* $$*99919906654&#"#"&54632#"&54324&#"32;'#S0@eID`IFa~q9WzC2EqG Ur|tx)w O@    91990@ &#)  ) ( ) 8 ]]!! !!5 Bl_{Nw@pp120!!!!)JD/@    991/<22990#!#!#"663J'7: Ddd>Dǜ3,B*# @- *(&  qr q-9919026732#"&54&#"#"&54632jciRA@Ae '&>ÄkTF32-ӅhB:Yr 7^YUWO\K=4>3:rWT@LHt8;##uu 9A  @  uu 99102#"&546!!"32654&B7T[[TS[[޾ܾM~tt||tt~7F   @  xwx w 9991/<2990!!654&#"!!&5! #~˲˄~#~zx89xz#VˤUy9yǤX{>@B8>66'&# 6-*>;0*? - 6 & 7 3;?<9999912<<<9990@N>>?@MMO@^^_@nno@@@2=0>B=@>R=P>b=`>=>=>=>=>]]4&#""326=>32>3 !3267#"$'#"&54$!354&#"w`gpq[Qe^waGMz =q}~Heߋ"ӆsUf}unLJDMm)JMOMOf~~CD01kdkdŨŸUO..N) +@> )+ *& &&++, #* #)B#LB;,999999991/9999990@@:5 ;75!8)?-IF KGD!H)[VT!U(ikfe!e(5:)EJ)U^(i em( ]].#"32654&'.5!27!"&''XK/w}HO0u|;CDG"jKmFElMpD)A+CN{8,,eP~--^!M@*   "  "<2999919990!3267#"$54677665%!!iAm@84`VQew\N^@D*ii1Q~d:3\/FPDB*(ǾcX:=L-d @ <2991/0!!!33h=^qd@ 10!#!LZ n@*      %  @  9190KSXY"3##'%`w͑%hN7V7#w@I #"!   %   !$2299990KSX92Y"&&#"!!#"&'53267#5!766327.T*Zd!)AD.U)Ycu!3*Bs_sM#;C@!.9* 1 "9*1<-<<219999990#"'&'&'&#"56632326#"'&'&'&#"56632326j`k^Xbian ^Vgj`k ^Xbk`k^V#PE:=MSNE;=KPE:=LTPE:>K  @ /91/90!!!#-3mV?j' 5  @  y y<2991<299055%$'qsq' 5  @ yy <<991<29905-5%%%!$'^ #@   1/<<220!!!!!!hhh}}} 'k'$u 'm'$uffm'2NufP@"     -+ 299991/220@ !!?!O!_!]# !3!!!!!!"# !2i iZhsf / F& 0ihX^{'3t@2"  .(%4"1 1 +B;499912<9990@/5?5O5O5_5o5o55F"]]4&#"!3267#"&'# !2>3 %"32654&w`hA q}~~HRՂG"QRLJBcw}}wu||f}unwf~~CD01QWTT88RVWQ:/10!!/10!!X +@    1<20!3!3!ddXb`Xo + @  1<20!#!#!TeTe`^X@ 10!3'dX`X9@ 10!#Td`V 0@  z{z <<10!!!!!!33Xˁ#uv@A%91990KSXY"  9%-F1'\k'<uh+@55%10KSXY"#3 J=#/@ ! ! $A !* @&00   '}|~-} |022999999122999990'7&&5467'766327'#"&72654&#"ϙљ0l=6l9ϘϚ.j?:l[\[~ Ϛ1k??l.͚Ϛ7n6?i/ϙ\\\]~'y291905%'q'y<91905%%$'+Bu@&       ET<2<<991/<2<2990KTKT[KT[KT[X@878Y@]!!#"!!!!#35463iJK:k$7DN``N'Bl@!      ET<2991/<22990KTKT[KT[KT[X@878Y@]!!!"!!!#3546{L<)7DN`N3;?@!   W VW <<<<2912<220!!!!!!!5!!5!VJ###!<}910!!h}L@ 10!#Te`F + @  1<20!#!#TeTe`^B V #/3?K|@C3 2211 003%@ *$F4 :02$L3IC1!  C=!'= I7' -L9912<<2220KSXY""32654&'2#"&546"32654&'2#"&546#32#"&546"32654& HNNHGLLGֹHNNHHMNGպֺ׺GNMHHLMh{rs{{sr{ؽ۽8|rs}}sr|ٽڽ ؽ۽٨{rs{{sr{ 'k'$uk'(u 'k'$uk'(uk'(uk',duk',du)k',du=k',duffk'2Nuffk'2Nuffk'2Nuk'8'uk'8'uk'8'u` 1/0@ P`p]!!f`yf6@ 91290K TKT[X@878Y3#'#Dzf\9@  @  999919999990K TKT[X@878Y@T              ( ]]'&'&#"#4632326=3#"&7/$&g]$I)=%$(g]$CT%>;+@9X;E10K TKT[X@878YKTX@878Y!!vPF i@  1<0K TKT[KT[X@878YK TX@878Y@]332673#"& cSSc FFJJFw;1*10K TX@878Y!!w1 C @ : 10K TKT[X@878Y32654&#"4632#"&}M67LM67Lvvvv7LM66MM6vvvo5@   991/0K TX@878Y!#"&/32654&'Z:7{0f42S!:A+->j/_[ .(R<fE@991<20K TKT[X@878Y3#3#-fxVo@   991/0!33267#"&546ō2&;1'M(7^)s{6CI'1 \V5myf6@ 91<90K TKT[X@878Y 373Dzx `@2 %    <<.9991/90KSXY"!7!!'%s۔#` j ~@-   %    T <2.991/90KSXY" ]@ut@ P ` ` tp p  ]]!7!'7ho}o XV-k'6ujbf'Vb\qk'=u\Ff']T@ <210##  !L @   -. <291/<20@X!P!`!////////OOOOOOOO________(]]3#32654&#! )#3PULxhgghyk#ateetamX'(@Y&'('%$%(('"#" ! "! 5((5(%('&%"! ## #)'& !#(%" BB;)999919990KSX92Y"KTKT[X)@))878Y@6f!/*76"?*O*oooooooooo]].#"32654&! 4!2''%'!%7l4uru| uj-.N$%3`ox#y-\8 watr`k'<uFf'\ @  - 2299991/0K TK T[KT[KT[KT[X@878Y@,0000PPPP]]!!3 !32654&#=1pzzp]mcenV^;@B @ 2210O`]%!!>32#"&"32654&fJu us{{ssyyb]]7 10!!) /@   <291<290 '7NNNN3NPPN{ 7  @   129035733!9 41Zm]@%   "@99919990KSX9Y"!!56654&#"56632r_9=4I;>TWKGeD 5P(2>-/oHyVZ(W@ #  ""#@#)& )99919990#"&'532654&##532654&#"56632P\fQDB<_hkrJTbZNP4{FAWZ`nQ$%@;@=/3--piE`d @     % @    229991/222990KSXY"333##5!5#335733!9y+ I 41Zd'@   %!   $$& !&"@ #%# (9991/299990KSX9Y"%!!56654&#"56632#335733!qt];>3J<>UXJIc 5N'2?-0oH|T I 41Zh 6:@ : 9988 77: %.1* #! #!$-*$!#917@$$8'" :!'"4  '4-";229999991/2<299990KSXY"33##5!53#"&'532654&##532654&#"56632#3'y%]fQDB<_hjsJTb[OO5zGAVZ-D7#nQ$%@;@=/3--piE`q fk'* 1u\FF'J=k', duo-'6job{'Vbf\k'&fuXuf'Ff\k'&fuXLf'F\$K%@"      @"B;%<<1/<20O&]!5!5!3#!5#"322654&#"FhJu tsyysryyrr+c\II]ɨo10!!ot910!!h}1r@;.*(1.!2*("%!) 2 +) )% 2229999999999122<2990%# '#73&&5467#736!2&&#"!!!!3267_pKXbXMep_Qc-VY2~cTR78 87NO{v$$ zzOO;@ 1<203#%3#mN810K TX@878Y@ //]!#3\#@  @! $  $999991<29990K TX$$$@878Y@\             ##+]]'&'&#"#465463232653#"&8- (kW%J';'%'kW&F#<2j'<9j810K TX@878Y@ //]#yE@ 91<90K TX@878Y@/// ]!#'#f4߲DzyK@ 91290K TX@878Y@//// ]373f߲DzP S@  120K TX@878Y@///// / ]332673#"&`LL`=<<=w*10K TX@878Y!!w  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f+B{s/) mRo b\}j331 fwwf3ff)u 1 =+'\^fXX\mX{'\RVX\j7dH)7\1 1 fwffXfXfXfXfXfXXmXmXmXmX<XXXXX5}''m-Z;)L'3u'7bXNVL++1 1 f VfXBB  7VhJLL+'3  B B1 w1 ww)fffwV#j\\!X7{mZHdHdHhf\jfXfX\Ro mw   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~    sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468%%%%Nq] 6 N{U?u<_O K G E a > *2e:\u#p|$Z<~*Z@!I"dqjw   - : G T a n { !!]!"""##$.$%!%K%%&H''n''((()6){))*<*++p,5,-8-a-}-.B..//\/////00001161U1t112 2292233v344-4L4~5*575D5Q5^5k5x5555555556 67667H7k778'8W889-9:9G9T9a9::::;O;;;<>>>>>>??????@4@T@AA@AuAAB 79k:;Y<$&$&$&$&$7a$8$9u$:$<<$Y$\$h$D$D$$<$r$r$$$$<$%9%:%<%%&/&6&&K&K&&&&'&',,G}G  @ 2 YYdhd@%%Y   %Y%&Y]%]@%dX:t:2  Y~}|{zyxwvtvututYtsYs}rq&ponm @lkjkjj@ihihYhgYgf\ fedcdcb]ccbW%b]b@a`_.`_.^Y^]\ ] \ [Y[KZYZYXYXW%VUTSRQPO%PO%NMLKJIH H@FEFEDCDCC@BdB@A}@?>,>,=<;:94 9287265 6@5 5@43 4 3 211}0/0d//.-,+,K++**K)()(' (' &%$%2$#"#"!%!   2@   @:%dd:%:%K       @d:@  @d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-ff@ Q/10!%!!fsr) Y@.   :UTS 991/0KSX9Y"!!!!iqlhE^h@VS1<20###h++=P@6 Z Z W   91/<2<<22<<220!!!3!!!!#!#!7!!7!F+`aa)5E)6````5F5`hh7 !(/v@C# ")^] ^][* [!*)#"&- !&-& - & 09999991/<29990#&&'&&54$773&&'6654&T;]1`x=ҿ+,+eX1?w93TdA7ckI-+&7=7 "%/$ DQ=07VK39q '3M@+e .e"a(ee a`d4+%   1  + %49912<0"32654&'2#"&54#3!2#"&54"32654&Vo=>Wn? ֝ k֝ Vn==Wn?hWWUWꭍ ꪍXYTX9&0@[   0'0%&$''0:0' - -iYf!gd` '*$ * 0$* 1999991/99990KSX999Y"]@`  * 9 K K'[ \'bm n'   &0' ' +'+0;';0III H H'J0ZZ\ \ \\#X'honki i l0$]] >7!!'#"$5467.54$32.#"3267m)>Z7+xJTv{ֿ.[e5WOVd54&#"6$3278{hmpe_@PMRZKN=21Ū(i@,s ^ x s ^xsw#d`)   & /999190K TK T[X)))@878Y!"&'32654&+732654&#">32q~wh9YiŖ1yUl7vp%s%%)49kYYraLP,*  @;         : uS    991/<290KSXY"K TK T[K T[K T[X@878YK]] !!3#!!Lo556`ARJ'@9:^]]sys vS `  999190KSX9Y"K TK T[K T[K T[X@878Y!!>32!"&'32654&#"j7v-,_0r}t;ol|Tt ѹ12/HD`q+-fH 'r@! ^ ]sss%d`(  (9190K TX(((@878Y@```` ` ` `````` ]"32654&.#">32!"476$32rZPqX6VQN]|pxG^ἔYc`f,,ȵ31ک!s 3@:vS991/0KSXY"!!!'f-<-F #/t@$ *ssw$sd`0- ' -!0991990K TK T[K T[KT[KT[KT[X000@878Y"32654&%.54$!2!"$546"32654&ufXwglkM&zt3f{YIf{YtSauSb-e谠-/yŰwbDTwbEST7'@ ^]s s "sd`(%% (9190K TX(((@878YKTX(@((878Y@o o o ooo$o%o&o' ]73267#"&5!2#"&2654&#"T5WQM]i|qx_rWQqX!-+ȵ31کa [b`fT`N@(:TzT91/0KSXY"!!!!-iJChL`}}` Z@.   :TpTz   9910KSX9Y"!#!!h;լiJu}=@|{29190 5<'@ o}o<210!!!!=@|{<91905511Jo!@I !:!  Y]iUTd  ! "999991/9990KSX9Y"!!!766776654&#"6632hFWJOHQLPs>ajLP9d1P}f:=j69=CB:*(wf<>M+\j L]@5IM-.* LF~*1~!=WM -.L C'7M991<<29990"32654&#"&543273654!"!267#"&'&5476$32!"#"&' jQMjP'-ZS}˅v\`Kvhm⎇bxroirg!ґTXɒV^KSBTEKnWSbbRMl>ɰH]\Yv{ @A     : uS   91/<90KSXY"]@  + / ?   + ) ]]!!!!!uLZ+?+ h@::S    !9991/90KSXY"2654&##2654&##!!! 3gtQL>ebeLbk#A h[;>s~vKHyn՜JJ@ uu d` 991990@  ))]]%# 476$32.#"3267يrroqty>`oeF12J=78IDIN+J@@!  : S   9991/0KSXY"3 4&#! !! :/""`abjq.#EQQzm\+\ T@/    :S    91/0KSXY"!!!!!!N9s6g:B7+\ O@+    :S  91/0KSXY"!!!!!N9s6g:{J9 h@6  : uu d`!  !299199990KSX9Y"%# 476$32&&# 3267#!sƳrqw;zv8p991VoGEC=87GF"+ u@A     :S    91/<<0KSXY"!!!!!!No8n{{9+y+6@:S91/0KSXY"]!!N+f g@%  : S    9991990KSX9Y"K TKT[X @ 878Y!!#3267N:N9  :S  9991/<2990KSXY"] ]!!!!NVlR + J ;@ uud`! !10KTX!!!@878Y4&#"3267> # 476$쟗s? qRn{oja*k4s?=QE'la_[+{@H    : u u S      99991/<9990KSX9Y"] ]2654&+ !!2!.#]dL3o#9ȫNh'p"a\?zvJEոXsoSR'@;    : uu%d`( " "(9999190KSX99Y"]@9 9 9 9 9 99999 9!I I I I I IIIII I!YZ Z Z Z Z ZZZZZ Z!m m m m m mkkmmmmm m!y y y y y yyyyyy y!< )```` ]].#"!"$'32654&/.54!2R>qiGoƹɑ=zJ}e.y87ZP39'265EMLlT7= '+%b`@:S991/20KSXY"K TK T[KT[X@878Y!!!!`9NTg@:     : ` S  91290KSX99Y"!3267!! $5467N ih$A 0Jba$Y;q@':S91/290KSXY"]@%5)76 ]]!!!nj5\+ % @J        : S    91/<2290KSXY"KTX @ 878Y@j       / / ? ? O O YYY      &%#' 637 0 BB UZVPP  !]]!!!!!d.n1}L2B==+o @I   :  S   91/<290KSXY" ]@4  -$ <2 LC    '$' * 79 : DHG ]] !! !!nyKa  +yx@5:S  991/290KSXY"]@  D]]!!!yy)o 9@:S   91/0KSXY"!!!7!08%:-<F@":lk9910KSXY"!!!!Nl--B5@ S9103Xƾm@@:lk9910KSXY"!7!!7!3+ +m`@ S91290##fg--10! f2@ 910K TKT[X@878Y#'fx#{ +@c        : "  g#"g&`  )#"),9991/99990KSX99999Y";"]@83!0"C!@"S!P"c!`"!"!"!"5":#:$K#K$[#[$k#k$#$#$ ]]"326?%!7#"&54$!37>54&#">32QGn}XsK8}{oa6p~ SQ=Fy)d_ BC.."Q?j @K  : ii`k    !  9991/990KSX9999Y""32654&!!6632#"&?cX_.!.huRkMH[sw\ifk+b]ρd~]L{3@ ii`  99910&&#"3267# $5476$329HCފ~TI7Y[ibmU=02u21ډgqnJ @K  : ii` k    ! 9991/990KSX9999Y"%2654&#"!!7#"&54676632uaW_ti!RkMH[s]hfkXb]ρd~]J{'H@( g$g`( ' !  (9999190!3267# $54676$32%6654&#" q7[Wg `Ri'9mlDC0/݀dx|(Yo  P^spfR@<      : igkz     991/22990KSX9Y"K TKT[KT[KT[KT[KT[X@878Y@ ``pp]#"!!!#37>3R/KE /1Ѩ2%7CO`N)Fuy+@Y+* )'&(  :& &g i z&i)#! ,99991/99990KSX99999Y"%#"&546766327!!"&'3267"32654&XViMHXv7i:h^5UY!T^Z^b\qdy\c3 !65fkhm?;@L   :  k  %#  9991/<99990KSX999Y"0]!>54&#"!!>32)q GAol.hucm VH9O@Fa^ N?X@(:zk  91/0KSXY" ]o ]!!!!h.h9`F @:     : gz k   ...9991990KSX9Y"K TK T[X@878Yo]!+73267!!h.ղ-?e]+h9`[? @A      :zk   91/<90KSXY"]@<     )EQXcwpvz  *ESdpus ]]!! !!mhug^?6@:k  91/0KSXY"]!!mh?{+@x !    "#$# !$#(')&$#%$$#:!  &$ )$z" %"!$  &$ %% $# ,99999991/<<<299990KSX9999Y"]@#     /-]>32!7654&#"!>54&#"!!>32Sr q?6gls >7clh!TgtgnM1VH|#7@HKM8?`_`w?;{@N   :  z  %#& 9991/<99990KSX999Y"0]!>54&#"!!>32)q GAolh!cm VH9O@F`a^ NJ5{ )@ii ` !)! 10p]"32654&2#"$54676$a]a@ZVf\Vd{joincvx~dtxVj{@M:ii`z !   9991990KSX9999Y"0!]%!!>32#"&"32654&s-h!RkMH[sAcX_ b]ρd~]7\ifkJVu{@N:ii`z  ! 9991990KSX9999Y"7!!#"&546766322654&#"isPkMH[saW_Lb]ρd~]]hfk?\{@6       :  z   & 91/9990KSX99Y" ]@#    @@@@@@``````].#"!!>32%Z4 fh'GՂ0!/`jq{{'@9    : gg%`(  ,*"(9999190KSX99Y"K TKT[K T[X(@((878Y@i j j jjj j!````o)vv]].#"!"&'32654&/.54$!2{5i]js@^Aٮs}6atqr@dAs=2473$ .$$9:64$( (X@>  : iz i  9991/<2990KSX9Y"K TK T[KT[KT[KT[K T[X@878Y)]!!;!"&5467#3=n3\=H3Ӣ\1>& .(@!>{s`@M    :  ` z &%9991/299990KSX999Y"K TK T[K T[K T[K T[KT[KT[KT[KT[KT[KT[X@878Y0]!3267!!7#"&546gq FAolg!\p9P?F'a`#Nm`@&:z91/290KSXY"K TKT[KT[KT[KT[KT[K T[K T[K T[X@878Y@FVffj]]!!!Jkn`j` @F     : z    91/<2290KSXY"KTKT[KT[K T[X @ 878Y@(I   %% GHF W fh xty ]]!!!!!J'R)P`%`^` @I     : z    91/<290KSXY"KTKT[KT[K T[K T[X @ 878Y@N  (%)+ 1GJ   ((')+* 65GEGFG G G kch i  ]] !! !!t#8{=#LbF`@C :  gz   /9129990KSX9Y"K TKT[KT[KT[KT[KT[K T[K T[X@878Y@   H]]!!+7326?R;wʠ%qXa&!`6ρ;J<` x@,,:izi   91/0KSXY"KTKT[KT[KT[KT[X @ 878Y@)&/ ]]!!!7!1FC1/`fZ0@g0/.-,+* $%&'() "!# : 1 #)*k110-*)&#   19999999199999990KSX9999Y"#"&546776654&##7326776633#"3+ڳ%[u@->'%+Fg!vrPJ Qtm{{<(7XHtWZMC(.0C410#Z0@l+,+0,,+ :+1''%,'%/k1'&0  /0+",%(&01999999199999990KSX9999Y"32677667&&546776654&##73233#"##Fg!wsPL !QtC+۳']t?-=%%mYZND-*2D3z{="6XHuR#@ o o1990#"'&'&'&#"56632326j`k^Xbk`k^VRPE:=MSPE:=K{k'$Du{m !@P!!    ! !:! u W " !  "99991/<9990KSXY"]@2!!!-!9!?!Y!!!! ! !(* +!!! ]]32654&#"!!!.54632!M66MN56Mh+u9vuZP6MM66MMP%M,uu0ML?Jo'&+\k'(u+m'1uuJk'2uTk'8mu#f'D#f'DC#f'D#1'D#9'D#'DLo{'FJ3f'HJf'HCJf'HJ1'H?f's?f'Cs?Pf's?R1's?;9'QJ5f'RJ5f'RCJ5f'RJ51'RJ59'R{sf'X{sf'XC{sf'X{s1'XN; [@0:S    9991220KSXY"!!!!!7!JJ!--#/dL @  -.-10"32654&'2#"&546HdcIHdeGBz0/11-0|D\dHHbcGHd3/0xDCy-03"a@8    i i #   #99199990&&##667#&&5%3f{94p9K@ YG8HU77l(77DX.рJm520h10"#"#}@E  :^] gsd s  99991/222990KSX9Y"&&#"!!!!3#737$!27;G}!u-@34?-!4.\%({ F=3?@F@1:4%  $+1d@$7! =%+.47! :=(!11.=070.(@9999999199990&&#"#"&'732654&''&&5467&&54$326654&+Z=P^19Z96T_0f=Ma0Owp42S!PUaPXr(&=22)No{:$X6++?0/%=6f{;)\5Y>=V@[8=]'` 2104676632#"&'&&'535II245633JI326J235624IJ336633; c@.  :S  9999120KSX9Y"!###&&54+Ӽ9fN?T7@^&% %&%67734257:5,& % 2gg2gk`667&%)"/ 57) ,/), "/, 7 89999999991/990KSX999Y"6$!2#"&'732654&''&&54676654&#"!*5f =TNNJ18o4Rd.M=C<ROfuZڰ0I]H7H+;[L=(A7+/e?1CFkp 4Lb@8-*+'0!5 2+A'*,$0-+$!1837$4-;6-34GM299991/29990"32676654&'&&#32654&'2#'&&###2#"$'&5476$yWWWWWVy{WWWWWXϲ##NOM+i`)Gok&: 1mmllmmmmllmm3WWWzyWVVUWWyzWXV5442wyVpP:NAD7nmmmmnnmmmmn1IH@(  2&>7,- 486 -9DJ21/990&&#"3267#"&54632'"32676654&'&&'2#"$'&5476$+9o9q~r@s.A>EyWWWWWVy{WWWWWXymmllmmmmllmmf%#rs~$#WWWzyWVVUWWyzWXVnmmmmnnmmmmn'R v@>  :   S ;: : ;:91<<2<<9990KSXY"73#######5ww㪉LqKBMPf\10K TKT[X@878YK TK T[X@878Y@ ))<<LL]!#+%Jf7;1u@99991<20K TK T[X@878Y@*    0000 ////????]]3#%3#f111 =@!   o} o  <291<2<2.990!3!!!'7#5!7!^P1}`@M  : u S  91/<90KSXY"]@ %%] !!!!!!!!!yw9s5f9A7Db^++ (6@D(76) ,&# ,'#,u#ud#`72'76) 2 2&(2 7.9999999199999990@             ! . / 0 1 2 3 4 5 6@@@@@@@@@@@@@@ @!@.@/@0@1@2@3@4@5@6PPPPPPPPPPPPPP P!P.P/P0P1P2P3P4P5P6H].#".5476$32%#"&''3267>54'&'(zR**nkaXf--oj\f{'zNs?a_\t5 /B@#  $'!-!0 $<*<099991<999032654&#"&&#"326#"&546326632#"&+vIZqgLHw+tKZqfMGzDaƯZcG_ů[1CDeOMeeCCdOMeia~q~n .@o  o = = <2<21/<<0!!#!5!!!  bb '@  o  <2291/90%!55PN '@ o  <<291/907!!55%  @S  :    S    9991/2<<<290KSXY"!!!7!7'!7!!!!!!:RRA'o%#pH%%h;`LL LLT\`&@W   &#$"% : % "` z'&%  '9999912<990KSX999Y"!3267!3267#"&'#"&'7-hVRfxh'29b-Xc>XJ]`T u(INpu# LROO/0;R)8@'! '!* $$*99919906654&#"#"&54632#"&54324&#"32;'#S0@eID`IFa~q9WzC2EqG Ur|tx)w 0@    91990!!!!5Bl_{Nw@??120!!!!)JD/@    991/<22990#!#!#"663J'7: Ddd>Dǜ3,:@ *# - *(&  @A @-9919026732#"&54&#"#"&54632jciRA@Ae '&>ÄkTF54&#"7>32/'\p>5TVBe}MLXU#bK=9F,4qXT@}LFod ,.##z3^u\ b@ d   DD 999910@,@@@OOOPPP___ JJJEEEXXX ]]2#"&54!!"32654&Ϸ*7&XcFCcGMѹLPKQ7>@    GFG F 9991/<2990!!654&#"!!&5! #~˲˄~#~zx89xz#VˤUy9yǤ#{ @J@T7@5= ,&A A5&%"g5) @G=g/)`KJAD76 ,:%&D5:@ 2:D2K9999999999912<<<999990@6; ; K K [ [ k k 2?0@B?@@R?P@b?`@?@?@?@]]"326?>32>32!3267#"&'#"&54$!37>54&#">54&#"QGnuh9_Ղ p5BuK<|xr^aQi%SQ=Fy)JIMMI-\/9mlCD0/ghif BC..  P^to$+{@@$,+%("(#(ii`,+#, %+ +" $+!! ,.99999999199999990&&#"&&54676$327#"&''3267E- ''[WdhDa))ZVemD`E/J;L~duw..o;Octz12pL!@M !!!:UT Y] i` S"  !  "9999919990KSX9Y"!3267#"&54677667%!!h VKPFPLPr=`jLS8Fh3P{f<=h69=DA*(wfK@/91/90!!!#-3mV?}' 4@     991<290772+Z%L1+Z%'qsqu' 4@     991<29077%%77%%7u1X+#L1X-#^ y@=    :T     999991/<<220KSXY"!!!!!!%hKhKBhL}}}{k'$Du{m'$DuJm'2uV ; !@8    : S   !  "91/220KSXY"]@ ## #0#`#p## ]#";!!!!!!# 476$3iLqkh9u8g9A9y7`Ѐ;/1J.zIFJo{ 3?j@:+( g:i g4i.(`@ 1 +=1=17!" @999999912<99906654&#"!3267#"&'#"$54676$326632"32654&`Ri%# p7:Z։[Ue@^ a]a  P^un9mlDC0/NRRNcuwQQQQ(]Bjoin@ q9910!! 3@ q9910!! 3X7 f@4     : S   H  991<20KSX99Y"!3!3X7'ը:'ժX``X b@2     : S H  91<20KSX99Y"!#!#T7ըT8ԩ``X9@:S910KSX9Y"!3;:'ժX`X5@:S10KSX9Y"!#wT8ԩ`V *@ on IJI <<10!!!!!!33Xˁ#uv@A:91990KSXY"  9%-F1'\yk'<ud10#3 J=#/@H ! ! $!* 00   'LKM-L K022999999122999990'7&&5467'766327'#"&72654&#"ϙљ0l=6l9ϘϚ.j?:l[\[~ Ϛ1k??l.͚Ϛ7n6?i/ϙ\\\]~}'@919071+Z%'qN'@ 9199077%%7N1X+#fb@c  : i gkz  &N&991/<22<2990KSX9Y"K TKT[KT[KT[X@878Y?]]!!!!#"!!!#37>3h9h/KE /1Ѩ2%ܐ7CO`Nfb@L   : i gk z    N&991/<22990KSX9Y"K TKT[KT[KT[X@878Y?]!!!"!!!#37>?#KE /1Ѩ2%)7CO`N;@F       : X S       .9999991<2<20KSXY"!!!!!!!7!!7!JJ!-X#/JI/!X-!<}`/@:T910KSXY"!!hL}5@:T10KSX9Y"!#T8ժ`  b@2     : T H  91<20KSX99Y"!#!#T7ըT8ժ``q 5 #/3?Kb@7 eFe:a@e2e$a0*`42dL1C=3'!    - ! 'I 7 'C =L9912<<22202#"&54"32654&!"32654&'2#"&54#3!2#"&54"32654& ۜם Vn=>Wm>$Vo=>Wn? ֝ k֝ Vn==Wn?魍WWUWWWUWꭍ ꪍXYTX{k'$Du+\k'(u{k'$Du+\k'(u+\k'(u+k',u+k',u+k',u+k',uJk'2uJk'2uJk'2uTk'8muTk'8muTk'8mu?`0@:z& 91/0KSXY"!!h`f8@ 991290K TKT[X@878Y!#'#!f9@"    91999999990K TKT[X@878Y@(         (]]'&'&#"#>3232673#"&{1&"4 ^$C%5"&4 ^"<T%E<+C>=X,9910K TX@878Y!!bw%TFo@  91<90K TX@878YK TX@878Y@   ]332673#"&546WVPQh"͜F AFGI|y;-1K@ 9910K TK T[X@878Y@  00//??]]!!11y @@  KK10K TK T[KT[X@878Y#"&546324&#"326wxxwTABTUAATxxxxATTAAUT-o#@   991/0!#"&'732654&'%"1a3(Q&BL4X*hs 9/E7%f@ 1<20K TK T[X@878YK TKT[X@878Y@-   0000@@@@]3#3#ɮbfxoF@@  991/0@IIIIYYYYiiii ]!33267#"&5463G41-%R+9Z'joJJP"& EBA~59fP@ 991<90K TKT[X@878YK TX@878Y!373x `@6    : S    .9991/90KSXY"!%!!'%eTi N7bh=iJׇ @1: k   .9991/90KSXY"KTKT[KT[KT[KT[KT[K T[K T[X @ 878Y / ]!7!'%hfdu` NˑVDˇRk'6uf'Vbk'=!uf']T@ <210##  m p@:    : S      .9999991/<20KSXY"!]3#3 4&#! )#393F;0""`adk}3/#EQQ{m\Jm,@c*+,+)(),,+&'&#$#%$$#'(&%&(#$#(( !"(:,+*)&%$#'"'i i`'k-*+,) %$'&#" + !! -99999919990KSX9Y"&&#"32654'4#"$5!2''%'!%4f4d^@A[Wel%1W$#T`R#ms (j\tdtx] l^tj^yk'<uFf'\+j@: :u uS  9991/0KSXY"!32##!32654&#N+ WSY9BP̈eb׿uOVN\zRVVj@L:ii`k  !  999991990KSX9999Y"%!!6632#"&"32654&shuRkMH[sAcX_b]ρd~]7\ifk on10!!) /@   <291<290 '7NNNN3NPPN) @0 OO:  b     9991290KSX2Y"]@   ))99JMMJJ]3?33!fۅ9 41Z\sc@!  dP99919990@ 55YY ]]!!7>54&#"7>32y!\nPNA:DG$SElxD :c*(..,mdOTRj(t@- #  #d)   PP& )99919990@        (]#"&'732654&+732654&#"7>32KNP>!:w54&#"7>32#33?33!Dv ^nQMB9DG%SFlw=mfۅ :a))0/,mdOT I 41ZZ(+6:@r*6,6)+),,6)O*)-2-+O2-4O2-3O22-: #)* .*0 9#d40,7`2*)43+5:.120/-8   /-PP& 25- ;9999991/2<299990KSXY" (]@:)+*,(.9+:,9.Y)Y+i)i+         '[)l)]]#"&'732654&+732654&#"7>32 333##7!7#3LOQ>#:w3232673#"&j1!$4 _%A#5$'5 ]&@!% @8) =:`:910K TX@878Y@ //]#hG@ 991<90K TX@878Y@/// ]!#'#\3 M@ 991290K TX@878Y@//// ]!373N3@  1290K TX@878Y332673#"&5N QOHj'Ɣ<7=6}!>@ 9910K TX@878Y@ 0000]]!!/  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f+7q9s/) R3 ^;JXf-T3T3\1{+J+w+w+J++3++++J+J)+ub1+ f#?LJmJ{f)??R??V??JJ?X{7d)7Z1{1{Jw++Jf#f#f#f#f#f#LmJmJmJmJ?????JJJJJ{{{{N'?'7` Z;)L'3X^'7b#LVL3}3u^1{1{J VVJ''  7VJL}LNLfLf  ' q1{w+1{w+w+++++JJJ?=Ty-%5HJ7+\RZJ)+JLJLJR3 +`3N   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~    sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468""""iE%JbG>lq  < _  Y F M w mEK?Hn+McIgu$NLNh W !{!"q"#,#n#{$ $-$:$G$T$a$n${$$$$$$$$$$% %%$%1%>%K%X%e%r%%%%%&.&'''(3()**w*++E+,- -D-s-..//8/[//01D12t23x334+45'5L556!6!6.6;6H67Z7v77848c8899"9/9E99::;:;;;>u>>?#?i??@6@p@A+A8AEARA_AABBBCCCCD8DE EF{G`GmGzGGGGGGGHpHHI5IqIJ J6JlJJK` R79k:;2<$&$&$&$&$&$2$7<$8$9u$:$<$F$G$W$Y$Z$\k$d$g$h$o$$$$$$k$$h$h$$$$$$$$k$$$$$%9%:%<%%&6&&'&'Ben Litchfield * @version $Revision: 1.15 $ */ public abstract class Encoding implements COSObjectable { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(Encoding.class); /** Identifies a non-mapped character. */ public static final String NOTDEF = ".notdef"; /** * This is a mapping from a character code to a character name. */ protected final Map codeToName = new HashMap(); /** * This is a mapping from a character name to a character code. */ protected final Map nameToCode = new HashMap(); private static final Map NAME_TO_CHARACTER = new HashMap(); private static final Map CHARACTER_TO_NAME = new HashMap(); static { //Loads the official Adobe Glyph List loadGlyphList("org/apache/pdfbox/resources/glyphlist.txt"); //Loads some additional glyph mappings loadGlyphList("org/apache/pdfbox/resources/additional_glyphlist.txt"); // Load an external glyph list file that user can give as JVM property try { String location = System.getProperty("glyphlist_ext"); if(location != null) { File external = new File(location); if(external.exists()) { loadGlyphList(location); } } } catch (SecurityException e) // can occur on Sytem.getProperty { // PDFBOX-1946 ignore and continue } NAME_TO_CHARACTER.put( NOTDEF, "" ); NAME_TO_CHARACTER.put( "fi", "fi" ); NAME_TO_CHARACTER.put( "fl", "fl" ); NAME_TO_CHARACTER.put( "ffi", "ffi" ); NAME_TO_CHARACTER.put( "ff", "ff" ); NAME_TO_CHARACTER.put( "pi", "pi" ); for( Map.Entry entry : NAME_TO_CHARACTER.entrySet() ) { CHARACTER_TO_NAME.put( entry.getValue(), entry.getKey() ); } } /** * Loads a glyph list from a given location and populates the NAME_TO_CHARACTER hashmap * for character lookups. * @param location - The string location of the glyphlist file */ private static void loadGlyphList(String location) { BufferedReader glyphStream = null; try { InputStream resource = ResourceLoader.loadResource( location ); if (resource == null) { throw new MissingResourceException("Glyphlist not found: " + location, Encoding.class.getName(), location); } glyphStream = new BufferedReader( new InputStreamReader( resource, "ISO-8859-1" ) ); String line = null; while( (line = glyphStream.readLine()) != null ) { line = line.trim(); //lines starting with # are comments which we can ignore. if( !line.startsWith("#" ) ) { int semicolonIndex = line.indexOf( ';' ); if( semicolonIndex >= 0 ) { String unicodeValue = null; try { String characterName = line.substring( 0, semicolonIndex ); unicodeValue = line.substring( semicolonIndex+1, line.length() ); StringTokenizer tokenizer = new StringTokenizer( unicodeValue, " ", false ); StringBuilder value = new StringBuilder(); while(tokenizer.hasMoreTokens()) { int characterCode = Integer.parseInt( tokenizer.nextToken(), 16 ); value.append((char)characterCode); } if (NAME_TO_CHARACTER.containsKey(characterName)) { LOG.warn("duplicate value for characterName="+characterName+","+value); } else { NAME_TO_CHARACTER.put( characterName, value.toString() ); } } catch( NumberFormatException nfe ) { LOG.error("malformed unicode value "+ unicodeValue, nfe); } } } } } catch( IOException io ) { LOG.error("error while reading the glyph list.", io); } finally { if( glyphStream != null ) { try { glyphStream.close(); } catch( IOException e ) { LOG.error("error when closing the glyph list.", e); } } } } /** * Returns an unmodifiable view of the Code2Name mapping. * @return the Code2Name map */ public Map getCodeToNameMap() { return Collections.unmodifiableMap(codeToName); } /** * Returns an unmodifiable view of the Name2Code mapping. * @return the Name2Code map */ public Map getNameToCodeMap() { return Collections.unmodifiableMap(nameToCode); } /** * This will add a character encoding. * * @param code The character code that matches the character. * @param name The name of the character. */ public void addCharacterEncoding( int code, String name ) { codeToName.put( code, name ); nameToCode.put( name, code ); } /** * Determines if the encoding has a mapping for the given name value. * * @param name the source value for the mapping * @return the mapped value */ public boolean hasCodeForName(String name) { return nameToCode.containsKey(name); } /** * Determines if the encoding has a mapping for the given code value. * * @param code the source value for the mapping * @return the mapped value */ public boolean hasNameForCode(int code) { return codeToName.containsKey(code); } /** * This will get the character code for the name. * * @param name The name of the character. * * @return The code for the character. * * @throws IOException If there is no character code for the name. */ public int getCode( String name ) throws IOException { Integer code = nameToCode.get( name ); if( code == null ) { throw new IOException( "No character code for character name '" + name + "'" ); } return code; } /** * This will take a character code and get the name from the code. * * @param code The character code. * * @return The name of the character. * * @throws IOException If there is no name for the code. */ public String getName( int code ) throws IOException { return codeToName.get( code ); } /** * This will take a name and get the character code for that name. * * @param name The name. * * @return The name of the character. * */ public static String getCharacterForName(String name) { if (NAME_TO_CHARACTER.containsKey(name)) { LOG.debug("No character for name " + name); return NAME_TO_CHARACTER.get(name); } return null; } /** * This will take a character code and get the name from the code. * * @param c The character. * * @return The name of the character. * * @throws IOException If there is no name for the character. */ public String getNameFromCharacter( char c ) throws IOException { String name = CHARACTER_TO_NAME.get( Character.toString(c) ); if( name == null ) { throw new IOException( "No name for character '" + c + "'" ); } return name; } /** * This will get the character from the code. * * @param code The character code. * * @return The printable character for the code. * * @throws IOException If there is not name for the character. */ public String getCharacter( int code ) throws IOException { String name = getName( code ); if (name != null) { return getCharacter( name ); } return null; } /** * This will get the character from the name. * * @param name The name of the character. * * @return The printable character for the code. */ public String getCharacter( String name ) { String character = NAME_TO_CHARACTER.get( name ); if( character == null ) { // test if we have a suffix and if so remove it if ( name.indexOf('.') > 0 ) { character = getCharacter(name.substring( 0, name.indexOf('.') )); } // test for Unicode name // (uniXXXX - XXXX must be a multiple of four; // each representing a hexadecimal Unicode code point) else if ( name.startsWith( "uni" ) ) { int nameLength = name.length(); StringBuilder uniStr = new StringBuilder(); try { for ( int chPos = 3; chPos + 4 <= nameLength; chPos += 4 ) { int characterCode = Integer.parseInt( name.substring( chPos, chPos + 4), 16 ); if ( characterCode > 0xD7FF && characterCode < 0xE000 ) { LOG.warn( "Unicode character name with not allowed code area: " + name ); } else { uniStr.append( (char) characterCode ); } } character = uniStr.toString(); NAME_TO_CHARACTER.put(name, character); } catch (NumberFormatException nfe) { LOG.warn( "Not a number in Unicode character name: " + name ); character = name; } } // test for an alternate Unicode name representation else if ( name.startsWith( "u" ) ) { try { int characterCode = Integer.parseInt( name.substring( 1 ), 16 ); if ( characterCode > 0xD7FF && characterCode < 0xE000 ) { LOG.warn( "Unicode character name with not allowed code area: " + name ); } else { character = String.valueOf((char)characterCode); NAME_TO_CHARACTER.put(name, character); } } catch (NumberFormatException nfe) { LOG.warn( "Not a number in Unicode character name: " + name ); character = name; } } else if (nameToCode.containsKey(name)) { int code = nameToCode.get(name); character = Character.toString((char)code); } else { character = name; } } return character; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/PDFBoxCharsetProvider.java0000644000000000000000000000372012645757432027553 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import java.nio.charset.Charset; import java.nio.charset.spi.CharsetProvider; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * {@link CharsetProvider} implementation for publishing PDFBox's encodings. * @version $Revision$ */ public class PDFBoxCharsetProvider extends CharsetProvider { private final Set available = new java.util.HashSet(); private final Map map = new java.util.HashMap(); /** * Constructor. */ public PDFBoxCharsetProvider() { available.add(PDFDocEncodingCharset.INSTANCE); for (Charset cs : available) { map.put(cs.name(), cs); for (String alias : cs.aliases()) { map.put(alias, cs); } } } /** {@inheritDoc} */ @Override public Iterator charsets() { return Collections.unmodifiableSet(available).iterator(); } /** {@inheritDoc} */ @Override public Charset charsetForName(String charsetName) { return map.get(charsetName); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/package.html0000644000000000000000000000176012645757432025064 0ustar rootroot This package contains the implementations for all of the encodings that are used in PDF documents. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/0000755000000000000000000000000012645757432024764 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/EncodingConverter.java0000644000000000000000000000356512645757432031256 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding.conversion; import org.apache.fontbox.cmap.CMap; /** * EncodingConverter converts string or characters in one encoding, which is specified in PDF * file, to another string with respective java charset. The mapping from * PDF encoding name to java charset name is maintained by EncodingConversionManager * @author Pin Xue (http://www.pinxue.net), Holly Lee (holly.lee (at) gmail.com) * @version $Revision: 1.0 $ */ public interface EncodingConverter { /** * Convert a string. * * @param s the string to be converted * @return the converted string */ public String convertString(String s); /** * Convert bytes to a string. * * @param c the byte array to be converted * @param offset the starting offset of the array * @param length the number of bytes * @param cmap the cmap to be used for conversion * @return the converted string */ public String convertBytes(byte [] c, int offset, int length, CMap cmap); } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/CJKEncoding.java0000644000000000000000000002463312645757432027715 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding.conversion; import java.util.HashMap; import java.util.Iterator; /** * This class represents PDF encoding name to Java charset name mapping. * * @author Pin Xue (http://www.pinxue.net), Holly Lee (holly.lee (at) gmail.com) * @version $Revision: 1.0 $ */ class CJKEncodings { // Mapping: PDF encoding name -> Java (IANA) charset name private static HashMap charsetMapping = new HashMap(); private CJKEncodings() { } static { // Chinese (Simplified) // Microsoft Code Page 936 (lfCharSet 0x86), GB 2312-80 character set, EUC-CN encoding charsetMapping.put("GB-EUC-H", "GB2312"); // Vertical version of GB-EUC-H charsetMapping.put("GB-EUC-V", "GB2312"); // Mac OS, GB 2312-80 character set, EUC-CN encoding, Script Manager code 19 charsetMapping.put("GBpc-EUC-H", "GB2312"); // Vertical version of GBpc-EUC-H charsetMapping.put("GBpc-EUC-V", "GB2312"); // Microsoft Code Page 936 (lfCharSet 0x86), GBK character set, GBK encoding charsetMapping.put("GBK-EUC-H", "GBK"); // Vertical version of GBK-EUC-H charsetMapping.put("GBK-EUC-V", "GBK"); // Same as GBK-EUC-H but replaces half-width Latin characters with proportional // forms and maps character code 0x24 to a dollar sign ($) instead of a yuan symbol (♀∴) charsetMapping.put("GBKp-EUC-H", "GBK"); // Vertical version of GBKp-EUC-H charsetMapping.put("GBKp-EUC-V", "GBK"); // GB 18030-2000 character set, mixed 1-, 2-, and 4-byte encoding charsetMapping.put("GBK2K-H", "GB18030"); // Vertical version of GBK2K-H charsetMapping.put("GBK2K-V", "GB18030"); // Unicode (UCS-2) encoding for the Adobe-GB1 character collection charsetMapping.put("UniGB-UCS2-H", "ISO-10646-UCS-2"); // Vertical version of UniGB-UCS2-H charsetMapping.put("UniGB-UCS2-V", "ISO-10646-UCS-2"); // Unicode (UTF-16BE) encoding for the Adobe-GB1 character collection; contains mappings // for all characters in the GB18030-2000 character set charsetMapping.put("UniGB-UTF16-H", "UTF-16BE"); // Vertical version of UniGB-UTF16-H charsetMapping.put("UniGB-UTF16-V", "UTF-16BE"); // Chinese (Traditional) // Mac OS, Big Five character set, Big Five encoding, Script Manager code 2 charsetMapping.put("B5pc-H", "BIG5"); // Vertical version of B5pc-H charsetMapping.put("B5pc-V", "BIG5"); // Hong Kong SCS, an extension to the Big Five character set and encoding charsetMapping.put("HKscs-B5-H", "Big5-HKSCS"); // Vertical version of HKscs-B5-H charsetMapping.put("HKscs-B5-V", "Big5-HKSCS"); // Microsoft Code Page 950 (lfCharSet 0x88), Big Five character set with ETen extensions charsetMapping.put("ETen-B5-H", "BIG5"); // Vertical version of ETen-B5-H charsetMapping.put("ETen-B5-V", "BIG5"); // Same as ETen-B5-H but replaces half-width Latin characters with proportional forms charsetMapping.put("ETenms-B5-H", "BIG5"); // Vertical version of ETenms-B5-H charsetMapping.put("ETenms-B5-V", "BIG5"); // CNS 11643-1992 character set, EUC-TW encoding charsetMapping.put("CNS-EUC-H", "HZ"); // Vertical version of CNS-EUC-H charsetMapping.put("CNS-EUC-V", "HZ"); // Unicode (UCS-2) encoding for the Adobe-CNS1 character collection charsetMapping.put("UniCNS-UCS2-H", "ISO-10646-UCS-2"); // Vertical version of UniCNS-UCS2-H charsetMapping.put("UniCNS-UCS2-V", "ISO-10646-UCS-2"); // Unicode (UTF-16BE) encoding for the Adobe-CNS1 character collection; // contains mappings for all the characters in the HKSCS-2001 character set and // contains both 2- and 4- byte character codes charsetMapping.put("UniCNS-UTF16-H", "UTF-16BE"); // Vertical version of UniCNS-UTF16-H charsetMapping.put("UniCNS-UTF16-V", "UTF-16BE"); //Japanese // Mac OS, JIS X 0208 character set with KanjiTalk6 extensions, Shift-JIS encoding, Script Manager code 1 charsetMapping.put("83pv-RKSJ-H", "JIS"); // Microsoft Code Page 932 (lfCharSet 0x80), JIS X 0208 character set with NEC and IBM- extensions charsetMapping.put("90ms-RKSJ-H", "JIS"); // Vertical version of 90ms-RKSJ-H charsetMapping.put("90ms-RKSJ-V", "JIS"); // Same as 90ms-RKSJ-H but replaces half-width Latin characters with proportional forms charsetMapping.put("90msp-RKSJ-H", "JIS"); // Vertical version of 90msp-RKSJ-H charsetMapping.put("90msp-RKSJ-V", "JIS"); // Mac OS, JIS X 0208 character set with KanjiTalk7 extensions, Shift-JIS encoding, Script Manager code 1 charsetMapping.put("90pv-RKSJ-H", "JIS"); // JIS X 0208 character set with Fujitsu FMR extensions, Shift-JIS encoding charsetMapping.put("Add-RKSJ-H", "JIS"); // Vertical version of Add-RKSJ-H charsetMapping.put("Add-RKSJ-V", "JIS"); // JIS X 0208 character set, EUC-JP encoding charsetMapping.put("EUC-H", "JIS"); // Vertical version of EUC-H charsetMapping.put("EUC-V", "JIS"); // JIS C 6226 (JIS78) character set with NEC extensions, Shift-JIS encoding charsetMapping.put("Ext-RKSJ-H", "JIS"); // Vertical version of Ext-RKSJ-H charsetMapping.put("Ext-RKSJ-V", "JIS"); // JIS X 0208 character set, ISO-2022-JP encoding charsetMapping.put("H", "JIS"); // Vertical version of H charsetMapping.put("V", "JIS"); // Unicode (UCS-2) encoding for the Adobe-Japan1 character collection charsetMapping.put("UniJIS-UCS2-H", "ISO-10646-UCS-2"); // Vertical version of UniJIS-UCS2-H charsetMapping.put("UniJIS-UCS2-V", "ISO-10646-UCS-2"); // Same as UniJIS-UCS2-H but replaces proportional Latin characters with half-width forms charsetMapping.put("UniJIS-UCS2-HW-H", "ISO-10646-UCS-2"); // Vertical version of UniJIS-UCS2-HW-H charsetMapping.put("UniJIS-UCS2-HW-V", "ISO-10646-UCS-2"); // Unicode (UTF-16BE) encoding for the Adobe-Japan1 character collection; // contains mappings for all characters in the JIS X 0213:1000 character set charsetMapping.put("UniJIS-UTF16-H", "UTF-16BE"); // Vertical version of UniJIS-UTF16-H charsetMapping.put("UniJIS-UTF16-V", "UTF-16BE"); // JIS X 0208 character set, ISO-2022-JP encoding charsetMapping.put("Identity-H", "JIS"); // Vertical version of H charsetMapping.put("Identity-V", "JIS"); //Korean // KS X 1001:1992 character set, EUC-KR encoding charsetMapping.put("KSC-EUC-H", "KSC"); // Vertical version of KSC-EUC-H charsetMapping.put("KSC-EUC-V", "KSC"); // Microsoft Code Page 949 (lfCharSet 0x81), KS X 1001:1992 character set // plus 8822.putitional hangul, Unified Hangul Code (UHC) encoding charsetMapping.put("KSCms-UHC-H", "KSC"); // Vertical version of KSCms-UHC-H charsetMapping.put("KSCms-UHC-V", "KSC"); // Same as KSCms-UHC-H but replaces proportional Latin characters with half-width forms charsetMapping.put("KSCms-UHC-HW-H", "KSC"); // Vertical version of KSCms-UHC-HW-H charsetMapping.put("KSCms-UHC-HW-V", "KSC"); // Mac OS, KS X 1001:1992 character set with Mac OS KH extensions, Script Manager Code 3 charsetMapping.put("KSCpc-EUC-H", "KSC"); // Unicode (UCS-2) encoding for the Adobe-Korea1 character collection charsetMapping.put("UniKS-UCS2-H", "ISO-10646-UCS-2"); // Vertical version of UniKS-UCS2-H charsetMapping.put("UniKS-UCS2-V", "ISO-10646-UCS-2"); // Unicode (UTF-16BE) encoding for the Adobe-Korea1 character collection charsetMapping.put("UniKS-UTF16-H", "UTF-16BE"); // Vertical version of UniKS-UTF16-H charsetMapping.put("UniKS-UTF16-V", "UTF-16BE"); } /** * Get respective Java charset name from given PDF encoding name. * * @param encoding PDF encoding name * @return Java charset name, or null if not found */ public static final String getCharset( String encoding ) { if ( encoding.startsWith("COSName")) { encoding = encoding.substring(8, encoding.length()-1); } return (String)(charsetMapping.get(encoding)); } /** * Return an iterator to iterate through all encodings. */ public static final Iterator getEncodingIterator() { return charsetMapping.keySet().iterator(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/package.html0000644000000000000000000000177612645757432027260 0ustar rootroot This package contains the implementations for conversions of encodings and CMaps that are used in PDF documents. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/CJKConverter.java0000644000000000000000000000611112645757432030125 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding.conversion; import org.apache.fontbox.cmap.CMap; import java.io.UnsupportedEncodingException; /** * CJKConverter converts encodings defined in CJKEncodings. * * @author Pin Xue (http://www.pinxue.net), Holly Lee (holly.lee (at) gmail.com) * @version $Revision: 1.0 $ */ public class CJKConverter implements EncodingConverter { // The encoding private String encodingName = null; // The java charset name private String charsetName = null; /** * Constructs a CJKConverter from a PDF encoding name. * * @param encoding the encoding to be used */ public CJKConverter(String encoding) { encodingName = encoding; charsetName = CJKEncodings.getCharset(encoding); } /** * Convert a string. It occurs when a cmap lookup returned * converted bytes successfully, but we still need to convert its * encoding. The parameter s is constructs as one byte or a UTF-16BE * encoded string. * * Note: pdfbox set string to UTF-16BE charset before calling into * this. * * {@inheritDoc} */ public String convertString(String s) { if ( s.length() == 1 ) { return s; } if ( charsetName.equalsIgnoreCase("UTF-16BE") ) { return s; } try { return new String(s.getBytes("UTF-16BE"), charsetName); } catch ( UnsupportedEncodingException uee ) { return s; } } /** * Convert bytes to a string. We just convert bytes within * coderange defined in CMap. * * {@inheritDoc} */ public String convertBytes(byte [] c, int offset, int length, CMap cmap) { if ( cmap != null ) { try { if ( cmap.isInCodeSpaceRanges(c, offset, length) ) { return new String(c, offset, length, charsetName); } else { return null; } } catch ( UnsupportedEncodingException uee ) { return new String(c, offset, length); } } // No cmap? return null; } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/EncodingConversionManager.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/EncodingConversionManager.j0000644000000000000000000000465712645757432032242 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding.conversion; import java.util.Iterator; import java.util.HashMap; /** * EncodingConversionManager maintains relationship between PDF encoding name * and respective EncodingConverter instance. Those PDF encoding name like * GBK-EUC-H should be converted to java charset name before constructing a * java string instance * * @author Pin Xue (http://www.pinxue.net), Holly Lee (holly.lee (at) gmail.com) * @version $Revision: 1.0 $ */ public class EncodingConversionManager { /** * Mapping from PDF encoding name to EncodingConverter instance. */ private static HashMap encodingMap = new HashMap(); private EncodingConversionManager() { } /** * Initialize the encodingMap before anything calls us. */ static { // Add CJK encodings to map Iterator it = CJKEncodings.getEncodingIterator(); while ( it.hasNext() ) { String encodingName = (String)(it.next()); encodingMap.put(encodingName, new CJKConverter(encodingName)); } // If there is any other encoding conversions, please add it here. } /** * Get converter from given encoding name. If no converted defined, * a null is returned. * * @param encoding search for a converter for the given encoding name * @return the converter for the given encoding name */ public static final EncodingConverter getConverter(String encoding) { return (EncodingConverter)(encodingMap.get(encoding)); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/conversion/CMapSubstitution.java0000644000000000000000000000620112645757432031103 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding.conversion; import java.util.HashMap; /** * This class provides a mapping from char code to unicode mapping files used for CJK-encoding. * @author Andreas Lehmkühler * @version $Revision: 1.0 $ * */ public class CMapSubstitution { private static HashMap cmapSubstitutions = new HashMap(); private CMapSubstitution() { } static { // I don't know if these mappings are complete. Perhaps there // has to be added still one or more // chinese simplified cmapSubstitutions.put( "Adobe-GB1-4", "Adobe-GB1-UCS2" ); cmapSubstitutions.put( "GBK-EUC-H", "GBK-EUC-UCS2" ); cmapSubstitutions.put( "GBK-EUC-V", "GBK-EUC-UCS2" ); cmapSubstitutions.put( "GBpc-EUC-H", "GBpc-EUC-UCS2C" ); cmapSubstitutions.put( "GBpc-EUC-V", "GBpc-EUC-UCS2C" ); // chinese traditional cmapSubstitutions.put( "Adobe-CNS1-4", "Adobe-CNS1-UCS2" ); cmapSubstitutions.put( "B5pc-H", "B5pc-UCS2" ); cmapSubstitutions.put( "B5pc-V", "B5pc-UCS2" ); cmapSubstitutions.put( "ETen-B5-H", "ETen-B5-UCS2" ); cmapSubstitutions.put( "ETen-B5-V", "ETen-B5-UCS2" ); cmapSubstitutions.put( "ETenms-B5-H", "ETen-B5-UCS2" ); cmapSubstitutions.put( "ETenms-B5-V", "ETen-B5-UCS2" ); // japanese cmapSubstitutions.put( "90ms-RKSJ-H", "90ms-RKSJ-UCS2" ); cmapSubstitutions.put( "90ms-RKSJ-V", "90ms-RKSJ-UCS2" ); cmapSubstitutions.put( "90msp-RKSJ-H", "90ms-RKSJ-UCS2" ); cmapSubstitutions.put( "90msp-RKSJ-V", "90ms-RKSJ-UCS2" ); cmapSubstitutions.put( "90pv-RKSJ-H", "90pv-RKSJ-UCS2"); cmapSubstitutions.put( "UniJIS-UCS2-HW-H", "UniJIS-UCS2-H" ); cmapSubstitutions.put( "Adobe-Japan1-4", "Adobe-Japan1-UCS2"); cmapSubstitutions.put( "Adobe-Identity-0", "Identity-H"); cmapSubstitutions.put( "Adobe-Identity-1", "Identity-H"); } /** * * @param cmapName The name of a cmap for which we have to find a possible substitution * @return the substitution for the given cmap name */ public static String substituteCMap(String cmapName) { if (cmapSubstitutions.containsKey(cmapName)) { return (String)cmapSubstitutions.get(cmapName); } return cmapName; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/PDFDocEncodingCharset.java0000644000000000000000000001051312645757432027462 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import java.nio.charset.Charset; /** * {@link Charset} implementation for the "PDFDocEncoding" from the PDF specification. * @version $Revision$ */ public class PDFDocEncodingCharset extends SingleByteCharset { /** Canonical name for the PDFDocEncoding. */ public static final String NAME = "PDFDocEncoding"; /** Singleton instance. */ public static final PDFDocEncodingCharset INSTANCE = new PDFDocEncodingCharset(); /** * Creates a new "PDFDocEncoding" charset. */ public PDFDocEncodingCharset() { super(NAME, null, createEncoding()); } private static char[] createEncoding() { char[] encoding = new char[256]; //Initialize with basically ISO-8859-1 for (int i = 0; i < 256; i++) { encoding[i] = (char)i; } //...then do all deviations (based on the table in ISO 32000-1:2008) //block 1 encoding[0x18] = '\u02D8'; //BREVE encoding[0x19] = '\u02C7'; //CARON encoding[0x1A] = '\u02C6'; //MODIFIER LETTER CIRCUMFLEX ACCENT encoding[0x1B] = '\u02D9'; //DOT ABOVE encoding[0x1C] = '\u02DD'; //DOUBLE ACUTE ACCENT encoding[0x1D] = '\u02DB'; //OGONEK encoding[0x1E] = '\u02DA'; //RING ABOVE encoding[0x1F] = '\u02DC'; //SMALL TILDE //block 2 encoding[0x7F] = REPLACEMENT_CHARACTER; //undefined encoding[0x80] = '\u2022'; //BULLET encoding[0x81] = '\u2020'; //DAGGER encoding[0x82] = '\u2021'; //DOUBLE DAGGER encoding[0x83] = '\u2026'; //HORIZONTAL ELLIPSIS encoding[0x84] = '\u2014'; //EM DASH encoding[0x85] = '\u2013'; //EN DASH encoding[0x86] = '\u0192'; //LATIN SMALL LETTER SCRIPT F encoding[0x87] = '\u2044'; //FRACTION SLASH (solidus) encoding[0x88] = '\u2039'; //SINGLE LEFT-POINTING ANGLE QUOTATION MARK encoding[0x89] = '\u203A'; //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK encoding[0x8A] = '\u2212'; //MINUS SIGN encoding[0x8B] = '\u2030'; //PER MILLE SIGN encoding[0x8C] = '\u201E'; //DOUBLE LOW-9 QUOTATION MARK (quotedblbase) encoding[0x8D] = '\u201C'; //LEFT DOUBLE QUOTATION MARK (double quote left) encoding[0x8E] = '\u201D'; //RIGHT DOUBLE QUOTATION MARK (quotedblright) encoding[0x8F] = '\u2018'; //LEFT SINGLE QUOTATION MARK (quoteleft) encoding[0x90] = '\u2019'; //RIGHT SINGLE QUOTATION MARK (quoteright) encoding[0x91] = '\u201A'; //SINGLE LOW-9 QUOTATION MARK (quotesinglbase) encoding[0x92] = '\u2122'; //TRADE MARK SIGN encoding[0x93] = '\uFB01'; //LATIN SMALL LIGATURE FI encoding[0x94] = '\uFB02'; //LATIN SMALL LIGATURE FL encoding[0x95] = '\u0141'; //LATIN CAPITAL LETTER L WITH STROKE encoding[0x96] = '\u0152'; //LATIN CAPITAL LIGATURE OE encoding[0x97] = '\u0160'; //LATIN CAPITAL LETTER S WITH CARON encoding[0x98] = '\u0178'; //LATIN CAPITAL LETTER Y WITH DIAERESIS encoding[0x99] = '\u017D'; //LATIN CAPITAL LETTER Z WITH CARON encoding[0x9A] = '\u0131'; //LATIN SMALL LETTER DOTLESS I encoding[0x9B] = '\u0142'; //LATIN SMALL LETTER L WITH STROKE encoding[0x9C] = '\u0153'; //LATIN SMALL LIGATURE OE encoding[0x9D] = '\u0161'; //LATIN SMALL LETTER S WITH CARON encoding[0x9E] = '\u017E'; //LATIN SMALL LETTER Z WITH CARON encoding[0x9F] = REPLACEMENT_CHARACTER; //undefined encoding[0xA0] = '\u20AC'; //EURO SIGN //end of deviations return encoding; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/MacOSRomanEncoding.java0000644000000000000000000000436312645757432027056 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import org.apache.pdfbox.cos.COSBase; /** * This is the Mac OS Roman encoding, which is similar to the * MacRomanEncoding with the addition of 15 entries */ public class MacOSRomanEncoding extends MacRomanEncoding { /** * Singleton instance of this class. * * @since Apache PDFBox 1.8.6 */ public static final MacOSRomanEncoding INSTANCE = new MacOSRomanEncoding(); /** * Constructor. */ public MacOSRomanEncoding() { super(); addCharacterEncoding(255, "notequal"); addCharacterEncoding(260, "infinity"); addCharacterEncoding(262, "lessequal"); addCharacterEncoding(263, "greaterequal"); addCharacterEncoding(266, "partialdiff"); addCharacterEncoding(267, "summation"); addCharacterEncoding(270, "product"); addCharacterEncoding(271, "pi"); addCharacterEncoding(272, "integral"); addCharacterEncoding(275, "Omega"); addCharacterEncoding(303, "radical"); addCharacterEncoding(305, "approxequal"); addCharacterEncoding(306, "Delta"); addCharacterEncoding(327, "lozenge"); addCharacterEncoding(333, "Euro"); addCharacterEncoding(360, "apple"); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/StandardEncoding.java0000644000000000000000000002066112645757432026656 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; /** * This is an interface to a text encoder. * * @author Ben Litchfield * @version $Revision: 1.10 $ */ public class StandardEncoding extends Encoding { /** * Singleton instance of this class. * * @since Apache PDFBox 1.3.0 */ public static final StandardEncoding INSTANCE = new StandardEncoding(); /** * Constructor. */ public StandardEncoding() { addCharacterEncoding( 0101, "A" ); addCharacterEncoding( 0341, "AE" ); addCharacterEncoding( 0102, "B" ); addCharacterEncoding( 0103, "C" ); addCharacterEncoding( 0104, "D" ); addCharacterEncoding( 0105, "E" ); addCharacterEncoding( 0106, "F" ); addCharacterEncoding( 0107, "G" ); addCharacterEncoding( 0110, "H" ); addCharacterEncoding( 0111, "I" ); addCharacterEncoding( 0112, "J" ); addCharacterEncoding( 0113, "K" ); addCharacterEncoding( 0114, "L" ); addCharacterEncoding( 0350, "Lslash" ); addCharacterEncoding( 0115, "M" ); addCharacterEncoding( 0116, "N" ); addCharacterEncoding( 0117, "O" ); addCharacterEncoding( 0352, "OE" ); addCharacterEncoding( 0351, "Oslash" ); addCharacterEncoding( 0120, "P" ); addCharacterEncoding( 0121, "Q" ); addCharacterEncoding( 0122, "R" ); addCharacterEncoding( 0123, "S" ); addCharacterEncoding( 0124, "T" ); addCharacterEncoding( 0125, "U" ); addCharacterEncoding( 0126, "V" ); addCharacterEncoding( 0127, "W" ); addCharacterEncoding( 0130, "X" ); addCharacterEncoding( 0131, "Y" ); addCharacterEncoding( 0132, "Z" ); addCharacterEncoding( 0141, "a" ); addCharacterEncoding( 0302, "acute" ); addCharacterEncoding( 0361, "ae" ); addCharacterEncoding( 0046, "ampersand" ); addCharacterEncoding( 0136, "asciicircum" ); addCharacterEncoding( 0176, "asciitilde" ); addCharacterEncoding( 0052, "asterisk" ); addCharacterEncoding( 0100, "at" ); addCharacterEncoding( 0142, "b" ); addCharacterEncoding( 0134, "backslash" ); addCharacterEncoding( 0174, "bar" ); addCharacterEncoding( 0173, "braceleft" ); addCharacterEncoding( 0175, "braceright" ); addCharacterEncoding( 0133, "bracketleft" ); addCharacterEncoding( 0135, "bracketright" ); addCharacterEncoding( 0306, "breve" ); addCharacterEncoding( 0267, "bullet" ); addCharacterEncoding( 0143, "c" ); addCharacterEncoding( 0317, "caron" ); addCharacterEncoding( 0313, "cedilla" ); addCharacterEncoding( 0242, "cent" ); addCharacterEncoding( 0303, "circumflex" ); addCharacterEncoding( 0072, "colon" ); addCharacterEncoding( 0054, "comma" ); addCharacterEncoding( 0250, "currency" ); addCharacterEncoding( 0144, "d" ); addCharacterEncoding( 0262, "dagger" ); addCharacterEncoding( 0263, "daggerdbl" ); addCharacterEncoding( 0310, "dieresis" ); addCharacterEncoding( 0044, "dollar" ); addCharacterEncoding( 0307, "dotaccent" ); addCharacterEncoding( 0365, "dotlessi" ); addCharacterEncoding( 0145, "e" ); addCharacterEncoding( 0070, "eight" ); addCharacterEncoding( 0274, "ellipsis" ); addCharacterEncoding( 0320, "emdash" ); addCharacterEncoding( 0261, "endash" ); addCharacterEncoding( 0075, "equal" ); addCharacterEncoding( 0041, "exclam" ); addCharacterEncoding( 0241, "exclamdown" ); addCharacterEncoding( 0146, "f" ); addCharacterEncoding( 0256, "fi" ); addCharacterEncoding( 0065, "five" ); addCharacterEncoding( 0257, "fl" ); addCharacterEncoding( 0246, "florin" ); addCharacterEncoding( 0064, "four" ); addCharacterEncoding( 0244, "fraction" ); addCharacterEncoding( 0147, "g" ); addCharacterEncoding( 0373, "germandbls" ); addCharacterEncoding( 0301, "grave" ); addCharacterEncoding( 0076, "greater" ); addCharacterEncoding( 0253, "guillemotleft" ); addCharacterEncoding( 0273, "guillemotright" ); addCharacterEncoding( 0254, "guilsinglleft" ); addCharacterEncoding( 0255, "guilsinglright" ); addCharacterEncoding( 0150, "h" ); addCharacterEncoding( 0315, "hungarumlaut" ); addCharacterEncoding( 0055, "hyphen" ); addCharacterEncoding( 0151, "i" ); addCharacterEncoding( 0152, "j" ); addCharacterEncoding( 0153, "k" ); addCharacterEncoding( 0154, "l" ); addCharacterEncoding( 0074, "less" ); addCharacterEncoding( 0370, "lslash" ); addCharacterEncoding( 0155, "m" ); addCharacterEncoding( 0305, "macron" ); addCharacterEncoding( 0156, "n" ); addCharacterEncoding( 0071, "nine" ); addCharacterEncoding( 0043, "numbersign" ); addCharacterEncoding( 0157, "o" ); addCharacterEncoding( 0372, "oe" ); addCharacterEncoding( 0316, "ogonek" ); addCharacterEncoding( 0061, "one" ); addCharacterEncoding( 0343, "ordfeminine" ); addCharacterEncoding( 0353, "ordmasculine" ); addCharacterEncoding( 0371, "oslash" ); addCharacterEncoding( 0160, "p" ); addCharacterEncoding( 0266, "paragraph" ); addCharacterEncoding( 0050, "parenleft" ); addCharacterEncoding( 0051, "parenright" ); addCharacterEncoding( 0045, "percent" ); addCharacterEncoding( 0056, "period" ); addCharacterEncoding( 0264, "periodcentered" ); addCharacterEncoding( 0275, "perthousand" ); addCharacterEncoding( 0053, "plus" ); addCharacterEncoding( 0161, "q" ); addCharacterEncoding( 0077, "question" ); addCharacterEncoding( 0277, "questiondown" ); addCharacterEncoding( 0042, "quotedbl" ); addCharacterEncoding( 0271, "quotedblbase" ); addCharacterEncoding( 0252, "quotedblleft" ); addCharacterEncoding( 0272, "quotedblright" ); addCharacterEncoding( 0140, "quoteleft" ); addCharacterEncoding( 0047, "quoteright" ); addCharacterEncoding( 0270, "quotesinglbase" ); addCharacterEncoding( 0251, "quotesingle" ); addCharacterEncoding( 0162, "r" ); addCharacterEncoding( 0312, "ring" ); addCharacterEncoding( 0163, "s" ); addCharacterEncoding( 0247, "section" ); addCharacterEncoding( 0073, "semicolon" ); addCharacterEncoding( 0067, "seven" ); addCharacterEncoding( 0066, "six" ); addCharacterEncoding( 0057, "slash" ); addCharacterEncoding( 0040, "space" ); addCharacterEncoding( 0243, "sterling" ); addCharacterEncoding( 0164, "t" ); addCharacterEncoding( 0063, "three" ); addCharacterEncoding( 0304, "tilde" ); addCharacterEncoding( 0062, "two" ); addCharacterEncoding( 0165, "u" ); addCharacterEncoding( 0137, "underscore" ); addCharacterEncoding( 0166, "v" ); addCharacterEncoding( 0167, "w" ); addCharacterEncoding( 0170, "x" ); addCharacterEncoding( 0171, "y" ); addCharacterEncoding( 0245, "yen" ); addCharacterEncoding( 0172, "z" ); addCharacterEncoding( 0060, "zero" ); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return COSName.STANDARD_ENCODING; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/WinAnsiEncoding.java0000644000000000000000000002717712645757432026477 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; /** * This the win ansi encoding. * * @author Ben Litchfield */ public class WinAnsiEncoding extends Encoding { /** * Singleton instance of this class. * * @since Apache PDFBox 1.3.0 */ public static final WinAnsiEncoding INSTANCE = new WinAnsiEncoding(); /** * Constructor. */ public WinAnsiEncoding() { addCharacterEncoding(0101, "A"); addCharacterEncoding(0306, "AE"); addCharacterEncoding(0301, "Aacute"); addCharacterEncoding(0302, "Acircumflex"); addCharacterEncoding(0304, "Adieresis"); addCharacterEncoding(0300, "Agrave"); addCharacterEncoding(0305, "Aring"); addCharacterEncoding(0303, "Atilde"); addCharacterEncoding(0102, "B"); addCharacterEncoding(0103, "C"); addCharacterEncoding(0307, "Ccedilla"); addCharacterEncoding(0104, "D"); addCharacterEncoding(0105, "E"); addCharacterEncoding(0311, "Eacute"); addCharacterEncoding(0312, "Ecircumflex"); addCharacterEncoding(0313, "Edieresis"); addCharacterEncoding(0310, "Egrave"); addCharacterEncoding(0320, "Eth"); addCharacterEncoding(0200, "Euro"); addCharacterEncoding(0106, "F"); addCharacterEncoding(0107, "G"); addCharacterEncoding(0110, "H"); addCharacterEncoding(0111, "I"); addCharacterEncoding(0315, "Iacute"); addCharacterEncoding(0316, "Icircumflex"); addCharacterEncoding(0317, "Idieresis"); addCharacterEncoding(0314, "Igrave"); addCharacterEncoding(0112, "J"); addCharacterEncoding(0113, "K"); addCharacterEncoding(0114, "L"); addCharacterEncoding(0115, "M"); addCharacterEncoding(0116, "N"); addCharacterEncoding(0321, "Ntilde"); addCharacterEncoding(0117, "O"); addCharacterEncoding(0214, "OE"); addCharacterEncoding(0323, "Oacute"); addCharacterEncoding(0324, "Ocircumflex"); addCharacterEncoding(0326, "Odieresis"); addCharacterEncoding(0322, "Ograve"); addCharacterEncoding(0330, "Oslash"); addCharacterEncoding(0325, "Otilde"); addCharacterEncoding(0120, "P"); addCharacterEncoding(0121, "Q"); addCharacterEncoding(0122, "R"); addCharacterEncoding(0123, "S"); addCharacterEncoding(0212, "Scaron"); addCharacterEncoding(0124, "T"); addCharacterEncoding(0336, "Thorn"); addCharacterEncoding(0125, "U"); addCharacterEncoding(0332, "Uacute"); addCharacterEncoding(0333, "Ucircumflex"); addCharacterEncoding(0334, "Udieresis"); addCharacterEncoding(0331, "Ugrave"); addCharacterEncoding(0126, "V"); addCharacterEncoding(0127, "W"); addCharacterEncoding(0130, "X"); addCharacterEncoding(0131, "Y"); addCharacterEncoding(0335, "Yacute"); addCharacterEncoding(0237, "Ydieresis"); addCharacterEncoding(0132, "Z"); addCharacterEncoding(0216, "Zcaron"); addCharacterEncoding(0141, "a"); addCharacterEncoding(0341, "aacute"); addCharacterEncoding(0342, "acircumflex"); addCharacterEncoding(0264, "acute"); addCharacterEncoding(0344, "adieresis"); addCharacterEncoding(0346, "ae"); addCharacterEncoding(0340, "agrave"); addCharacterEncoding(046, "ampersand"); addCharacterEncoding(0345, "aring"); addCharacterEncoding(0136, "asciicircum"); addCharacterEncoding(0176, "asciitilde"); addCharacterEncoding(052, "asterisk"); addCharacterEncoding(0100, "at"); addCharacterEncoding(0343, "atilde"); addCharacterEncoding(0142, "b"); addCharacterEncoding(0134, "backslash"); addCharacterEncoding(0174, "bar"); addCharacterEncoding(0173, "braceleft"); addCharacterEncoding(0175, "braceright"); addCharacterEncoding(0133, "bracketleft"); addCharacterEncoding(0135, "bracketright"); addCharacterEncoding(0246, "brokenbar"); addCharacterEncoding(0225, "bullet"); addCharacterEncoding(0143, "c"); addCharacterEncoding(0347, "ccedilla"); addCharacterEncoding(0270, "cedilla"); addCharacterEncoding(0242, "cent"); addCharacterEncoding(0210, "circumflex"); addCharacterEncoding(072, "colon"); addCharacterEncoding(054, "comma"); addCharacterEncoding(0251, "copyright"); addCharacterEncoding(0244, "currency"); addCharacterEncoding(0144, "d"); addCharacterEncoding(0206, "dagger"); addCharacterEncoding(0207, "daggerdbl"); addCharacterEncoding(0260, "degree"); addCharacterEncoding(0250, "dieresis"); addCharacterEncoding(0367, "divide"); addCharacterEncoding(044, "dollar"); addCharacterEncoding(0145, "e"); addCharacterEncoding(0351, "eacute"); addCharacterEncoding(0352, "ecircumflex"); addCharacterEncoding(0353, "edieresis"); addCharacterEncoding(0350, "egrave"); addCharacterEncoding(070, "eight"); addCharacterEncoding(0205, "ellipsis"); addCharacterEncoding(0227, "emdash"); addCharacterEncoding(0226, "endash"); addCharacterEncoding(075, "equal"); addCharacterEncoding(0360, "eth"); addCharacterEncoding(041, "exclam"); addCharacterEncoding(0241, "exclamdown"); addCharacterEncoding(0146, "f"); addCharacterEncoding(065, "five"); addCharacterEncoding(0203, "florin"); addCharacterEncoding(064, "four"); addCharacterEncoding(0147, "g"); addCharacterEncoding(0337, "germandbls"); addCharacterEncoding(0140, "grave"); addCharacterEncoding(076, "greater"); addCharacterEncoding(0253, "guillemotleft"); addCharacterEncoding(0273, "guillemotright"); addCharacterEncoding(0213, "guilsinglleft"); addCharacterEncoding(0233, "guilsinglright"); addCharacterEncoding(0150, "h"); addCharacterEncoding(055, "hyphen"); addCharacterEncoding(0151, "i"); addCharacterEncoding(0355, "iacute"); addCharacterEncoding(0356, "icircumflex"); addCharacterEncoding(0357, "idieresis"); addCharacterEncoding(0354, "igrave"); addCharacterEncoding(0152, "j"); addCharacterEncoding(0153, "k"); addCharacterEncoding(0154, "l"); addCharacterEncoding(074, "less"); addCharacterEncoding(0254, "logicalnot"); addCharacterEncoding(0155, "m"); addCharacterEncoding(0257, "macron"); addCharacterEncoding(0265, "mu"); addCharacterEncoding(0327, "multiply"); addCharacterEncoding(0156, "n"); addCharacterEncoding(071, "nine"); addCharacterEncoding(0361, "ntilde"); addCharacterEncoding(043, "numbersign"); addCharacterEncoding(0157, "o"); addCharacterEncoding(0363, "oacute"); addCharacterEncoding(0364, "ocircumflex"); addCharacterEncoding(0366, "odieresis"); addCharacterEncoding(0234, "oe"); addCharacterEncoding(0362, "ograve"); addCharacterEncoding(061, "one"); addCharacterEncoding(0275, "onehalf"); addCharacterEncoding(0274, "onequarter"); addCharacterEncoding(0271, "onesuperior"); addCharacterEncoding(0252, "ordfeminine"); addCharacterEncoding(0272, "ordmasculine"); addCharacterEncoding(0370, "oslash"); addCharacterEncoding(0365, "otilde"); addCharacterEncoding(0160, "p"); addCharacterEncoding(0266, "paragraph"); addCharacterEncoding(050, "parenleft"); addCharacterEncoding(051, "parenright"); addCharacterEncoding(045, "percent"); addCharacterEncoding(056, "period"); addCharacterEncoding(0267, "periodcentered"); addCharacterEncoding(0211, "perthousand"); addCharacterEncoding(053, "plus"); addCharacterEncoding(0261, "plusminus"); addCharacterEncoding(0161, "q"); addCharacterEncoding(077, "question"); addCharacterEncoding(0277, "questiondown"); addCharacterEncoding(042, "quotedbl"); addCharacterEncoding(0204, "quotedblbase"); addCharacterEncoding(0223, "quotedblleft"); addCharacterEncoding(0224, "quotedblright"); addCharacterEncoding(0221, "quoteleft"); addCharacterEncoding(0222, "quoteright"); addCharacterEncoding(0202, "quotesinglbase"); addCharacterEncoding(047, "quotesingle"); addCharacterEncoding(0162, "r"); addCharacterEncoding(0256, "registered"); addCharacterEncoding(0163, "s"); addCharacterEncoding(0232, "scaron"); addCharacterEncoding(0247, "section"); addCharacterEncoding(073, "semicolon"); addCharacterEncoding(067, "seven"); addCharacterEncoding(066, "six"); addCharacterEncoding(057, "slash"); addCharacterEncoding(040, "space"); addCharacterEncoding(0243, "sterling"); addCharacterEncoding(0164, "t"); addCharacterEncoding(0376, "thorn"); addCharacterEncoding(063, "three"); addCharacterEncoding(0276, "threequarters"); addCharacterEncoding(0263, "threesuperior"); addCharacterEncoding(0230, "tilde"); addCharacterEncoding(0231, "trademark"); addCharacterEncoding(062, "two"); addCharacterEncoding(0262, "twosuperior"); addCharacterEncoding(0165, "u"); addCharacterEncoding(0372, "uacute"); addCharacterEncoding(0373, "ucircumflex"); addCharacterEncoding(0374, "udieresis"); addCharacterEncoding(0371, "ugrave"); addCharacterEncoding(0137, "underscore"); addCharacterEncoding(0166, "v"); addCharacterEncoding(0167, "w"); addCharacterEncoding(0170, "x"); addCharacterEncoding(0171, "y"); addCharacterEncoding(0375, "yacute"); addCharacterEncoding(0377, "ydieresis"); addCharacterEncoding(0245, "yen"); addCharacterEncoding(0172, "z"); addCharacterEncoding(0236, "zcaron"); addCharacterEncoding(060, "zero"); // adding some additional mappings as defined in Appendix D of the pdf spec // we must not add them to both mappings as the nameToCode mapping // wouldn't be unique codeToName.put(0240, "space"); codeToName.put(0255, "hyphen"); for (int i = 041; i <= 255; i++) { if (!codeToName.containsKey(i)) { codeToName.put(i, "bullet"); } } } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return COSName.WIN_ANSI_ENCODING; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/DictionaryEncoding.java0000644000000000000000000000714312645757432027223 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; /** * This will perform the encoding from a dictionary. * * @author Ben Litchfield * @version $Revision: 1.13 $ */ public class DictionaryEncoding extends Encoding { private COSDictionary encoding = null; /** * Constructor. * * @param fontEncoding The encoding dictionary. * * @throws IOException If there is a problem getting the base font. */ public DictionaryEncoding( COSDictionary fontEncoding ) throws IOException { encoding = fontEncoding; //first set up the base encoding //The previious value WinAnsiEncoding() has been changed to StandardEnding //see p 389 of the PDF 1.5 ref�rence table 5.11 entries in a dictionary encoding //"If this entry is absent, the Differences entry describes differences from an implicit //base encoding. For a font program that is embedded in the PDF file, the //implicit base encoding is the font program�s built-in encoding, as described //above and further elaborated in the sections on specific font types below. Otherwise, //for a nonsymbolic font, it is StandardEncoding, and for a symbolic font, it //is the font�s built-in encoding." // The default base encoding is standardEncoding Encoding baseEncoding = StandardEncoding.INSTANCE; COSName baseEncodingName = (COSName) encoding.getDictionaryObject(COSName.BASE_ENCODING); if (baseEncodingName != null) { baseEncoding = EncodingManager.INSTANCE.getEncoding(baseEncodingName); } nameToCode.putAll( baseEncoding.nameToCode ); codeToName.putAll( baseEncoding.codeToName ); //now replace with the differences. COSArray differences = (COSArray)encoding.getDictionaryObject( COSName.DIFFERENCES ); int currentIndex = -1; for( int i=0; differences != null && iBen Litchfield */ public class MacRomanEncoding extends Encoding { /** * Singleton instance of this class. * * @since Apache PDFBox 1.3.0 */ public static final MacRomanEncoding INSTANCE = new MacRomanEncoding(); /** * Constructor. */ public MacRomanEncoding() { addCharacterEncoding( 0101, "A" ); addCharacterEncoding( 0256, "AE" ); addCharacterEncoding( 0347, "Aacute" ); addCharacterEncoding( 0345, "Acircumflex" ); addCharacterEncoding( 0200, "Adieresis" ); addCharacterEncoding( 0313, "Agrave" ); addCharacterEncoding( 0201, "Aring" ); addCharacterEncoding( 0314, "Atilde" ); addCharacterEncoding( 0102, "B" ); addCharacterEncoding( 0103, "C" ); addCharacterEncoding( 0202, "Ccedilla" ); addCharacterEncoding( 0104, "D" ); addCharacterEncoding( 0105, "E" ); addCharacterEncoding( 0203, "Eacute" ); addCharacterEncoding( 0346, "Ecircumflex" ); addCharacterEncoding( 0350, "Edieresis" ); addCharacterEncoding( 0351, "Egrave" ); addCharacterEncoding( 0106, "F" ); addCharacterEncoding( 0107, "G" ); addCharacterEncoding( 0110, "H" ); addCharacterEncoding( 0111, "I" ); addCharacterEncoding( 0352, "Iacute" ); addCharacterEncoding( 0353, "Icircumflex" ); addCharacterEncoding( 0354, "Idieresis" ); addCharacterEncoding( 0355, "Igrave" ); addCharacterEncoding( 0112, "J" ); addCharacterEncoding( 0113, "K" ); addCharacterEncoding( 0114, "L" ); addCharacterEncoding( 0115, "M" ); addCharacterEncoding( 0116, "N" ); addCharacterEncoding( 0204, "Ntilde" ); addCharacterEncoding( 0117, "O" ); addCharacterEncoding( 0316, "OE" ); addCharacterEncoding( 0356, "Oacute" ); addCharacterEncoding( 0357, "Ocircumflex" ); addCharacterEncoding( 0205, "Odieresis" ); addCharacterEncoding( 0361, "Ograve" ); addCharacterEncoding( 0257, "Oslash" ); addCharacterEncoding( 0315, "Otilde" ); addCharacterEncoding( 0120, "P" ); addCharacterEncoding( 0121, "Q" ); addCharacterEncoding( 0122, "R" ); addCharacterEncoding( 0123, "S" ); addCharacterEncoding( 0124, "T" ); addCharacterEncoding( 0125, "U" ); addCharacterEncoding( 0362, "Uacute" ); addCharacterEncoding( 0363, "Ucircumflex" ); addCharacterEncoding( 0206, "Udieresis" ); addCharacterEncoding( 0364, "Ugrave" ); addCharacterEncoding( 0126, "V" ); addCharacterEncoding( 0127, "W" ); addCharacterEncoding( 0130, "X" ); addCharacterEncoding( 0131, "Y" ); addCharacterEncoding( 0331, "Ydieresis" ); addCharacterEncoding( 0132, "Z" ); addCharacterEncoding( 0141, "a" ); addCharacterEncoding( 0207, "aacute" ); addCharacterEncoding( 0211, "acircumflex" ); addCharacterEncoding( 0253, "acute" ); addCharacterEncoding( 0212, "adieresis" ); addCharacterEncoding( 0276, "ae" ); addCharacterEncoding( 0210, "agrave" ); addCharacterEncoding( 046, "ampersand" ); addCharacterEncoding( 0214, "aring" ); addCharacterEncoding( 0136, "asciicircum" ); addCharacterEncoding( 0176, "asciitilde" ); addCharacterEncoding( 052, "asterisk" ); addCharacterEncoding( 0100, "at" ); addCharacterEncoding( 0213, "atilde" ); addCharacterEncoding( 0142, "b" ); addCharacterEncoding( 0134, "backslash" ); addCharacterEncoding( 0174, "bar" ); addCharacterEncoding( 0173, "braceleft" ); addCharacterEncoding( 0175, "braceright" ); addCharacterEncoding( 0133, "bracketleft" ); addCharacterEncoding( 0135, "bracketright" ); addCharacterEncoding( 0371, "breve" ); addCharacterEncoding( 0245, "bullet" ); addCharacterEncoding( 0143, "c" ); addCharacterEncoding( 0377, "caron" ); addCharacterEncoding( 0215, "ccedilla" ); addCharacterEncoding( 0374, "cedilla" ); addCharacterEncoding( 0242, "cent" ); addCharacterEncoding( 0366, "circumflex" ); addCharacterEncoding( 072, "colon" ); addCharacterEncoding( 054, "comma" ); addCharacterEncoding( 0251, "copyright" ); addCharacterEncoding( 0333, "currency" ); addCharacterEncoding( 0144, "d" ); addCharacterEncoding( 0240, "dagger" ); addCharacterEncoding( 0340, "daggerdbl" ); addCharacterEncoding( 0241, "degree" ); addCharacterEncoding( 0254, "dieresis" ); addCharacterEncoding( 0326, "divide" ); addCharacterEncoding( 044, "dollar" ); addCharacterEncoding( 0372, "dotaccent" ); addCharacterEncoding( 0365, "dotlessi" ); addCharacterEncoding( 0145, "e" ); addCharacterEncoding( 0216, "eacute" ); addCharacterEncoding( 0220, "ecircumflex" ); addCharacterEncoding( 0221, "edieresis" ); addCharacterEncoding( 0217, "egrave" ); addCharacterEncoding( 070, "eight" ); addCharacterEncoding( 0311, "ellipsis" ); addCharacterEncoding( 0321, "emdash" ); addCharacterEncoding( 0320, "endash" ); addCharacterEncoding( 075, "equal" ); addCharacterEncoding( 041, "exclam" ); addCharacterEncoding( 0301, "exclamdown" ); addCharacterEncoding( 0146, "f" ); addCharacterEncoding( 0336, "fi" ); addCharacterEncoding( 065, "five" ); addCharacterEncoding( 0337, "fl" ); addCharacterEncoding( 0304, "florin" ); addCharacterEncoding( 064, "four" ); addCharacterEncoding( 0332, "fraction" ); addCharacterEncoding( 0147, "g" ); addCharacterEncoding( 0247, "germandbls" ); addCharacterEncoding( 0140, "grave" ); addCharacterEncoding( 076, "greater" ); addCharacterEncoding( 0307, "guillemotleft" ); addCharacterEncoding( 0310, "guillemotright" ); addCharacterEncoding( 0334, "guilsinglleft" ); addCharacterEncoding( 0335, "guilsinglright" ); addCharacterEncoding( 0150, "h" ); addCharacterEncoding( 0375, "hungarumlaut" ); addCharacterEncoding( 055, "hyphen" ); addCharacterEncoding( 0151, "i" ); addCharacterEncoding( 0222, "iacute" ); addCharacterEncoding( 0224, "icircumflex" ); addCharacterEncoding( 0225, "idieresis" ); addCharacterEncoding( 0223, "igrave" ); addCharacterEncoding( 0152, "j" ); addCharacterEncoding( 0153, "k" ); addCharacterEncoding( 0154, "l" ); addCharacterEncoding( 074, "less" ); addCharacterEncoding( 0302, "logicalnot" ); addCharacterEncoding( 0155, "m" ); addCharacterEncoding( 0370, "macron" ); addCharacterEncoding( 0265, "mu" ); addCharacterEncoding( 0156, "n" ); addCharacterEncoding( 071, "nine" ); addCharacterEncoding( 0226, "ntilde" ); addCharacterEncoding( 043, "numbersign" ); addCharacterEncoding( 0157, "o" ); addCharacterEncoding( 0227, "oacute" ); addCharacterEncoding( 0231, "ocircumflex" ); addCharacterEncoding( 0232, "odieresis" ); addCharacterEncoding( 0317, "oe" ); addCharacterEncoding( 0376, "ogonek" ); addCharacterEncoding( 0230, "ograve" ); addCharacterEncoding( 061, "one" ); addCharacterEncoding( 0273, "ordfeminine" ); addCharacterEncoding( 0274, "ordmasculine" ); addCharacterEncoding( 0277, "oslash" ); addCharacterEncoding( 0233, "otilde" ); addCharacterEncoding( 0160, "p" ); addCharacterEncoding( 0246, "paragraph" ); addCharacterEncoding( 050, "parenleft" ); addCharacterEncoding( 051, "parenright" ); addCharacterEncoding( 045, "percent" ); addCharacterEncoding( 056, "period" ); addCharacterEncoding( 0341, "periodcentered" ); addCharacterEncoding( 0344, "perthousand" ); addCharacterEncoding( 053, "plus" ); addCharacterEncoding( 0261, "plusminus" ); addCharacterEncoding( 0161, "q" ); addCharacterEncoding( 077, "question" ); addCharacterEncoding( 0300, "questiondown" ); addCharacterEncoding( 042, "quotedbl" ); addCharacterEncoding( 0343, "quotedblbase" ); addCharacterEncoding( 0322, "quotedblleft" ); addCharacterEncoding( 0323, "quotedblright" ); addCharacterEncoding( 0324, "quoteleft" ); addCharacterEncoding( 0325, "quoteright" ); addCharacterEncoding( 0342, "quotesinglbase" ); addCharacterEncoding( 047, "quotesingle" ); addCharacterEncoding( 0162, "r" ); addCharacterEncoding( 0250, "registered" ); addCharacterEncoding( 0373, "ring" ); addCharacterEncoding( 0163, "s" ); addCharacterEncoding( 0244, "section" ); addCharacterEncoding( 073, "semicolon" ); addCharacterEncoding( 067, "seven" ); addCharacterEncoding( 066, "six" ); addCharacterEncoding( 057, "slash" ); addCharacterEncoding( 040, "space" ); addCharacterEncoding( 0243, "sterling" ); addCharacterEncoding( 0164, "t" ); addCharacterEncoding( 063, "three" ); addCharacterEncoding( 0367, "tilde" ); addCharacterEncoding( 0252, "trademark" ); addCharacterEncoding( 062, "two" ); addCharacterEncoding( 0165, "u" ); addCharacterEncoding( 0234, "uacute" ); addCharacterEncoding( 0236, "ucircumflex" ); addCharacterEncoding( 0237, "udieresis" ); addCharacterEncoding( 0235, "ugrave" ); addCharacterEncoding( 0137, "underscore" ); addCharacterEncoding( 0166, "v" ); addCharacterEncoding( 0167, "w" ); addCharacterEncoding( 0170, "x" ); addCharacterEncoding( 0171, "y" ); addCharacterEncoding( 0330, "ydieresis" ); addCharacterEncoding( 0264, "yen" ); addCharacterEncoding( 0172, "z" ); addCharacterEncoding( 060, "zero" ); // adding an additional mapping as defined in Appendix D of the pdf spec // we must not add it to both mappings as the nameToCode mapping // wouldn't be unique codeToName.put(0312, "space"); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return COSName.MAC_ROMAN_ENCODING; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/SingleByteCharset.java0000644000000000000000000001401212645757432027017 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; /** * {@link Charset} implementation for the single-byte encodings. * @version $Revision$ */ public class SingleByteCharset extends Charset { /** Unicode replacement character 0xFFFD. */ protected static final char REPLACEMENT_CHARACTER = '\uFFFD'; private final char[] toUnicodeMap; private byte[][] toByteMap; /** * Creates a new single-byte charset using an array of unicode characters. * @param canonicalName the canonical name * @param aliases An array of this charset's aliases, or null if it has no aliases * @param toUnicodeMap the array of unicode characters (may have a maximum of 256 characters, * first character must be 0x0000) */ protected SingleByteCharset(String canonicalName, String[] aliases, char[] toUnicodeMap) { super(canonicalName, aliases); if (toUnicodeMap.length > 256) { throw new IllegalArgumentException("Single-byte encodings may have at most 256 characters."); } //Copy array so it cannot be changed accidentally from the outside this.toUnicodeMap = new char[256]; System.arraycopy(toUnicodeMap, 0, this.toUnicodeMap, 0, toUnicodeMap.length); //build the inverse lookup table initInverseMap(); } private void initInverseMap() { toByteMap = new byte[256][]; if (toUnicodeMap[0] != '\u0000') { throw new IllegalArgumentException("First character in map must be a NUL (0x0000) character."); //because we're using 0x00 for encoding otherwise unmapped characters } //we're building a kind of sparse lookup table in which not all subranges are covered. for (int i = 1, len = toUnicodeMap.length; i < len; i++) { char ch = toUnicodeMap[i]; if (ch == REPLACEMENT_CHARACTER) { continue; //skip } int upper = ch >> 8; int lower = ch & 0xFF; if (upper > 0xFF) { throw new IllegalArgumentException("Not a compatible character: " + ch + " (" + Integer.toHexString(ch) + ")"); } byte[] map = toByteMap[upper]; if (map == null) { map = new byte[256]; toByteMap[upper] = map; } map[lower] = (byte)(i & 0xFF); } } /** {@inheritDoc} */ @Override public boolean contains(Charset cs) { return (cs.getClass() == getClass()); } /** {@inheritDoc} */ @Override public CharsetDecoder newDecoder() { return new Decoder(); } /** {@inheritDoc} */ @Override public CharsetEncoder newEncoder() { return new Encoder(); } /** The decoder. */ private class Decoder extends CharsetDecoder { protected Decoder() { super(SingleByteCharset.this, 1, 1); } @Override protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { while (in.hasRemaining()) { byte b = in.get(); char ch; if (!out.hasRemaining()) { in.position(in.position() - 1); return CoderResult.OVERFLOW; } ch = toUnicodeMap[b & 0xFF]; if (ch == REPLACEMENT_CHARACTER) { in.position(in.position() - 1); return CoderResult.unmappableForLength(1); } out.put(ch); } return CoderResult.UNDERFLOW; } } /** The encoder. */ private class Encoder extends CharsetEncoder { protected Encoder() { super(SingleByteCharset.this, 1, 1); } @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { while (in.hasRemaining()) { int ch = in.get(); if (!out.hasRemaining()) { in.position(in.position() - 1); return CoderResult.OVERFLOW; } int upper = ch >> 8; int lower = ch & 0xFF; if (upper > 0xFF) { in.position(in.position() - 1); return CoderResult.unmappableForLength(1); } byte[] map = toByteMap[upper]; if (map == null) { in.position(in.position() - 1); return CoderResult.unmappableForLength(1); } byte b = map[lower]; if (b == 0x00) { in.position(in.position() - 1); return CoderResult.unmappableForLength(1); } out.put(b); } return CoderResult.UNDERFLOW; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/EncodingManager.java0000644000000000000000000000446012645757432026467 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import java.io.IOException; import org.apache.pdfbox.cos.COSName; /** * This class will handle getting the appropriate encodings. * * @author Ben Litchfield * @version $Revision: 1.9 $ */ public class EncodingManager { /** * Default singleton instance of this class. * * @since Apache PDFBox 1.3.0 */ public static final EncodingManager INSTANCE = new EncodingManager(); /** * This will get the standard encoding. * * @return The standard encoding. */ public Encoding getStandardEncoding() { return StandardEncoding.INSTANCE; } /** * This will get an encoding by name. * * @param name The name of the encoding to get. * @return The encoding that matches the name. * @throws IOException if there is no encoding with that name. */ public Encoding getEncoding( COSName name ) throws IOException { if (COSName.STANDARD_ENCODING.equals(name)) { return StandardEncoding.INSTANCE; } else if (COSName.WIN_ANSI_ENCODING.equals(name)) { return WinAnsiEncoding.INSTANCE; } else if (COSName.MAC_ROMAN_ENCODING.equals(name)) { return MacRomanEncoding.INSTANCE; } else if (COSName.PDF_DOC_ENCODING.equals(name)) { return PdfDocEncoding.INSTANCE; } else { throw new IOException( "Unknown encoding for '" + name.getName() + "'"); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/PdfDocEncoding.java0000644000000000000000000003037412645757432026257 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; /** * This is an interface to a text encoder. * * @author Ben Litchfield * @version $Revision: 1.10 $ */ public class PdfDocEncoding extends Encoding { /** * Singleton instance of this class. * * @since Apache PDFBox 1.3.0 */ public static final PdfDocEncoding INSTANCE = new PdfDocEncoding(); /** * Constructor. */ public PdfDocEncoding() { addCharacterEncoding( 0101, "A" ); addCharacterEncoding( 0306, "AE" ); addCharacterEncoding( 0301, "Aacute" ); addCharacterEncoding( 0302, "Acircumflex" ); addCharacterEncoding( 0304, "Adieresis" ); addCharacterEncoding( 0300, "Agrave" ); addCharacterEncoding( 0305, "Aring" ); addCharacterEncoding( 0303, "Atilde" ); addCharacterEncoding( 0102, "B" ); addCharacterEncoding( 0103, "C" ); addCharacterEncoding( 0307, "Ccedilla" ); addCharacterEncoding( 0104, "D" ); addCharacterEncoding( 0105, "E" ); addCharacterEncoding( 0311, "Eacute" ); addCharacterEncoding( 0312, "Ecircumflex" ); addCharacterEncoding( 0313, "Edieresis" ); addCharacterEncoding( 0310, "Egrave" ); addCharacterEncoding( 0320, "Eth" ); addCharacterEncoding( 0240, "Euro" ); addCharacterEncoding( 0106, "F" ); addCharacterEncoding( 0107, "G" ); addCharacterEncoding( 0110, "H" ); addCharacterEncoding( 0111, "I" ); addCharacterEncoding( 0315, "Iacute" ); addCharacterEncoding( 0316, "Icircumflex" ); addCharacterEncoding( 0317, "Idieresis" ); addCharacterEncoding( 0314, "Igrave" ); addCharacterEncoding( 0112, "J" ); addCharacterEncoding( 0113, "K" ); addCharacterEncoding( 0114, "L" ); addCharacterEncoding( 0225, "Lslash" ); addCharacterEncoding( 0115, "M" ); addCharacterEncoding( 0116, "N" ); addCharacterEncoding( 0321, "Ntilde" ); addCharacterEncoding( 0117, "O" ); addCharacterEncoding( 0226, "OE" ); addCharacterEncoding( 0323, "Oacute" ); addCharacterEncoding( 0324, "Ocircumflex" ); addCharacterEncoding( 0326, "Odieresis" ); addCharacterEncoding( 0322, "Ograve" ); addCharacterEncoding( 0330, "Oslash" ); addCharacterEncoding( 0325, "Otilde" ); addCharacterEncoding( 0120, "P" ); addCharacterEncoding( 0121, "Q" ); addCharacterEncoding( 0122, "R" ); addCharacterEncoding( 0123, "S" ); addCharacterEncoding( 0227, "Scaron" ); addCharacterEncoding( 0124, "T" ); addCharacterEncoding( 0336, "Thorn" ); addCharacterEncoding( 0125, "U" ); addCharacterEncoding( 0332, "Uacute" ); addCharacterEncoding( 0333, "Ucircumflex" ); addCharacterEncoding( 0334, "Udieresis" ); addCharacterEncoding( 0331, "Ugrave" ); addCharacterEncoding( 0126, "V" ); addCharacterEncoding( 0127, "W" ); addCharacterEncoding( 0130, "X" ); addCharacterEncoding( 0131, "Y" ); addCharacterEncoding( 0335, "Yacute" ); addCharacterEncoding( 0230, "Ydieresis" ); addCharacterEncoding( 0132, "Z" ); addCharacterEncoding( 0231, "Zcaron" ); addCharacterEncoding( 0141, "a" ); addCharacterEncoding( 0341, "aacute" ); addCharacterEncoding( 0342, "acircumflex" ); addCharacterEncoding( 0264, "acute" ); addCharacterEncoding( 0344, "adieresis" ); addCharacterEncoding( 0346, "ae" ); addCharacterEncoding( 0340, "agrave" ); addCharacterEncoding( 046, "ampersand" ); addCharacterEncoding( 0345, "aring" ); addCharacterEncoding( 0136, "asciicircum" ); addCharacterEncoding( 0176, "asciitilde" ); addCharacterEncoding( 052, "asterisk" ); addCharacterEncoding( 0100, "at" ); addCharacterEncoding( 0343, "atilde" ); addCharacterEncoding( 0142, "b" ); addCharacterEncoding( 0134, "backslash" ); addCharacterEncoding( 0174, "bar" ); addCharacterEncoding( 0173, "braceleft" ); addCharacterEncoding( 0175, "braceright" ); addCharacterEncoding( 0133, "bracketleft" ); addCharacterEncoding( 0135, "bracketright" ); addCharacterEncoding( 030, "breve" ); addCharacterEncoding( 0246, "brokenbar" ); addCharacterEncoding( 0200, "bullet" ); addCharacterEncoding( 0143, "c" ); addCharacterEncoding( 031, "caron" ); addCharacterEncoding( 0347, "ccedilla" ); addCharacterEncoding( 0270, "cedilla" ); addCharacterEncoding( 0242, "cent" ); addCharacterEncoding( 032, "circumflex" ); addCharacterEncoding( 072, "colon" ); addCharacterEncoding( 054, "comma" ); addCharacterEncoding( 0251, "copyright" ); addCharacterEncoding( 0244, "currency" ); addCharacterEncoding( 0144, "d" ); addCharacterEncoding( 0201, "dagger" ); addCharacterEncoding( 0202, "daggerdbl" ); addCharacterEncoding( 0260, "degree" ); addCharacterEncoding( 0250, "dieresis" ); addCharacterEncoding( 0367, "divide" ); addCharacterEncoding( 044, "dollar" ); addCharacterEncoding( 033, "dotaccent" ); addCharacterEncoding( 0232, "dotlessi" ); addCharacterEncoding( 0145, "e" ); addCharacterEncoding( 0351, "eacute" ); addCharacterEncoding( 0352, "ecircumflex" ); addCharacterEncoding( 0353, "edieresis" ); addCharacterEncoding( 0350, "egrave" ); addCharacterEncoding( 070, "eight" ); addCharacterEncoding( 0203, "ellipsis" ); addCharacterEncoding( 0204, "emdash" ); addCharacterEncoding( 0205, "endash" ); addCharacterEncoding( 075, "equal" ); addCharacterEncoding( 0360, "eth" ); addCharacterEncoding( 041, "exclam" ); addCharacterEncoding( 0241, "exclamdown" ); addCharacterEncoding( 0146, "f" ); addCharacterEncoding( 0223, "fi" ); addCharacterEncoding( 065, "five" ); addCharacterEncoding( 0224, "fl" ); addCharacterEncoding( 0206, "florin" ); addCharacterEncoding( 064, "four" ); addCharacterEncoding( 0207, "fraction" ); addCharacterEncoding( 0147, "g" ); addCharacterEncoding( 0337, "germandbls" ); addCharacterEncoding( 0140, "grave" ); addCharacterEncoding( 076, "greater" ); addCharacterEncoding( 0253, "guillemotleft" ); addCharacterEncoding( 0273, "guillemotright" ); addCharacterEncoding( 0210, "guilsinglleft" ); addCharacterEncoding( 0211, "guilsinglright" ); addCharacterEncoding( 0150, "h" ); addCharacterEncoding( 034, "hungarumlaut" ); addCharacterEncoding( 055, "hyphen" ); addCharacterEncoding( 0151, "i" ); addCharacterEncoding( 0355, "iacute" ); addCharacterEncoding( 0356, "icircumflex" ); addCharacterEncoding( 0357, "idieresis" ); addCharacterEncoding( 0354, "igrave" ); addCharacterEncoding( 0152, "j" ); addCharacterEncoding( 0153, "k" ); addCharacterEncoding( 0154, "l" ); addCharacterEncoding( 074, "less" ); addCharacterEncoding( 0254, "logicalnot" ); addCharacterEncoding( 0233, "lslash" ); addCharacterEncoding( 0155, "m" ); addCharacterEncoding( 0257, "macron" ); addCharacterEncoding( 0212, "minus" ); addCharacterEncoding( 0265, "mu" ); addCharacterEncoding( 0327, "multiply" ); addCharacterEncoding( 0156, "n" ); addCharacterEncoding( 071, "nine" ); addCharacterEncoding( 0361, "ntilde" ); addCharacterEncoding( 043, "numbersign" ); addCharacterEncoding( 0157, "o" ); addCharacterEncoding( 0363, "oacute" ); addCharacterEncoding( 0364, "ocircumflex" ); addCharacterEncoding( 0366, "odieresis" ); addCharacterEncoding( 0234, "oe" ); addCharacterEncoding( 035, "ogonek" ); addCharacterEncoding( 0362, "ograve" ); addCharacterEncoding( 061, "one" ); addCharacterEncoding( 0275, "onehalf" ); addCharacterEncoding( 0274, "onequarter" ); addCharacterEncoding( 0271, "onesuperior" ); addCharacterEncoding( 0252, "ordfeminine" ); addCharacterEncoding( 0272, "ordmasculine" ); addCharacterEncoding( 0370, "oslash" ); addCharacterEncoding( 0365, "otilde" ); addCharacterEncoding( 0160, "p" ); addCharacterEncoding( 0266, "paragraph" ); addCharacterEncoding( 050, "parenleft" ); addCharacterEncoding( 051, "parenright" ); addCharacterEncoding( 045, "percent" ); addCharacterEncoding( 056, "period" ); addCharacterEncoding( 0267, "periodcentered" ); addCharacterEncoding( 0213, "perthousand" ); addCharacterEncoding( 053, "plus" ); addCharacterEncoding( 0261, "plusminus" ); addCharacterEncoding( 0161, "q" ); addCharacterEncoding( 077, "question" ); addCharacterEncoding( 0277, "questiondown" ); addCharacterEncoding( 042, "quotedbl" ); addCharacterEncoding( 0214, "quotedblbase" ); addCharacterEncoding( 0215, "quotedblleft" ); addCharacterEncoding( 0216, "quotedblright" ); addCharacterEncoding( 0217, "quoteleft" ); addCharacterEncoding( 0220, "quoteright" ); addCharacterEncoding( 0221, "quotesinglbase" ); addCharacterEncoding( 047, "quotesingle" ); addCharacterEncoding( 0162, "r" ); addCharacterEncoding( 0256, "registered" ); addCharacterEncoding( 036, "ring" ); addCharacterEncoding( 0163, "s" ); addCharacterEncoding( 0235, "scaron" ); addCharacterEncoding( 0247, "section" ); addCharacterEncoding( 073, "semicolon" ); addCharacterEncoding( 067, "seven" ); addCharacterEncoding( 066, "six" ); addCharacterEncoding( 057, "slash" ); addCharacterEncoding( 040, "space" ); addCharacterEncoding( 0243, "sterling" ); addCharacterEncoding( 0164, "t" ); addCharacterEncoding( 0376, "thorn" ); addCharacterEncoding( 063, "three" ); addCharacterEncoding( 0276, "threequarters" ); addCharacterEncoding( 0263, "threesuperior" ); addCharacterEncoding( 037, "tilde" ); addCharacterEncoding( 0222, "trademark" ); addCharacterEncoding( 062, "two" ); addCharacterEncoding( 0262, "twosuperior" ); addCharacterEncoding( 0165, "u" ); addCharacterEncoding( 0372, "uacute" ); addCharacterEncoding( 0373, "ucircumflex" ); addCharacterEncoding( 0374, "udieresis" ); addCharacterEncoding( 0371, "ugrave" ); addCharacterEncoding( 0137, "underscore" ); addCharacterEncoding( 0166, "v" ); addCharacterEncoding( 0167, "w" ); addCharacterEncoding( 0170, "x" ); addCharacterEncoding( 0171, "y" ); addCharacterEncoding( 0375, "yacute" ); addCharacterEncoding( 0377, "ydieresis" ); addCharacterEncoding( 0245, "yen" ); addCharacterEncoding( 0172, "z" ); addCharacterEncoding( 0236, "zcaron" ); addCharacterEncoding( 060, "zero" ); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return COSName.PDF_DOC_ENCODING; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encoding/AFMEncoding.java0000644000000000000000000000357712645757432025530 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encoding; import java.util.Iterator; import org.apache.fontbox.afm.CharMetric; import org.apache.fontbox.afm.FontMetric; import org.apache.pdfbox.cos.COSBase; /** * This will handle the encoding from an AFM font. * * @author Ben Litchfield * @version $Revision: 1.8 $ */ public class AFMEncoding extends Encoding { private FontMetric metric = null; /** * Constructor. * * @param fontInfo The font metric information. */ public AFMEncoding( FontMetric fontInfo ) { metric = fontInfo; Iterator characters = metric.getCharMetrics().iterator(); while( characters.hasNext() ) { CharMetric nextMetric = (CharMetric)characters.next(); addCharacterEncoding( nextMetric.getCharacterCode(), nextMetric.getName() ); } } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/WriteDecodedDoc.java0000644000000000000000000001512712645757432024652 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import java.io.File; import java.io.IOException; import java.util.Iterator; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.exceptions.COSVisitorException; /** * load document and write with all streams decoded. * * @author Michael Traut * @version $Revision: 1.8 $ */ public class WriteDecodedDoc { private static final String PASSWORD = "-password"; private static final String NONSEQ = "-nonSeq"; /** * Constructor. */ public WriteDecodedDoc() { super(); } /** * This will perform the document reading, decoding and writing. * * @param in The filename used for input. * @param out The filename used for output. * * @throws IOException If there is an error parsing the document. * @throws COSVisitorException If there is an error while copying the document. * * @deprecated use {@link WriteDecodedDoc#doIt(String, String, String, boolean)} instead. */ public void doIt(String in, String out) throws IOException, COSVisitorException { doIt(in, out, "", false); } /** * This will perform the document reading, decoding and writing. * * @param in The filename used for input. * @param out The filename used for output. * @param password The password to open the document. * @param useNonSeqParser use the non sequential parser * * @throws IOException If there is an error parsing the document. * @throws COSVisitorException If there is an error while copying the document. */ public void doIt(String in, String out, String password, boolean useNonSeqParser) throws IOException, COSVisitorException { PDDocument doc = null; try { if (useNonSeqParser) { doc = PDDocument.loadNonSeq(new File(in), null, password); doc.setAllSecurityToBeRemoved(true); } else { doc = PDDocument.load( in ); if( doc.isEncrypted() ) { try { doc.decrypt( password ); doc.setAllSecurityToBeRemoved(true); } catch( org.apache.pdfbox.exceptions.CryptographyException e ) { e.printStackTrace(); return; } } } for (Iterator i = doc.getDocument().getObjects().iterator(); i.hasNext();) { COSBase base = ((COSObject) i.next()).getObject(); if (base instanceof COSStream) { // just kill the filters COSStream cosStream = (COSStream)base; cosStream.getUnfilteredStream(); cosStream.setFilters(null); } } doc.save( out ); } finally { if( doc != null ) { doc.close(); } } } /** * This will write a PDF document with completely decoded streams. *
* see usage() for commandline * * @param args command line arguments */ public static void main(String[] args) { WriteDecodedDoc app = new WriteDecodedDoc(); String password = ""; boolean useNonSeqParser = false; String pdfFile = null; String outputFile = null; for( int i=0; i= args.length ) { usage(); } password = args[i]; } else if( args[i].equals( NONSEQ ) ) { useNonSeqParser = true; } else { if( pdfFile == null ) { pdfFile = args[i]; } else { outputFile = args[i]; } } } if( pdfFile == null ) { usage(); } else { try { if (outputFile == null) { outputFile = calculateOutputFilename(pdfFile); } app.doIt(pdfFile, outputFile, password, useNonSeqParser); } catch (Exception e) { e.printStackTrace(); } } } private static String calculateOutputFilename(String filename) { String outputFilename; if (filename.toLowerCase().endsWith(".pdf")) { outputFilename = filename.substring(0,filename.length()-4); } else { outputFilename = filename; } outputFilename += "_unc.pdf"; return outputFilename; } /** * This will print out a message telling how to use this example. */ private static void usage() { System.err.println( "usage: java -jar pdfbox-app-x.y.z.jar WriteDecodedDoc [OPTIONS] [output-file]\n" + " -password Password to decrypt the document\n" + " -nonSeq Enables the new non-sequential parser\n" + " The PDF document to be decompressed\n" + " [output-file] The filename for the decompressed pdf\n" ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/PDFDebugger.java0000644000000000000000000003411012645757432023731 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import org.apache.pdfbox.pdfviewer.PDFTreeModel; import org.apache.pdfbox.pdfviewer.PDFTreeCellRenderer; import org.apache.pdfbox.pdfviewer.ArrayEntry; import org.apache.pdfbox.pdfviewer.MapEntry; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.util.ExtensionFileFilter; import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNull; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; //import javax.swing.tree.*; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import javax.swing.JFileChooser; import javax.swing.JScrollPane; import javax.swing.JPanel; import javax.swing.UIManager; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.io.IOException; /** * * @author wurtz * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDFDebugger extends javax.swing.JFrame { private File currentDir=new File("."); private PDDocument document = null; private static final String NONSEQ = "-nonSeq"; private static final String PASSWORD = "-password"; private static boolean useNonSeqParser = false; /** * Constructor. */ public PDFDebugger() { initComponents(); } /** * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() { jSplitPane1 = new javax.swing.JSplitPane(); jScrollPane1 = new javax.swing.JScrollPane(); jTree1 = new javax.swing.JTree(); jScrollPane2 = new javax.swing.JScrollPane(); jTextPane1 = new javax.swing.JTextPane(); menuBar = new javax.swing.JMenuBar(); fileMenu = new javax.swing.JMenu(); openMenuItem = new javax.swing.JMenuItem(); saveMenuItem = new javax.swing.JMenuItem(); saveAsMenuItem = new javax.swing.JMenuItem(); exitMenuItem = new javax.swing.JMenuItem(); editMenu = new javax.swing.JMenu(); cutMenuItem = new javax.swing.JMenuItem(); copyMenuItem = new javax.swing.JMenuItem(); pasteMenuItem = new javax.swing.JMenuItem(); deleteMenuItem = new javax.swing.JMenuItem(); helpMenu = new javax.swing.JMenu(); contentsMenuItem = new javax.swing.JMenuItem(); aboutMenuItem = new javax.swing.JMenuItem(); jTree1.setCellRenderer( new PDFTreeCellRenderer() ); jTree1.setModel( null ); setTitle("PDFBox - PDF Viewer"); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jScrollPane1.setBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED)); jScrollPane1.setPreferredSize(new java.awt.Dimension(300, 500)); jTree1.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() { public void valueChanged(javax.swing.event.TreeSelectionEvent evt) { jTree1ValueChanged(evt); } }); jScrollPane1.setViewportView(jTree1); jSplitPane1.setRightComponent(jScrollPane2); jScrollPane2.setPreferredSize(new java.awt.Dimension(300, 500)); jScrollPane2.setViewportView(jTextPane1); jSplitPane1.setLeftComponent(jScrollPane1); JScrollPane documentScroller = new JScrollPane(); //documentScroller.setPreferredSize( new Dimension( 300, 500 ) ); documentScroller.setViewportView( documentPanel ); getContentPane().add( jSplitPane1, java.awt.BorderLayout.CENTER ); fileMenu.setText("File"); openMenuItem.setText("Open"); openMenuItem.setToolTipText("Open PDF file"); openMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openMenuItemActionPerformed(evt); } }); fileMenu.add(openMenuItem); saveMenuItem.setText("Save"); saveAsMenuItem.setText("Save As ..."); exitMenuItem.setText("Exit"); exitMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { exitMenuItemActionPerformed(evt); } }); fileMenu.add(exitMenuItem); menuBar.add(fileMenu); editMenu.setText("Edit"); cutMenuItem.setText("Cut"); editMenu.add(cutMenuItem); copyMenuItem.setText("Copy"); editMenu.add(copyMenuItem); pasteMenuItem.setText("Paste"); editMenu.add(pasteMenuItem); deleteMenuItem.setText("Delete"); editMenu.add(deleteMenuItem); helpMenu.setText("Help"); contentsMenuItem.setText("Contents"); helpMenu.add(contentsMenuItem); aboutMenuItem.setText("About"); helpMenu.add(aboutMenuItem); setJMenuBar(menuBar); java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); setBounds((screenSize.width-700)/2, (screenSize.height-600)/2, 700, 600); }//GEN-END:initComponents private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) { JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(currentDir); ExtensionFileFilter pdfFilter = new ExtensionFileFilter(new String[] {"pdf", "PDF"}, "PDF Files"); chooser.setFileFilter(pdfFilter); int result = chooser.showOpenDialog(PDFDebugger.this); if (result == JFileChooser.APPROVE_OPTION) { String name = chooser.getSelectedFile().getPath(); currentDir = new File(name).getParentFile(); try { readPDFFile(name, ""); } catch (Exception e) { e.printStackTrace(); } } }//GEN-LAST:event_openMenuItemActionPerformed private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) { TreePath path = jTree1.getSelectionPath(); if (path != null) { try { Object selectedNode = path.getLastPathComponent(); String data=convertToString(selectedNode); if (data != null) { jTextPane1.setText(data); } else { jTextPane1.setText( "" ); } } catch (Exception e) { e.printStackTrace(); } } }//GEN-LAST:event_jTree1ValueChanged private String convertToString( Object selectedNode ) { String data = null; if(selectedNode instanceof COSBoolean) { data = "" + ((COSBoolean)selectedNode).getValue(); } else if( selectedNode instanceof COSFloat ) { data = "" + ((COSFloat)selectedNode).floatValue(); } else if( selectedNode instanceof COSNull ) { data = "null"; } else if( selectedNode instanceof COSInteger ) { data = "" + ((COSInteger)selectedNode).intValue(); } else if( selectedNode instanceof COSName ) { data = "" + ((COSName)selectedNode).getName(); } else if( selectedNode instanceof COSString ) { data = "" + ((COSString)selectedNode).getString(); } else if( selectedNode instanceof COSStream ) { try { COSStream stream = (COSStream)selectedNode; InputStream ioStream = stream.getUnfilteredStream(); ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int amountRead = 0; while( (amountRead = ioStream.read( buffer, 0, buffer.length ) ) != -1 ) { byteArray.write( buffer, 0, amountRead ); } data = byteArray.toString(); } catch( IOException e ) { e.printStackTrace(); } } else if( selectedNode instanceof MapEntry ) { data = convertToString( ((MapEntry)selectedNode).getValue() ); } else if( selectedNode instanceof ArrayEntry ) { data = convertToString( ((ArrayEntry)selectedNode).getValue() ); } return data; } private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) { if( document != null ) { try { document.close(); } catch( IOException io ) { io.printStackTrace(); } } System.exit(0); } /** * Exit the Application. */ private void exitForm(java.awt.event.WindowEvent evt) { if( document != null ) { try { document.close(); } catch( IOException io ) { io.printStackTrace(); } } System.exit(0); } /** * @param args the command line arguments * * @throws Exception If anything goes wrong. */ public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); PDFDebugger viewer = new PDFDebugger(); String filename = null; String password = ""; for( int i = 0; i < args.length; i++ ) { if( args[i].equals( PASSWORD ) ) { i++; if( i >= args.length ) { usage(); } password = args[i]; } if( args[i].equals( NONSEQ ) ) { useNonSeqParser = true; } else { filename = args[i]; } } if (filename != null) { viewer.readPDFFile( filename, password ); } viewer.setVisible(true); } private void readPDFFile(String file, String password) throws Exception { if( document != null ) { document.close(); } File f = new File( file ); parseDocument( f, password ); TreeModel model=new PDFTreeModel(document); jTree1.setModel(model); setTitle( "PDFBox - " + f.getAbsolutePath() ); } /** * This will parse a document. * * @param input The file addressing the document. * * @throws IOException If there is an error parsing the document. */ private void parseDocument( File file, String password )throws IOException { if (useNonSeqParser) { document = PDDocument.loadNonSeq(file, null, password); } else { document = PDDocument.load( file ); if( document.isEncrypted() ) { try { document.decrypt( password ); } catch( org.apache.pdfbox.exceptions.CryptographyException e ) { e.printStackTrace(); } } } } /** * This will print out a message telling how to use this utility. */ private static void usage() { System.err.println( "usage: java -jar pdfbox-app-x.y.z.jar PDFDebugger [OPTIONS] \n" + " -password Password to decrypt the document\n" + " -nonSeq Enables the new non-sequential parser\n" + " The PDF document to be loaded\n" ); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem aboutMenuItem; private javax.swing.JMenuItem contentsMenuItem; private javax.swing.JMenuItem copyMenuItem; private javax.swing.JMenuItem cutMenuItem; private javax.swing.JMenuItem deleteMenuItem; private javax.swing.JMenu editMenu; private javax.swing.JMenuItem exitMenuItem; private javax.swing.JMenu fileMenu; private javax.swing.JMenu helpMenu; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JTextPane jTextPane1; private javax.swing.JTree jTree1; private javax.swing.JMenuBar menuBar; private javax.swing.JMenuItem openMenuItem; private javax.swing.JMenuItem pasteMenuItem; private javax.swing.JMenuItem saveAsMenuItem; private javax.swing.JMenuItem saveMenuItem; private JPanel documentPanel = new JPanel(); // End of variables declaration//GEN-END:variables } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/ExportXFDF.java0000644000000000000000000000761312645757432023614 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import java.io.IOException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.fdf.FDFDocument; /** * This example will take a PDF document and fill the fields with data from the * FDF fields. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class ExportXFDF { /** * Creates a new instance of ImportFDF. */ public ExportXFDF() { } /** * This will import an fdf document and write out another pdf. *
* see usage() for commandline * * @param args command line arguments * * @throws Exception If there is an error importing the FDF document. */ public static void main(String[] args) throws Exception { ExportXFDF exporter = new ExportXFDF(); exporter.exportXFDF( args ); } private void exportXFDF( String[] args ) throws Exception { PDDocument pdf = null; FDFDocument fdf = null; try { if( args.length != 1 && args.length != 2 ) { usage(); } else { pdf = PDDocument.load( args[0] ); PDAcroForm form = pdf.getDocumentCatalog().getAcroForm(); if( form == null ) { System.err.println( "Error: This PDF does not contain a form." ); } else { String fdfName = null; if( args.length == 2 ) { fdfName = args[1]; } else { if( args[0].length() > 4 ) { fdfName = args[0].substring( 0, args[0].length() -4 ) + ".xfdf"; } } fdf = form.exportFDF(); fdf.saveXFDF( fdfName ); } } } finally { close( fdf ); close( pdf ); } } /** * This will print out a message telling how to use this example. */ private static void usage() { System.err.println( "usage: org.apache.pdfbox.ExortXFDF [output-xfdf-file]" ); System.err.println( " [output-xfdf-file] - Default is pdf name, test.pdf->test.xfdf" ); } /** * Close the document. * * @param doc The doc to close. * * @throws IOException If there is an error closing the document. */ public void close( FDFDocument doc ) throws IOException { if( doc != null ) { doc.close(); } } /** * Close the document. * * @param doc The doc to close. * * @throws IOException If there is an error closing the document. */ public void close( PDDocument doc ) throws IOException { if( doc != null ) { doc.close(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/0000755000000000000000000000000012645757432023004 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PDFTreeModel.java0000644000000000000000000002425212645757432026066 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; /** * A tree model that uses a cos document. * * * @author wurtz * @author Ben Litchfield * @version $Revision: 1.9 $ */ import javax.swing.tree.TreePath; import javax.swing.tree.TreeModel; //import java.awt.event.*; import javax.swing.event.TreeModelListener; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.pdmodel.PDDocument; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * A class to model a PDF document as a tree structure. * * @author Ben Litchfield * @version $Revision: 1.9 $ */ public class PDFTreeModel implements TreeModel { private PDDocument document; /** * constructor. */ public PDFTreeModel() { //default constructor } /** * Constructor to take a document. * * @param doc The document to display in the tree. */ public PDFTreeModel(PDDocument doc) { setDocument(doc); } /** * Set the document to display in the tree. * * @param doc The document to display in the tree. */ public void setDocument(PDDocument doc) { document = doc; } /** * Adds a listener for the TreeModelEvent * posted after the tree changes. * * @param l the listener to add * @see #removeTreeModelListener * */ public void addTreeModelListener(TreeModelListener l) { //required for interface } /** * Returns the child of parent at index index * in the parent's * child array. parent must be a node previously obtained * from this data source. This should not return null * if index * is a valid index for parent (that is index >= 0 && * index < getChildCount(parent)). * * @param parent a node in the tree, obtained from this data source * @param index The index into the parent object to location the child object. * @return the child of parent at index index * */ public Object getChild(Object parent, int index) { Object retval = null; if( parent instanceof COSArray ) { ArrayEntry entry = new ArrayEntry(); entry.setIndex( index ); entry.setValue( ((COSArray)parent).getObject( index ) ); retval = entry; } else if( parent instanceof COSDictionary ) { COSDictionary dict = ((COSDictionary)parent); List keys = new ArrayList(dict.keySet()); Collections.sort( keys ); Object key = keys.get( index ); Object value = dict.getDictionaryObject( (COSName)key ); MapEntry entry = new MapEntry(); entry.setKey( key ); entry.setValue( value ); retval = entry; } else if( parent instanceof MapEntry ) { retval = getChild( ((MapEntry)parent).getValue(), index ); } else if( parent instanceof ArrayEntry ) { retval = getChild( ((ArrayEntry)parent).getValue(), index ); } else if( parent instanceof COSDocument ) { retval = ((COSDocument)parent).getObjects().get( index ); } else if( parent instanceof COSObject ) { retval = ((COSObject)parent).getObject(); } else { throw new RuntimeException( "Unknown COS type " + parent.getClass().getName() ); } return retval; } /** Returns the number of children of parent. * Returns 0 if the node * is a leaf or if it has no children. parent must be a node * previously obtained from this data source. * * @param parent a node in the tree, obtained from this data source * @return the number of children of the node parent * */ public int getChildCount(Object parent) { int retval = 0; if( parent instanceof COSArray ) { retval = ((COSArray)parent).size(); } else if( parent instanceof COSDictionary ) { retval = ((COSDictionary)parent).size(); } else if( parent instanceof MapEntry ) { retval = getChildCount( ((MapEntry)parent).getValue() ); } else if( parent instanceof ArrayEntry ) { retval = getChildCount( ((ArrayEntry)parent).getValue() ); } else if( parent instanceof COSDocument ) { retval = ((COSDocument)parent).getObjects().size(); } else if( parent instanceof COSObject ) { retval = 1; } return retval; } /** Returns the index of child in parent. If parent * is null or child is null, * returns -1. * * @param parent a note in the tree, obtained from this data source * @param child the node we are interested in * @return the index of the child in the parent, or -1 if either * child or parent are null * */ public int getIndexOfChild(Object parent, Object child) { int retval = -1; if( parent != null && child != null ) { if( parent instanceof COSArray ) { COSArray array = (COSArray)parent; if( child instanceof ArrayEntry ) { ArrayEntry arrayEntry = (ArrayEntry)child; retval = arrayEntry.getIndex(); } else { retval = array.indexOf( (COSBase)child ); } } else if( parent instanceof COSDictionary ) { MapEntry entry = (MapEntry)child; COSDictionary dict = (COSDictionary)parent; List keys = new ArrayList(dict.keySet()); Collections.sort( keys ); for( int i=0; retval == -1 && inull * only if the tree has no nodes. * * @return the root of the tree * */ public Object getRoot() { return document.getDocument().getTrailer(); } /** Returns true if node is a leaf. * It is possible for this method to return false * even if node has no children. * A directory in a filesystem, for example, * may contain no files; the node representing * the directory is not a leaf, but it also has no children. * * @param node a node in the tree, obtained from this data source * @return true if node is a leaf * */ public boolean isLeaf(Object node) { boolean isLeaf = !(node instanceof COSDictionary || node instanceof COSArray || node instanceof COSDocument || node instanceof COSObject || (node instanceof MapEntry && !isLeaf(((MapEntry)node).getValue()) ) || (node instanceof ArrayEntry && !isLeaf(((ArrayEntry)node).getValue()) )); return isLeaf; } /** Removes a listener previously added with * addTreeModelListener. * * @see #addTreeModelListener * @param l the listener to remove * */ public void removeTreeModelListener(TreeModelListener l) { //required for interface } /** Messaged when the user has altered the value for the item identified * by path to newValue. * If newValue signifies a truly new value * the model should post a treeNodesChanged event. * * @param path path to the node that the user has altered * @param newValue the new value from the TreeCellEditor * */ public void valueForPathChanged(TreePath path, Object newValue) { //required for interface } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/MapEntry.java0000644000000000000000000000426112645757432025411 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; import org.apache.pdfbox.cos.COSName; /** * This is a simple class that will contain a key and a value. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class MapEntry { private Object key; private Object value; /** * Get the key for this entry. * * @return The entry's key. */ public Object getKey() { return key; } /** * This will set the key for this entry. * * @param k the new key for this entry. */ public void setKey(Object k) { key = k; } /** * This will get the value for this entry. * * @return The value for this entry. */ public Object getValue() { return value; } /** * This will set the value for this entry. * * @param val the new value for this entry. */ public void setValue(Object val) { this.value = val; } /** * This will output a string representation of this class. * * @return A string representation of this class. */ public String toString() { String retval = null; if( key instanceof COSName ) { retval = ((COSName)key).getName(); } else { retval = "" +key; } return retval; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageWrapper.java0000644000000000000000000000626612645757432026076 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; import java.awt.Dimension; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.io.IOException; import javax.swing.JPanel; import org.apache.pdfbox.PDFReader; import org.apache.pdfbox.pdmodel.PDPage; /** * A class to handle some prettyness around a single PDF page. * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class PageWrapper implements MouseMotionListener { private JPanel pageWrapper = new JPanel(); private PDFPagePanel pagePanel = null; private PDFReader reader = null; private static final int SPACE_AROUND_DOCUMENT = 20; /** * Constructor. * * @param aReader The reader application that holds this page. * * @throws IOException If there is an error creating the page drawing objects. */ public PageWrapper( PDFReader aReader ) throws IOException { reader = aReader; pagePanel = new PDFPagePanel(); pageWrapper.setLayout( null ); pageWrapper.add( pagePanel ); pagePanel.setLocation( SPACE_AROUND_DOCUMENT, SPACE_AROUND_DOCUMENT ); pageWrapper.setBorder( javax.swing.border.LineBorder.createBlackLineBorder() ); pagePanel.addMouseMotionListener( this ); } /** * This will display the PDF page in this component. * * @param page The PDF page to display. */ public void displayPage( PDPage page ) { pagePanel.setPage( page ); pagePanel.setPreferredSize( pagePanel.getSize() ); Dimension d = pagePanel.getSize(); d.width+=(SPACE_AROUND_DOCUMENT*2); d.height+=(SPACE_AROUND_DOCUMENT*2); pageWrapper.setPreferredSize( d ); pageWrapper.validate(); } /** * This will get the JPanel that can be displayed. * * @return The panel with the displayed PDF page. */ public JPanel getPanel() { return pageWrapper; } /** * {@inheritDoc} */ public void mouseDragged(MouseEvent e) { //do nothing when mouse moves. } /** * {@inheritDoc} */ public void mouseMoved(MouseEvent e) { //reader.getBottomStatusPanel().getStatusLabel().setText( e.getX() + "," + (pagePanel.getHeight() - e.getY()) ); reader.getBottomStatusPanel().getStatusLabel().setText( e.getX() + "," + e.getY() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/package.html0000644000000000000000000000175512645757432025275 0ustar rootroot The pdfviewer package contains classes to graphically display information about a PDF document. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/ReaderBottomPanel.java0000644000000000000000000000407712645757432027226 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; import java.awt.Dimension; import javax.swing.JPanel; import javax.swing.JLabel; import java.awt.FlowLayout; /** * A panel to display at the bottom of the window for status and other stuff. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class ReaderBottomPanel extends JPanel { private JLabel statusLabel = null; /** * This is the default constructor. */ public ReaderBottomPanel() { super(); initialize(); } /** * This method initializes this. */ private void initialize() { FlowLayout flowLayout1 = new FlowLayout(); this.setLayout(flowLayout1); this.setComponentOrientation(java.awt.ComponentOrientation.LEFT_TO_RIGHT); this.setPreferredSize( new Dimension( 1000, 20 ) ); flowLayout1.setAlignment(java.awt.FlowLayout.LEFT); this.add(getStatusLabel(), null); } /** * This method initializes status label. * * @return javax.swing.JLabel */ public JLabel getStatusLabel() { if (statusLabel == null) { statusLabel = new JLabel(); statusLabel.setText("Ready"); } return statusLabel; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java0000644000000000000000000006461412645757432025703 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.geom.Area; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.Image; import java.io.IOException; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDMatrix; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; import org.apache.pdfbox.pdmodel.graphics.PDShading; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingResources; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType1; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType2; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType3; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType4; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType5; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType6; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType7; import org.apache.pdfbox.pdmodel.graphics.shading.Type1ShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.AxialShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.RadialShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.Type4ShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.Type5ShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.Type6ShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.Type7ShadingPaint; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.text.PDTextState; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFStreamEngine; import org.apache.pdfbox.util.ResourceLoader; import org.apache.pdfbox.util.TextPosition; import org.apache.pdfbox.cos.COSName; /** * This will paint a page in a PDF document to a graphics context. * * @author Ben Litchfield * @version $Revision: 1.22 $ */ public class PageDrawer extends PDFStreamEngine { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PageDrawer.class); private Graphics2D graphics; /** * clipping winding rule used for the clipping path. */ private int clippingWindingRule = -1; /** * Size of the page. */ protected Dimension pageSize; /** * Current page to be rendered. */ protected PDPage page; private GeneralPath linePath = new GeneralPath(); private BasicStroke stroke = null; /** * Default constructor, loads properties from file. * * @throws IOException If there is an error loading properties from the file. */ public PageDrawer() throws IOException { super( ResourceLoader.loadProperties( "org/apache/pdfbox/resources/PageDrawer.properties", true ) ); } /** * This will draw the page to the requested context. * * @param g The graphics context to draw onto. * @param p The page to draw. * @param pageDimension The size of the page to draw. * * @throws IOException If there is an IO error while drawing the page. */ public void drawPage( Graphics g, PDPage p, Dimension pageDimension ) throws IOException { graphics = (Graphics2D)g; page = p; pageSize = pageDimension; graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); graphics.setRenderingHint( RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON ); // initialize the used stroke with CAP_BUTT instead of CAP_SQUARE graphics.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER)); // Only if there is some content, we have to process it. // Otherwise we are done here and we will produce an empty page if ( page.getContents() != null) { PDResources resources = page.findResources(); processStream( page, resources, page.getContents().getStream() ); } List annotations = page.getAnnotations(); for( int i=0; i appearanceMap = appearDictionary.getNormalAppearance(); if (appearanceMap != null) { PDAppearanceStream appearance = (PDAppearanceStream)appearanceMap.get( appearanceName ); if( appearance != null ) { Point2D point = new Point2D.Float(rect.getLowerLeftX(), rect.getLowerLeftY()); Matrix matrix = appearance.getMatrix(); if (matrix != null) { // transform the rectangle using the given matrix AffineTransform at = matrix.createAffineTransform(); at.transform(point, point); } g.translate( (int)point.getX(), -(int)point.getY() ); processSubStream( page, appearance.getResources(), appearance.getStream() ); g.translate( -(int)point.getX(), (int)point.getY() ); } } } } } /** * Remove all cached resources. */ public void dispose() { graphics = null; linePath = null; page = null; pageSize = null; } /** * You should override this method if you want to perform an action when a * text is being processed. * * @param text The text to process */ protected void processTextPosition( TextPosition text ) { try { PDGraphicsState graphicsState = getGraphicsState(); Composite composite; Paint paint; switch(graphicsState.getTextState().getRenderingMode()) { case PDTextState.RENDERING_MODE_FILL_TEXT: composite = graphicsState.getNonStrokeJavaComposite(); paint = graphicsState.getNonStrokingColor().getJavaColor(); if (paint == null) { paint = graphicsState.getNonStrokingColor().getPaint(pageSize.height); } break; case PDTextState.RENDERING_MODE_STROKE_TEXT: composite = graphicsState.getStrokeJavaComposite(); paint = graphicsState.getStrokingColor().getJavaColor(); if (paint == null) { paint = graphicsState.getStrokingColor().getPaint(pageSize.height); } break; case PDTextState.RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT: //basic support for text rendering mode "invisible" Color nsc = graphicsState.getStrokingColor().getJavaColor(); float[] components = {Color.black.getRed(),Color.black.getGreen(),Color.black.getBlue()}; paint = new Color(nsc.getColorSpace(),components,0f); composite = graphicsState.getStrokeJavaComposite(); break; default: // TODO : need to implement.... LOG.debug("Unsupported RenderingMode " + this.getGraphicsState().getTextState().getRenderingMode() + " in PageDrawer.processTextPosition()." + " Using RenderingMode " + PDTextState.RENDERING_MODE_FILL_TEXT + " instead"); composite = graphicsState.getNonStrokeJavaComposite(); paint = graphicsState.getNonStrokingColor().getJavaColor(); } graphics.setComposite(composite); graphics.setPaint(paint); PDFont font = text.getFont(); Matrix textPos = text.getTextPos().copy(); float x = textPos.getXPosition(); // the 0,0-reference has to be moved from the lower left (PDF) to the upper left (AWT-graphics) float y = pageSize.height - textPos.getYPosition(); // Set translation to 0,0. We only need the scaling and shearing textPos.setValue(2, 0, 0); textPos.setValue(2, 1, 0); // because of the moved 0,0-reference, we have to shear in the opposite direction textPos.setValue(0, 1, (-1)*textPos.getValue(0, 1)); textPos.setValue(1, 0, (-1)*textPos.getValue(1, 0)); AffineTransform at = textPos.createAffineTransform(); PDMatrix fontMatrix = font.getFontMatrix(); at.scale(fontMatrix.getValue(0, 0) * 1000f, fontMatrix.getValue(1, 1) * 1000f); //TODO setClip() is a massive performance hot spot. Investigate optimization possibilities graphics.setClip(graphicsState.getCurrentClippingPath()); // the fontSize is no longer needed as it is already part of the transformation // we should remove it from the parameter list in the long run font.drawString( text.getCharacter(), text.getCodePoints(), graphics, 1, at, x, y ); } catch( IOException io ) { LOG.error (io, io); } } /** * Get the graphics that we are currently drawing on. * * @return The graphics we are drawing on. */ public Graphics2D getGraphics() { return graphics; } /** * Get the page that is currently being drawn. * * @return The page that is being drawn. */ public PDPage getPage() { return page; } /** * Get the size of the page that is currently being drawn. * * @return The size of the page that is being drawn. */ public Dimension getPageSize() { return pageSize; } /** * Fix the y coordinate. * * @param y The y coordinate. * @return The updated y coordinate. */ public double fixY( double y ) { return pageSize.getHeight() - y; } /** * Get the current line path to be drawn. * * @return The current line path to be drawn. */ public GeneralPath getLinePath() { return linePath; } /** * Set the line path to draw. * * @param newLinePath Set the line path to draw. */ public void setLinePath(GeneralPath newLinePath) { if (linePath == null || linePath.getCurrentPoint() == null) { linePath = newLinePath; } else { linePath.append(newLinePath, false); } } /** * Fill the path. * * @param windingRule The winding rule this path will use. * * @throws IOException If there is an IO error while filling the path. */ public void fillPath(int windingRule) throws IOException { graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite()); Paint nonStrokingPaint = getGraphicsState().getNonStrokingColor().getJavaColor(); if ( nonStrokingPaint == null ) { nonStrokingPaint = getGraphicsState().getNonStrokingColor().getPaint(pageSize.height); } if ( nonStrokingPaint == null ) { LOG.info("ColorSpace "+getGraphicsState().getNonStrokingColor().getColorSpace().getName() +" doesn't provide a non-stroking color, using white instead!"); nonStrokingPaint = Color.WHITE; } graphics.setPaint( nonStrokingPaint ); getLinePath().setWindingRule(windingRule); graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF ); graphics.setClip(getGraphicsState().getCurrentClippingPath()); if (!(graphics.getPaint() instanceof Color)) { // apply clip to path to avoid oversized device bounds in shading contexts (PDFBOX-XXXX) Area area = new Area(getLinePath()); area.intersect(new Area(graphics.getClip())); graphics.fill(area); } else { graphics.fill( getLinePath() ); } getLinePath().reset(); } /** * This will set the current stroke. * * @param newStroke The current stroke. * */ public void setStroke(BasicStroke newStroke) { stroke = newStroke; } /** * This will return the current stroke. * * @return The current stroke. * */ public BasicStroke getStroke() { return stroke; } /** * Create a new stroke based on the current ctm and the current stroke. * * @return the transformed stroke */ private BasicStroke calculateStroke() { float lineWidth = transformWidth((float) getGraphicsState().getLineWidth()); if (lineWidth < 0.25) { lineWidth = 0.25f; } BasicStroke currentStroke = null; if (stroke == null) { currentStroke = new BasicStroke(lineWidth); } else { float phaseStart = stroke.getDashPhase(); float[] dashArray = stroke.getDashArray(); if (dashArray != null) { // apply the CTM for (int i = 0; i < dashArray.length; ++i) { dashArray[i] = transformWidth(dashArray[i]); } phaseStart = (int)transformWidth(phaseStart); // empty dash array is illegal if (dashArray.length == 0) { dashArray = null; } } currentStroke = new BasicStroke(lineWidth, stroke.getEndCap(), stroke.getLineJoin(), stroke.getMiterLimit(), dashArray, phaseStart); } return currentStroke; } /** * Stroke the path. * * @throws IOException If there is an IO error while stroking the path. */ public void strokePath() throws IOException { graphics.setComposite(getGraphicsState().getStrokeJavaComposite()); Paint strokingPaint = getGraphicsState().getStrokingColor().getJavaColor(); if ( strokingPaint == null ) { strokingPaint = getGraphicsState().getStrokingColor().getPaint(pageSize.height); } if ( strokingPaint == null ) { LOG.info("ColorSpace "+getGraphicsState().getStrokingColor().getColorSpace().getName() +" doesn't provide a stroking color, using white instead!"); strokingPaint = Color.WHITE; } graphics.setPaint(strokingPaint); graphics.setStroke(calculateStroke()); graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF ); graphics.setClip(getGraphicsState().getCurrentClippingPath()); GeneralPath path = getLinePath(); graphics.draw( path ); path.reset(); } /** * Called when the color changed. * @param bStroking true for the stroking color, false for the non-stroking color * @throws IOException if an I/O error occurs */ @Deprecated public void colorChanged(boolean bStroking) throws IOException { //logger().info("changing " + (bStroking ? "" : "non") + "stroking color"); } //This code generalizes the code Jim Lynch wrote for AppendRectangleToPath /** * use the current transformation matrix to transform a single point. * @param x x-coordinate of the point to be transform * @param y y-coordinate of the point to be transform * @return the transformed coordinates as Point2D.Double */ public Point2D.Double transformedPoint(double x, double y) { double[] position = {x,y}; getGraphicsState().getCurrentTransformationMatrix().createAffineTransform().transform( position, 0, position, 0, 1); position[1] = fixY(position[1]); return new Point2D.Double(position[0],position[1]); } /** * Set the clipping Path. * * @param windingRule The winding rule this path will use. * * @deprecated use {@link #setClippingWindingRule(int)} instead * */ public void setClippingPath(int windingRule) { setClippingWindingRule(windingRule); } /** * Set the clipping winding rule. * * @param windingRule The winding rule which will be used for clipping. * */ public void setClippingWindingRule(int windingRule) { clippingWindingRule = windingRule; } /** * Set the clipping Path. * */ public void endPath() { if (clippingWindingRule > -1) { PDGraphicsState graphicsState = getGraphicsState(); GeneralPath clippingPath = (GeneralPath)getLinePath().clone(); // TODO do we really need to clone this? isn't the line path reset anyway? clippingPath.setWindingRule(clippingWindingRule); // If there is already set a clipping path, we have to intersect the new with the existing one if (graphicsState.getCurrentClippingPath() != null) { Area currentArea = new Area(getGraphicsState().getCurrentClippingPath()); Area newArea = new Area(clippingPath); currentArea.intersect(newArea); graphicsState.setCurrentClippingPath(currentArea); } else { graphicsState.setCurrentClippingPath(clippingPath); } clippingWindingRule = -1; } getLinePath().reset(); } /** * Draw the AWT image. Called by Invoke. * Moved into PageDrawer so that Invoke doesn't have to reach in here for Graphics as that breaks extensibility. * * @param awtImage The image to draw. * @param at The transformation to use when drawing. * */ public void drawImage(Image awtImage, AffineTransform at) { graphics.setComposite(getGraphicsState().getStrokeJavaComposite()); graphics.setClip(getGraphicsState().getCurrentClippingPath()); graphics.drawImage( awtImage, at, null ); } /** * Fill with Shading. Called by SHFill operator. * * @param ShadingName The name of the Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. * * @deprecated use {@link #shFill(COSName)} instead. */ public void SHFill(COSName ShadingName) throws IOException { shFill(ShadingName); } /** * Fill with Shading. Called by SHFill operator. * * @param shadingName The name of the Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the clipping area. */ public void shFill(COSName shadingName) throws IOException { PDShadingResources shading = getResources().getShadings().get(shadingName.getName()); LOG.debug("Shading = " + shading.toString()); int shadingType = shading.getShadingType(); Matrix ctm = getGraphicsState().getCurrentTransformationMatrix(); Paint paint = null; switch (shadingType) { case 1: paint = new Type1ShadingPaint((PDShadingType1)shading, ctm, pageSize.height); break; case 2: paint = new AxialShadingPaint((PDShadingType2)shading, ctm, pageSize.height); break; case 3: paint = new RadialShadingPaint((PDShadingType3)shading, ctm, pageSize.height); break; case 4: paint = new Type4ShadingPaint((PDShadingType4)shading, ctm, pageSize.height); break; case 5: paint = new Type5ShadingPaint((PDShadingType5)shading, ctm, pageSize.height); break; case 6: paint = new Type6ShadingPaint((PDShadingType6)shading, ctm, pageSize.height); break; case 7: paint = new Type7ShadingPaint((PDShadingType7)shading, ctm, pageSize.height); break; default: throw new IOException("Invalid ShadingType " + shadingType + " for Shading " + shadingName); } graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite()); graphics.setPaint(paint); graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF ); graphics.setClip(null); // PDFBOX-2153 don't use obsolete clipping path graphics.fill( getGraphicsState().getCurrentClippingPath() ); } /** * Fill with a Function-based gradient / shading. * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_Function(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } /** * Fill with an Axial Shading. * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_Axial(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } /** * Fill with a Radial gradient / shading. * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_Radial(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } /** * Fill with a Free-form Gourad-shaded triangle mesh. * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_FreeGourad(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } /** * Fill with a Lattice-form Gourad-shaded triangle mesh. * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_LatticeGourad(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } /** * Fill with a Coons patch mesh * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_CoonsPatch(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } /** * Fill with a Tensor-product patch mesh. * If extending the class, override this and its siblings, not the public SHFill method. * * @param Shading The Shading Dictionary to use for this fill instruction. * * @throws IOException If there is an IO error while shade-filling the path/clipping area. */ protected void SHFill_TensorPatch(PDShading Shading) throws IOException { throw new IOException("Not Implemented"); } private float transformWidth(float width) { Matrix ctm = getGraphicsState().getCurrentTransformationMatrix(); if (ctm == null) { // TODO does the CTM really need to use null? return width; } float x = ctm.getValue(0, 0) + ctm.getValue(1, 0); float y = ctm.getValue(0, 1) + ctm.getValue(1, 1); return width * (float) Math.sqrt((x * x + y * y) * 0.5); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PDFTreeCellRenderer.java0000644000000000000000000001027112645757432027370 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; import java.awt.Component; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNull; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; /** * A class to render tree cells for the pdfviewer. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class PDFTreeCellRenderer extends DefaultTreeCellRenderer { /** * {@inheritDoc} */ public Component getTreeCellRendererComponent( JTree tree, Object nodeValue, boolean isSelected, boolean expanded, boolean leaf, int row, boolean componentHasFocus) { nodeValue = convertToTreeObject( nodeValue ); return super.getTreeCellRendererComponent( tree, nodeValue, isSelected, expanded, leaf, row, componentHasFocus ); } private Object convertToTreeObject( Object nodeValue ) { if( nodeValue instanceof MapEntry ) { MapEntry entry = (MapEntry)nodeValue; COSName key = (COSName)entry.getKey(); COSBase value = (COSBase)entry.getValue(); nodeValue = key.getName() + ":" + convertToTreeObject( value ); } else if( nodeValue instanceof COSFloat ) { nodeValue = "" + ((COSFloat)nodeValue).floatValue(); } else if( nodeValue instanceof COSInteger ) { nodeValue = "" + ((COSInteger)nodeValue).intValue(); } else if( nodeValue instanceof COSString ) { nodeValue = ((COSString)nodeValue).getString(); } else if( nodeValue instanceof COSName ) { nodeValue = ((COSName)nodeValue).getName(); } else if( nodeValue instanceof ArrayEntry ) { ArrayEntry entry = (ArrayEntry)nodeValue; nodeValue = "[" + entry.getIndex() + "]" + convertToTreeObject( entry.getValue() ); } else if( nodeValue instanceof COSNull ) { nodeValue = "null"; } else if( nodeValue instanceof COSDictionary ) { COSDictionary dict = (COSDictionary)nodeValue; if( nodeValue instanceof COSStream ) { nodeValue = "Stream"; } else { nodeValue = "Dictionary"; } COSName type = (COSName)dict.getDictionaryObject( COSName.TYPE ); if( type != null ) { nodeValue = nodeValue + "(" + type.getName(); COSName subType = (COSName)dict.getDictionaryObject( COSName.SUBTYPE ); if( subType != null ) { nodeValue = nodeValue + ":" + subType.getName(); } nodeValue = nodeValue + ")"; } } else if( nodeValue instanceof COSArray ) { nodeValue="Array"; } else if( nodeValue instanceof COSString ) { nodeValue = ((COSString)nodeValue).getString(); } return nodeValue; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/ArrayEntry.java0000644000000000000000000000341712645757432025754 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; /** * This is a simple class that will contain an index and a value. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class ArrayEntry { private int index; private Object value; /** * This will get the value for this entry. * * @return The value for this entry. */ public Object getValue() { return value; } /** * This will set the value for this entry. * * @param val the new value for this entry. */ public void setValue(Object val) { this.value = val; } /** * This will get the index of the array entry. * * @return The 0-based index into the array */ public int getIndex() { return index; } /** * This will set the index value. * * @param i The new index value. */ public void setIndex(int i) { index = i; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PDFPagePanel.java0000644000000000000000000000742312645757432026043 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfviewer; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.io.IOException; import javax.swing.JPanel; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * This is a simple JPanel that can be used to display a PDF page. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDFPagePanel extends JPanel { private static final long serialVersionUID = -4629033339560890669L; private PDPage page; private PageDrawer drawer = null; private Dimension pageDimension = null; private Dimension drawDimension = null; /** * Constructor. * * @throws IOException If there is an error creating the Page drawing objects. */ public PDFPagePanel() throws IOException { drawer = new PageDrawer(); } /** * This will set the page that should be displayed in this panel. * * @param pdfPage The page to draw. */ public void setPage( PDPage pdfPage ) { page = pdfPage; PDRectangle cropBox = page.findCropBox(); drawDimension = cropBox.createDimension(); if (page.findRotation() % 180 == 0) { pageDimension = drawDimension; } else { pageDimension = new Dimension(drawDimension.height, drawDimension.width); } setSize( pageDimension ); setBackground( java.awt.Color.white ); } /** * {@inheritDoc} */ @Override public void paint(Graphics g ) { try { g.setColor( getBackground() ); g.fillRect( 0, 0, getWidth(), getHeight() ); int rotationAngle = page.findRotation(); // normalize the rotation angle while (rotationAngle < 0) { rotationAngle += 360; } while (rotationAngle >= 360) { rotationAngle -= 360; } if (rotationAngle != 0) { Graphics2D g2D = (Graphics2D)g; double translateX = 0; double translateY = 0; switch (rotationAngle) { case 90: translateX = pageDimension.getWidth(); break; case 270: translateY = pageDimension.getHeight(); break; case 180: translateX = pageDimension.getWidth(); translateY = pageDimension.getHeight(); break; } g2D.translate(translateX, translateY); g2D.rotate(Math.toRadians(rotationAngle)); } drawer.drawPage( g, page, drawDimension ); } catch( IOException e ) { e.printStackTrace(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/persistence/0000755000000000000000000000000012645757432023335 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/0000755000000000000000000000000012645757432024312 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSObjectKey.java0000644000000000000000000000676212645757432027414 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.persistence.util; import org.apache.pdfbox.cos.COSObject; /** * Object representing the physical reference to an indirect pdf object. * * @author Michael Traut * @version $Revision: 1.5 $ */ public class COSObjectKey implements Comparable { private long number; private long generation; /** * PDFObjectKey constructor comment. * * @param object The object that this key will represent. */ public COSObjectKey(COSObject object) { this( object.getObjectNumber().longValue(), object.getGenerationNumber().longValue() ); } /** * PDFObjectKey constructor comment. * * @param num The object number. * @param gen The object generation number. */ public COSObjectKey(long num, long gen) { setNumber(num); setGeneration(gen); } /** * {@inheritDoc} */ public boolean equals(Object obj) { return (obj instanceof COSObjectKey) && ((COSObjectKey)obj).getNumber() == getNumber() && ((COSObjectKey)obj).getGeneration() == getGeneration(); } /** * This will get the generation number. * * @return The objects generation number. */ public long getGeneration() { return generation; } /** * This will get the objects id. * * @return The object's id. */ public long getNumber() { return number; } /** * {@inheritDoc} */ public int hashCode() { return (int)(number + generation); } /** * This will set the objects generation number. * * @param newGeneration The objects generation number. */ public void setGeneration(long newGeneration) { generation = newGeneration; } /** * This will set the objects id. * * @param newNumber The objects number. */ public void setNumber(long newNumber) { number = newNumber; } /** * {@inheritDoc} */ public String toString() { return "" + getNumber() + " " + getGeneration() + " R"; } /** {@inheritDoc} */ public int compareTo(COSObjectKey other) { if (getNumber() < other.getNumber()) { return -1; } else if (getNumber() > other.getNumber()) { return 1; } else { if (getGeneration() < other.getGeneration()) { return -1; } else if (getGeneration() > other.getGeneration()) { return 1; } else { return 0; } } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/package.html0000644000000000000000000000170012645757432026571 0ustar rootroot These are utilities used by the persistence layer. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSHEXTable.java0000644000000000000000000003711412645757432027124 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.persistence.util; import org.apache.pdfbox.util.StringUtil; /** * helper type for faster mapping of bytes to their hex equivalent. * * @author Michael Traut * @version $Revision: 1.4 $ */ public final class COSHEXTable { private COSHEXTable() { } /** * ASCII byte values for the hex strings. */ public static final byte[][] TABLE = { StringUtil.getBytes("00"), StringUtil.getBytes("01"), StringUtil.getBytes("02"), StringUtil.getBytes("03"), StringUtil.getBytes("04"), StringUtil.getBytes("05"), StringUtil.getBytes("06"), StringUtil.getBytes("07"), StringUtil.getBytes("08"), StringUtil.getBytes("09"), StringUtil.getBytes("0A"), StringUtil.getBytes("0B"), StringUtil.getBytes("0C"), StringUtil.getBytes("0D"), StringUtil.getBytes("0E"), StringUtil.getBytes("0F"), StringUtil.getBytes("10"), StringUtil.getBytes("11"), StringUtil.getBytes("12"), StringUtil.getBytes("13"), StringUtil.getBytes("14"), StringUtil.getBytes("15"), StringUtil.getBytes("16"), StringUtil.getBytes("17"), StringUtil.getBytes("18"), StringUtil.getBytes("19"), StringUtil.getBytes("1A"), StringUtil.getBytes("1B"), StringUtil.getBytes("1C"), StringUtil.getBytes("1D"), StringUtil.getBytes("1E"), StringUtil.getBytes("1F"), StringUtil.getBytes("20"), StringUtil.getBytes("21"), StringUtil.getBytes("22"), StringUtil.getBytes("23"), StringUtil.getBytes("24"), StringUtil.getBytes("25"), StringUtil.getBytes("26"), StringUtil.getBytes("27"), StringUtil.getBytes("28"), StringUtil.getBytes("29"), StringUtil.getBytes("2A"), StringUtil.getBytes("2B"), StringUtil.getBytes("2C"), StringUtil.getBytes("2D"), StringUtil.getBytes("2E"), StringUtil.getBytes("2F"), StringUtil.getBytes("30"), StringUtil.getBytes("31"), StringUtil.getBytes("32"), StringUtil.getBytes("33"), StringUtil.getBytes("34"), StringUtil.getBytes("35"), StringUtil.getBytes("36"), StringUtil.getBytes("37"), StringUtil.getBytes("38"), StringUtil.getBytes("39"), StringUtil.getBytes("3A"), StringUtil.getBytes("3B"), StringUtil.getBytes("3C"), StringUtil.getBytes("3D"), StringUtil.getBytes("3E"), StringUtil.getBytes("3F"), StringUtil.getBytes("40"), StringUtil.getBytes("41"), StringUtil.getBytes("42"), StringUtil.getBytes("43"), StringUtil.getBytes("44"), StringUtil.getBytes("45"), StringUtil.getBytes("46"), StringUtil.getBytes("47"), StringUtil.getBytes("48"), StringUtil.getBytes("49"), StringUtil.getBytes("4A"), StringUtil.getBytes("4B"), StringUtil.getBytes("4C"), StringUtil.getBytes("4D"), StringUtil.getBytes("4E"), StringUtil.getBytes("4F"), StringUtil.getBytes("50"), StringUtil.getBytes("51"), StringUtil.getBytes("52"), StringUtil.getBytes("53"), StringUtil.getBytes("54"), StringUtil.getBytes("55"), StringUtil.getBytes("56"), StringUtil.getBytes("57"), StringUtil.getBytes("58"), StringUtil.getBytes("59"), StringUtil.getBytes("5A"), StringUtil.getBytes("5B"), StringUtil.getBytes("5C"), StringUtil.getBytes("5D"), StringUtil.getBytes("5E"), StringUtil.getBytes("5F"), StringUtil.getBytes("60"), StringUtil.getBytes("61"), StringUtil.getBytes("62"), StringUtil.getBytes("63"), StringUtil.getBytes("64"), StringUtil.getBytes("65"), StringUtil.getBytes("66"), StringUtil.getBytes("67"), StringUtil.getBytes("68"), StringUtil.getBytes("69"), StringUtil.getBytes("6A"), StringUtil.getBytes("6B"), StringUtil.getBytes("6C"), StringUtil.getBytes("6D"), StringUtil.getBytes("6E"), StringUtil.getBytes("6F"), StringUtil.getBytes("70"), StringUtil.getBytes("71"), StringUtil.getBytes("72"), StringUtil.getBytes("73"), StringUtil.getBytes("74"), StringUtil.getBytes("75"), StringUtil.getBytes("76"), StringUtil.getBytes("77"), StringUtil.getBytes("78"), StringUtil.getBytes("79"), StringUtil.getBytes("7A"), StringUtil.getBytes("7B"), StringUtil.getBytes("7C"), StringUtil.getBytes("7D"), StringUtil.getBytes("7E"), StringUtil.getBytes("7F"), StringUtil.getBytes("80"), StringUtil.getBytes("81"), StringUtil.getBytes("82"), StringUtil.getBytes("83"), StringUtil.getBytes("84"), StringUtil.getBytes("85"), StringUtil.getBytes("86"), StringUtil.getBytes("87"), StringUtil.getBytes("88"), StringUtil.getBytes("89"), StringUtil.getBytes("8A"), StringUtil.getBytes("8B"), StringUtil.getBytes("8C"), StringUtil.getBytes("8D"), StringUtil.getBytes("8E"), StringUtil.getBytes("8F"), StringUtil.getBytes("90"), StringUtil.getBytes("91"), StringUtil.getBytes("92"), StringUtil.getBytes("93"), StringUtil.getBytes("94"), StringUtil.getBytes("95"), StringUtil.getBytes("96"), StringUtil.getBytes("97"), StringUtil.getBytes("98"), StringUtil.getBytes("99"), StringUtil.getBytes("9A"), StringUtil.getBytes("9B"), StringUtil.getBytes("9C"), StringUtil.getBytes("9D"), StringUtil.getBytes("9E"), StringUtil.getBytes("9F"), StringUtil.getBytes("A0"), StringUtil.getBytes("A1"), StringUtil.getBytes("A2"), StringUtil.getBytes("A3"), StringUtil.getBytes("A4"), StringUtil.getBytes("A5"), StringUtil.getBytes("A6"), StringUtil.getBytes("A7"), StringUtil.getBytes("A8"), StringUtil.getBytes("A9"), StringUtil.getBytes("AA"), StringUtil.getBytes("AB"), StringUtil.getBytes("AC"), StringUtil.getBytes("AD"), StringUtil.getBytes("AE"), StringUtil.getBytes("AF"), StringUtil.getBytes("B0"), StringUtil.getBytes("B1"), StringUtil.getBytes("B2"), StringUtil.getBytes("B3"), StringUtil.getBytes("B4"), StringUtil.getBytes("B5"), StringUtil.getBytes("B6"), StringUtil.getBytes("B7"), StringUtil.getBytes("B8"), StringUtil.getBytes("B9"), StringUtil.getBytes("BA"), StringUtil.getBytes("BB"), StringUtil.getBytes("BC"), StringUtil.getBytes("BD"), StringUtil.getBytes("BE"), StringUtil.getBytes("BF"), StringUtil.getBytes("C0"), StringUtil.getBytes("C1"), StringUtil.getBytes("C2"), StringUtil.getBytes("C3"), StringUtil.getBytes("C4"), StringUtil.getBytes("C5"), StringUtil.getBytes("C6"), StringUtil.getBytes("C7"), StringUtil.getBytes("C8"), StringUtil.getBytes("C9"), StringUtil.getBytes("CA"), StringUtil.getBytes("CB"), StringUtil.getBytes("CC"), StringUtil.getBytes("CD"), StringUtil.getBytes("CE"), StringUtil.getBytes("CF"), StringUtil.getBytes("D0"), StringUtil.getBytes("D1"), StringUtil.getBytes("D2"), StringUtil.getBytes("D3"), StringUtil.getBytes("D4"), StringUtil.getBytes("D5"), StringUtil.getBytes("D6"), StringUtil.getBytes("D7"), StringUtil.getBytes("D8"), StringUtil.getBytes("D9"), StringUtil.getBytes("DA"), StringUtil.getBytes("DB"), StringUtil.getBytes("DC"), StringUtil.getBytes("DD"), StringUtil.getBytes("DE"), StringUtil.getBytes("DF"), StringUtil.getBytes("E0"), StringUtil.getBytes("E1"), StringUtil.getBytes("E2"), StringUtil.getBytes("E3"), StringUtil.getBytes("E4"), StringUtil.getBytes("E5"), StringUtil.getBytes("E6"), StringUtil.getBytes("E7"), StringUtil.getBytes("E8"), StringUtil.getBytes("E9"), StringUtil.getBytes("EA"), StringUtil.getBytes("EB"), StringUtil.getBytes("EC"), StringUtil.getBytes("ED"), StringUtil.getBytes("EE"), StringUtil.getBytes("EF"), StringUtil.getBytes("F0"), StringUtil.getBytes("F1"), StringUtil.getBytes("F2"), StringUtil.getBytes("F3"), StringUtil.getBytes("F4"), StringUtil.getBytes("F5"), StringUtil.getBytes("F6"), StringUtil.getBytes("F7"), StringUtil.getBytes("F8"), StringUtil.getBytes("F9"), StringUtil.getBytes("FA"), StringUtil.getBytes("FB"), StringUtil.getBytes("FC"), StringUtil.getBytes("FD"), StringUtil.getBytes("FE"), StringUtil.getBytes("FF") }; /** * ASCII byte values for the hex strings. */ public static final String[] HEX_TABLE = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" }; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/Overlay.java0000644000000000000000000004014212645757432023276 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdfwriter.COSWriter; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.TreeMap; import java.util.Map; /** * Overlay on document with another one.
* e.g. Overlay an invoice with your company layout
*
* How it (should) work:
* If the document has 10 pages, and the layout 2 the following is the result:
*
 * Document: 1234567890
 * Layout  : 1212121212
 * 
*
* * @author Mario Ivankovits (mario@ops.co.at) * @author Ben Litchfield * * @version $Revision: 1.7 $ */ public class Overlay { /** * @deprecated use the {@link COSName#XOBJECT} constant instead */ public static final COSName XOBJECT = COSName.XOBJECT; /** * @deprecated use the {@link COSName#PROC_SET} constant instead */ public static final COSName PROC_SET = COSName.PROC_SET; /** * @deprecated use the {@link COSName#EXT_G_STATE} constant instead */ public static final COSName EXT_G_STATE = COSName.EXT_G_STATE; private List layoutPages = new ArrayList(10); private PDDocument pdfOverlay; private PDDocument pdfDocument; private int pageCount = 0; private COSStream saveGraphicsStateStream; private COSStream restoreGraphicsStateStream; /** * This will overlay a document and write out the results.

* * usage: java org.apache.pdfbox.Overlay <overlay.pdf> <document.pdf> <result.pdf> * * @param args The command line arguments. * * @throws IOException If there is an error reading/writing the document. * @throws COSVisitorException If there is an error writing the document. */ public static void main( String[] args ) throws IOException, COSVisitorException { if( args.length != 3 ) { usage(); System.exit(1); } else { PDDocument overlay = null; PDDocument pdf = null; try { overlay = getDocument( args[0] ); pdf = getDocument( args[1] ); Overlay overlayer = new Overlay(); overlayer.overlay( overlay, pdf ); writeDocument( pdf, args[2] ); } finally { if( overlay != null ) { overlay.close(); } if( pdf != null ) { pdf.close(); } } } } private static void writeDocument( PDDocument pdf, String filename ) throws IOException, COSVisitorException { FileOutputStream output = null; COSWriter writer = null; try { output = new FileOutputStream( filename ); writer = new COSWriter( output ); writer.write( pdf ); } finally { if( writer != null ) { writer.close(); } if( output != null ) { output.close(); } } } private static PDDocument getDocument( String filename ) throws IOException { FileInputStream input = null; PDFParser parser = null; PDDocument result = null; try { input = new FileInputStream( filename ); parser = new PDFParser( input ); parser.parse(); result = parser.getPDDocument(); } finally { if( input != null ) { input.close(); } } return result; } private static void usage() { System.err.println( "usage: java -jar pdfbox-app-x.y.z.jar Overlay " ); } /** * Private class. */ private static class LayoutPage { private final COSBase contents; private final COSDictionary res; private final Map objectNameMap; /** * Constructor. * * @param contentsValue The contents. * @param resValue The resource dictionary * @param objectNameMapValue The map */ public LayoutPage(COSBase contentsValue, COSDictionary resValue, Map objectNameMapValue) { contents = contentsValue; res = resValue; objectNameMap = objectNameMapValue; } } /** * This will overlay two documents onto each other. The overlay document is * repeatedly overlayed onto the destination document for every page in the * destination. * * @param overlay The document to copy onto the destination * @param destination The file that the overlay should be placed on. * * @return The destination pdf, same as argument passed in. * * @throws IOException If there is an error accessing data. */ public PDDocument overlay( PDDocument overlay, PDDocument destination ) throws IOException { pdfOverlay = overlay; pdfDocument = destination; PDDocumentCatalog overlayCatalog = pdfOverlay.getDocumentCatalog(); collectLayoutPages( overlayCatalog.getAllPages() ); COSDictionary saveGraphicsStateDic = new COSDictionary(); saveGraphicsStateStream = pdfDocument.getDocument().createCOSStream(saveGraphicsStateDic); OutputStream saveStream = saveGraphicsStateStream.createUnfilteredStream(); saveStream.write( " q\n".getBytes("ISO-8859-1") ); saveStream.flush(); restoreGraphicsStateStream = pdfDocument.getDocument().createCOSStream(saveGraphicsStateDic); OutputStream restoreStream = restoreGraphicsStateStream.createUnfilteredStream(); restoreStream.write( " Q\n".getBytes("ISO-8859-1") ); restoreStream.flush(); PDDocumentCatalog pdfCatalog = pdfDocument.getDocumentCatalog(); processPages( pdfCatalog.getAllPages() ); return pdfDocument; } private void collectLayoutPages( List pages) throws IOException { Iterator pagesIter = pages.iterator(); while( pagesIter.hasNext() ) { PDPage page = (PDPage)pagesIter.next(); COSBase contents = page.getCOSDictionary().getDictionaryObject( COSName.CONTENTS ); PDResources resources = page.findResources(); if( resources == null ) { resources = new PDResources(); page.setResources( resources ); } COSDictionary res = resources.getCOSDictionary(); if( contents instanceof COSStream ) { COSStream stream = (COSStream) contents; Map objectNameMap = new TreeMap(); stream = makeUniqObjectNames(objectNameMap, stream); layoutPages.add(new LayoutPage(stream, res, objectNameMap)); } else if( contents instanceof COSArray ) { throw new UnsupportedOperationException("Layout pages with COSArray currently not supported."); // layoutPages.add(new LayoutPage(contents, res)); } else { throw new IOException( "Contents are unknown type:" + contents.getClass().getName() ); } } } private COSStream makeUniqObjectNames(Map objectNameMap, COSStream stream) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(10240); byte[] buf = new byte[10240]; int read; InputStream is = stream.getUnfilteredStream(); while ((read = is.read(buf)) > -1) { baos.write(buf, 0, read); } buf = baos.toByteArray(); baos = new ByteArrayOutputStream(buf.length + 100); StringBuffer sbObjectName = new StringBuffer(10); boolean bInObjectIdent = false; boolean bInText = false; boolean bInEscape = false; for (int i = 0; i // // // array.add(0, saveGraphicsStateStream ); array.add( restoreGraphicsStateStream ); array.add(layoutPage.contents); } /** * merges two dictionaries. * * @param dest * @param source */ private void mergeDictionary(COSName name, COSDictionary dest, COSDictionary source, Map objectNameMap) { COSDictionary destDict = (COSDictionary) dest.getDictionaryObject(name); COSDictionary sourceDict = (COSDictionary) source.getDictionaryObject(name); if (destDict == null) { destDict = new COSDictionary(); dest.setItem(name, destDict); } if( sourceDict != null ) { for (Map.Entry entry : sourceDict.entrySet()) { COSName mappedKey = (COSName) objectNameMap.get(entry.getKey().getName()); if (mappedKey != null) { destDict.setItem(mappedKey, entry.getValue()); } } } } /** * merges two arrays. * * @param dest * @param source */ private void mergeArray(COSName name, COSDictionary dest, COSDictionary source) { COSArray destDict = (COSArray) dest.getDictionaryObject(name); COSArray sourceDict = (COSArray) source.getDictionaryObject(name); if (destDict == null) { destDict = new COSArray(); dest.setItem(name, destDict); } for (int sourceDictIdx = 0; sourceDict != null && sourceDictIdxBen Litchfield * @version $Revision: 1.6 $ */ public class PDFSplit { private static final String PASSWORD = "-password"; private static final String SPLIT = "-split"; private static final String START_PAGE = "-startPage"; private static final String END_PAGE = "-endPage"; private static final String NONSEQ = "-nonSeq"; private static final String OUTPUT_PREFIX = "-outputPrefix"; private PDFSplit() { } /** * Infamous main method. * * @param args Command line arguments, should be one and a reference to a file. * * @throws Exception If there is an error parsing the document. */ public static void main( String[] args ) throws Exception { PDFSplit split = new PDFSplit(); split.split( args ); } private void split( String[] args ) throws Exception { String password = ""; String split = null; String startPage = null; String endPage = null; boolean useNonSeqParser = false; Splitter splitter = new Splitter(); String pdfFile = null; String outputPrefix = null; for( int i=0; i= args.length ) { usage(); } password = args[i]; } else if( args[i].equals( SPLIT ) ) { i++; if( i >= args.length ) { usage(); } split = args[i]; } else if( args[i].equals( START_PAGE ) ) { i++; if( i >= args.length ) { usage(); } startPage = args[i]; } else if( args[i].equals( END_PAGE ) ) { i++; if( i >= args.length ) { usage(); } endPage = args[i]; } else if( args[i].equals( OUTPUT_PREFIX ) ) { i++; outputPrefix = args[i]; } else if( args[i].equals( NONSEQ ) ) { useNonSeqParser = true; } else { if( pdfFile == null ) { pdfFile = args[i]; } } } if( pdfFile == null ) { usage(); } else { if (outputPrefix == null) { outputPrefix = pdfFile.substring(0, pdfFile.lastIndexOf('.')); } PDDocument document = null; List documents = null; try { if (useNonSeqParser) { document = PDDocument.loadNonSeq(new File(pdfFile), null, password); } else { document = PDDocument.load(pdfFile); if( document.isEncrypted() ) { document.decrypt( password ); } } int numberOfPages = document.getNumberOfPages(); boolean startEndPageSet = false; if (startPage != null) { splitter.setStartPage(Integer.parseInt( startPage )); startEndPageSet = true; if (split == null) { splitter.setSplitAtPage(numberOfPages); } } if (endPage != null) { splitter.setEndPage(Integer.parseInt( endPage )); startEndPageSet = true; if (split == null) { splitter.setSplitAtPage(Integer.parseInt( endPage )); } } if (split != null) { splitter.setSplitAtPage( Integer.parseInt( split ) ); } else { if (!startEndPageSet) { splitter.setSplitAtPage(1); } } documents = splitter.split( document ); for( int i=0; i\n" + " -password Password to decrypt document\n" + " -split split after this many pages (default 1, if startPage and endPage are unset)\n"+ " -startPage start page\n" + " -endPage end page\n" + " -nonSeq Enables the new non-sequential parser\n" + " -outputPrefix Filename prefix for image files\n" + " The PDF document to use\n" ); System.exit( 1 ); } }pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/0000755000000000000000000000000012645757432023017 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java0000644000000000000000000000741112645757432027315 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfwriter; import org.apache.pdfbox.persistence.util.COSObjectKey; import org.apache.pdfbox.cos.COSBase; /** * this is en entry in the xref section of the physical pdf document * generated by the COSWriter. * * @author Michael Traut * @version $Revision: 1.7 $ */ public class COSWriterXRefEntry implements Comparable { private long offset; private COSBase object; private COSObjectKey key; private boolean free = false; private static COSWriterXRefEntry nullEntry; /** * {@inheritDoc} */ public int compareTo(COSWriterXRefEntry obj) { if (obj instanceof COSWriterXRefEntry) { return (int)(getKey().getNumber() - obj.getKey().getNumber()); } else { return -1; } } /** * This will return a null entry: 0000000000 65535 f * * @return null COSWriterXRefEntry */ public static COSWriterXRefEntry getNullEntry() { if (nullEntry == null) { nullEntry = new COSWriterXRefEntry(0, null, new COSObjectKey(0, 65535)); nullEntry.setFree(true); } return nullEntry; } /** * This will get the Object key. * * @return The object key. */ public COSObjectKey getKey() { return key; } /** * This will get the offset into the document. * * @return The offset into the document. */ public long getOffset() { return offset; } /** * Gets the xref 'free' attribute. * * @return The free attribute. */ public boolean isFree() { return free; } /** * This will set the free attribute. * * @param newFree The newly freed attribute. */ public void setFree(boolean newFree) { free = newFree; } /** * This will set the object key. * * @param newKey The new object key. */ private void setKey(COSObjectKey newKey) { key = newKey; } /** * The offset attribute. * * @param newOffset The new value for the offset. */ public void setOffset(long newOffset) { offset = newOffset; } /** * COSWriterXRefEntry constructor comment. * * @param start The start attribute. * @param obj The COS object that this entry represents. * @param keyValue The key to the COS object. */ public COSWriterXRefEntry(long start, COSBase obj, COSObjectKey keyValue) { super(); setOffset(start); setObject(obj); setKey(keyValue); } /** * This will get the object. * * @return The object. */ public COSBase getObject() { return object; } /** * This will set the object for this xref. * * @param newObject The object that is being set. */ private void setObject(COSBase newObject) { object = newObject; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSStandardOutputStream.java0000644000000000000000000001341612645757432030371 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfwriter; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.channels.FileChannel; import org.apache.pdfbox.util.StringUtil; /** * simple output stream with some minor features for generating "pretty" * pdf files. * * @author Michael Traut * @version $Revision: 1.5 $ */ public class COSStandardOutputStream extends FilterOutputStream { /** * To be used when 2 byte sequence is enforced. */ public static final byte[] CRLF = StringUtil.getBytes("\r\n"); /** * Line feed character. */ public static final byte[] LF = StringUtil.getBytes("\n"); /** * standard line separator. */ public static final byte[] EOL = StringUtil.getBytes("\n"); // current byte pos in the output stream private long pos = 0; // flag to prevent generating two newlines in sequence private boolean onNewLine = false; private FileChannel fileChannel = null; private FileDescriptor fileDescriptor = null; private long mark = -1; /** * COSOutputStream constructor comment. * * @param out The underlying stream to write to. */ public COSStandardOutputStream(OutputStream out) { super(out); if(out instanceof FileOutputStream) { try { fileChannel = ((FileOutputStream)out).getChannel(); fileDescriptor = ((FileOutputStream)out).getFD(); pos = fileChannel.position(); } catch (IOException e) { e.printStackTrace(); } } } /** * This will get the current position in the stream. * * @return The current position in the stream. */ public long getPos() { return pos; } /** * This will set the current position in the stream. * * @param pos the to be set position in the stream. * @throws IOException */ public void setPos(long pos) throws IOException { if(fileChannel!=null) { checkPos(); this.pos=pos; fileChannel.position(pos); } } /** * This will tell if we are on a newline. * * @return true If we are on a newline. */ public boolean isOnNewLine() { return onNewLine; } /** * This will set a flag telling if we are on a newline. * * @param newOnNewLine The new value for the onNewLine attribute. */ public void setOnNewLine(boolean newOnNewLine) { onNewLine = newOnNewLine; } /** * This will write some byte to the stream. * * @param b The source byte array. * @param off The offset into the array to start writing. * @param len The number of bytes to write. * * @throws IOException If the underlying stream throws an exception. */ @Override public void write(byte[] b, int off, int len) throws IOException { checkPos(); setOnNewLine(false); out.write(b, off, len); pos += len; } /** * This will write a single byte to the stream. * * @param b The byte to write to the stream. * * @throws IOException If there is an error writing to the underlying stream. */ @Override public void write(int b) throws IOException { checkPos(); setOnNewLine(false); out.write(b); pos++; } /** * This will write a CRLF to the stream. * * @throws IOException If there is an error writing the data to the stream. */ public void writeCRLF() throws IOException { write(CRLF); } /** * This will write an EOL to the stream. * * @throws IOException If there is an error writing to the stream */ public void writeEOL() throws IOException { if (!isOnNewLine()) { write(EOL); setOnNewLine(true); } } /** * This will write a Linefeed to the stream. * * @throws IOException If there is an error writing to the underlying stream. */ public void writeLF() throws IOException { write(LF); } public void mark() throws IOException { checkPos(); mark = getPos(); } public void reset() throws IOException { if(mark<0) return; setPos(mark); } private void checkPos() throws IOException { if(fileChannel!=null && fileChannel.position() != getPos()) throw new IOException("OutputStream has an invalid position"); } public byte[] getFileInBytes(int[] byteRange) throws IOException { return null; } public InputStream getFilterInputStream(int[] byteRange) { return new COSFilterInputStream(new FileInputStream(fileDescriptor), byteRange); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/package.html0000644000000000000000000000173312645757432025304 0ustar rootroot This is the persistence layer used to write the PDFBox documents to a stream. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSFilterInputStream.java0000644000000000000000000000562212645757432027655 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfwriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; public class COSFilterInputStream extends FilterInputStream { int[] byteRange; long position = 0; public COSFilterInputStream(InputStream in, int[] byteRange) { super(in); this.byteRange = byteRange; } public COSFilterInputStream(byte[] in, int[] byteRange) { super(new ByteArrayInputStream(in)); this.byteRange = byteRange; } @Override public int read() throws IOException { nextAvailable(); int i = super.read(); if (i>-1) ++position; return i; } @Override public int read(byte[] b) throws IOException { return read(b,0,b.length); } @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; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; } private boolean inRange() throws IOException { long pos = position; for (int i = 0; ipos) { return true; } } return false; } private void nextAvailable() throws IOException { while (!inRange()) { ++position; if(super.read()<0) break; } } public byte[] toByteArray() throws IOException { ByteArrayOutputStream byteOS = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int c; while ((c = this.read(buffer)) != -1) byteOS.write(buffer, 0, c); return byteOS.toByteArray(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/ContentStreamWriter.java0000644000000000000000000001341212645757432027646 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfwriter; import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.util.ImageParameters; import org.apache.pdfbox.util.PDFOperator; /** * A class that will take a list of tokens and write out a stream with them. * * @author Ben Litchfield * @version $Revision: 1.8 $ */ public class ContentStreamWriter { private OutputStream output; /** * space character. */ public static final byte[] SPACE = new byte[] { 32 }; /** * standard line separator */ public static final byte[] EOL = new byte[] { 0x0A }; /** * This will create a new content stream writer. * * @param out The stream to write the data to. */ public ContentStreamWriter( OutputStream out ) { output = out; } /** * This will write out the list of tokens to the stream. * * @param tokens The tokens to write to the stream. * @param start The start index into the list of tokens. * @param end The end index into the list of tokens. * @throws IOException If there is an error writing to the stream. */ public void writeTokens( List tokens, int start, int end ) throws IOException { for( int i=start; i entry : obj.entrySet()) { if (entry.getValue() != null) { writeObject( entry.getKey() ); output.write( SPACE ); writeObject( entry.getValue() ); output.write( SPACE ); } } output.write( COSWriter.DICT_CLOSE ); output.write( SPACE ); } else if( o instanceof PDFOperator ) { PDFOperator op = (PDFOperator)o; if( op.getOperation().equals( "BI" ) ) { output.write( "BI".getBytes("ISO-8859-1") ); ImageParameters params = op.getImageParameters(); COSDictionary dic = params.getDictionary(); for( COSName key : dic.keySet() ) { Object value = dic.getDictionaryObject( key ); key.writePDF( output ); output.write( SPACE ); writeObject( value ); output.write( EOL ); } output.write( "ID".getBytes("ISO-8859-1") ); output.write( EOL ); output.write( op.getImageData() ); output.write( EOL ); output.write( "EI".getBytes("ISO-8859-1") ); output.write( EOL ); } else { output.write( op.getOperation().getBytes("ISO-8859-1") ); output.write( EOL ); } } else { throw new IOException( "Error:Unknown type in content stream:" + o ); } } /** * This will write out the list of tokens to the stream. * * @param tokens The tokens to write to the stream. * @throws IOException If there is an error writing to the stream. */ public void writeTokens( List tokens ) throws IOException { writeTokens( tokens, 0, tokens.size() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java0000644000000000000000000014224412645757432025512 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfwriter; import java.io.BufferedInputStream; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNull; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.cos.ICOSVisitor; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.exceptions.SignatureException; import org.apache.pdfbox.pdfparser.PDFXRefStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.encryption.SecurityHandler; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; import org.apache.pdfbox.persistence.util.COSObjectKey; import org.apache.pdfbox.util.StringUtil; /** * this class acts on a in-memory representation of a pdf document. * * todo no support for incremental updates * todo single xref section only * todo no linearization * * @author Michael Traut * @author Ben Litchfield * */ public class COSWriter implements ICOSVisitor, Closeable { /** * The dictionary open token. */ public static final byte[] DICT_OPEN = StringUtil.getBytes("<<"); /** * The dictionary close token. */ public static final byte[] DICT_CLOSE = StringUtil.getBytes(">>"); /** * space character. */ public static final byte[] SPACE = StringUtil.getBytes(" "); /** * The start to a PDF comment. */ public static final byte[] COMMENT = StringUtil.getBytes("%"); /** * The output version of the PDF. */ public static final byte[] VERSION = StringUtil.getBytes("PDF-1.4"); /** * Garbage bytes used to create the PDF header. */ public static final byte[] GARBAGE = new byte[] {(byte)0xf6, (byte)0xe4, (byte)0xfc, (byte)0xdf}; /** * The EOF constant. */ public static final byte[] EOF = StringUtil.getBytes("%%EOF"); // pdf tokens /** * The reference token. */ public static final byte[] REFERENCE = StringUtil.getBytes("R"); /** * The XREF token. */ public static final byte[] XREF = StringUtil.getBytes("xref"); /** * The xref free token. */ public static final byte[] XREF_FREE = StringUtil.getBytes("f"); /** * The xref used token. */ public static final byte[] XREF_USED = StringUtil.getBytes("n"); /** * The trailer token. */ public static final byte[] TRAILER = StringUtil.getBytes("trailer"); /** * The start xref token. */ public static final byte[] STARTXREF = StringUtil.getBytes("startxref"); /** * The starting object token. */ public static final byte[] OBJ = StringUtil.getBytes("obj"); /** * The end object token. */ public static final byte[] ENDOBJ = StringUtil.getBytes("endobj"); /** * The array open token. */ public static final byte[] ARRAY_OPEN = StringUtil.getBytes("["); /** * The array close token. */ public static final byte[] ARRAY_CLOSE = StringUtil.getBytes("]"); /** * The open stream token. */ public static final byte[] STREAM = StringUtil.getBytes("stream"); /** * The close stream token. */ public static final byte[] ENDSTREAM = StringUtil.getBytes("endstream"); private NumberFormat formatXrefOffset = new DecimalFormat("0000000000"); /** * The decimal format for the xref object generation number data. */ private NumberFormat formatXrefGeneration = new DecimalFormat("00000"); private NumberFormat formatDecimal = NumberFormat.getNumberInstance( Locale.US ); // the stream where we create the pdf output private OutputStream output; // the stream used to write standard cos data private COSStandardOutputStream standardOutput; // the start position of the x ref section private long startxref = 0; // the current object number private long number = 0; // maps the object to the keys generated in the writer // these are used for indirect references in other objects //A hashtable is used on purpose over a hashmap //so that null entries will not get added. private Map objectKeys = new Hashtable(); private Map keyObject = new Hashtable(); // the list of x ref entries to be made so far private List xRefEntries = new ArrayList(); private HashSet objectsToWriteSet = new HashSet(); //A list of objects to write. private LinkedList objectsToWrite = new LinkedList(); //a list of objects already written private Set writtenObjects = new HashSet(); //An 'actual' is any COSBase that is not a COSObject. //need to keep a list of the actuals that are added //as well as the objects because there is a problem //when adding a COSObject and then later adding //the actual for that object, so we will track //actuals separately. private Set actualsAdded = new HashSet(); private COSObjectKey currentObjectKey = null; private PDDocument document = null; private boolean willEncrypt = false; private boolean incrementalUpdate = false; private boolean reachedSignature = false; private int[] signaturePosition = new int[2]; private int[] byterangePosition = new int[2]; private InputStream in; /** * COSWriter constructor comment. * * @param os The wrapped output stream. */ public COSWriter(OutputStream os) { super(); setOutput(os); setStandardOutput(new COSStandardOutputStream(output)); formatDecimal.setMaximumFractionDigits( 10 ); formatDecimal.setGroupingUsed( false ); } /** * COSWriter constructor for incremental updates. * * @param os The wrapped output stream. * @param is input stream */ public COSWriter(OutputStream os, InputStream is) { this(os); in = is; incrementalUpdate = true; } private void prepareIncrement(PDDocument doc) { try { if (doc != null) { COSDocument cosDoc = doc.getDocument(); Map xrefTable = cosDoc.getXrefTable(); Set keySet = xrefTable.keySet(); long highestNumber=0; for ( COSObjectKey cosObjectKey : keySet ) { COSBase object = cosDoc.getObjectFromPool(cosObjectKey).getObject(); if (object != null && cosObjectKey!= null && !(object instanceof COSNumber)) { objectKeys.put(object, cosObjectKey); keyObject.put(cosObjectKey,object); } long num = cosObjectKey.getNumber(); if (num > highestNumber) { highestNumber=num; } } setNumber(highestNumber); // xrefTable.clear(); } } catch (IOException e) { e.printStackTrace(); } } /** * add an entry in the x ref table for later dump. * * @param entry The new entry to add. */ protected void addXRefEntry(COSWriterXRefEntry entry) { getXRefEntries().add(entry); } /** * This will close the stream. * * @throws IOException If the underlying stream throws an exception. */ public void close() throws IOException { if (getStandardOutput() != null) { getStandardOutput().close(); } if (getOutput() != null) { getOutput().close(); } } /** * This will get the current object number. * * @return The current object number. */ protected long getNumber() { return number; } /** * This will get all available object keys. * * @return A map of all object keys. */ public Map getObjectKeys() { return objectKeys; } /** * This will get the output stream. * * @return The output stream. */ protected java.io.OutputStream getOutput() { return output; } /** * This will get the standard output stream. * * @return The standard output stream. */ protected COSStandardOutputStream getStandardOutput() { return standardOutput; } /** * This will get the current start xref. * * @return The current start xref. */ protected long getStartxref() { return startxref; } /** * This will get the xref entries. * * @return All available xref entries. */ protected List getXRefEntries() { return xRefEntries; } /** * This will set the current object number. * * @param newNumber The new object number. */ protected void setNumber(long newNumber) { number = newNumber; } /** * This will set the output stream. * * @param newOutput The new output stream. */ private void setOutput( OutputStream newOutput ) { output = newOutput; } /** * This will set the standard output stream. * * @param newStandardOutput The new standard output stream. */ private void setStandardOutput(COSStandardOutputStream newStandardOutput) { standardOutput = newStandardOutput; } /** * This will set the start xref. * * @param newStartxref The new start xref attribute. */ protected void setStartxref(long newStartxref) { startxref = newStartxref; } /** * This will write the body of the document. * * @param doc The document to write the body for. * * @throws IOException If there is an error writing the data. * @throws COSVisitorException If there is an error generating the data. */ protected void doWriteBody(COSDocument doc) throws IOException, COSVisitorException { COSDictionary trailer = doc.getTrailer(); COSDictionary root = (COSDictionary)trailer.getDictionaryObject( COSName.ROOT ); COSDictionary info = (COSDictionary)trailer.getDictionaryObject( COSName.INFO ); COSDictionary encrypt = (COSDictionary)trailer.getDictionaryObject( COSName.ENCRYPT ); if( root != null ) { addObjectToWrite( root ); } if( info != null ) { addObjectToWrite( info ); } while( objectsToWrite.size() > 0 ) { COSBase nextObject = objectsToWrite.removeFirst(); objectsToWriteSet.remove(nextObject); doWriteObject( nextObject ); } willEncrypt = false; if( encrypt != null ) { addObjectToWrite( encrypt ); } while( objectsToWrite.size() > 0 ) { COSBase nextObject = objectsToWrite.removeFirst(); objectsToWriteSet.remove(nextObject); doWriteObject( nextObject ); } } private void addObjectToWrite( COSBase object ) { COSBase actual = object; if( actual instanceof COSObject ) { actual = ((COSObject)actual).getObject(); } if( !writtenObjects.contains( object ) && !objectsToWriteSet.contains( object ) && !actualsAdded.contains( actual ) ) { COSBase cosBase=null; COSObjectKey cosObjectKey = null; if(actual != null) { cosObjectKey= objectKeys.get(actual); } if(cosObjectKey!=null) { cosBase = keyObject.get(cosObjectKey); } if(actual != null && objectKeys.containsKey(actual) && !object.isNeedToBeUpdate() && (cosBase!= null && !cosBase.isNeedToBeUpdate())) { return; } objectsToWrite.add( object ); objectsToWriteSet.add( object ); if( actual != null ) { actualsAdded.add( actual ); } } } /** * This will write a COS object. * * @param obj The object to write. * * @throws COSVisitorException If there is an error visiting objects. */ public void doWriteObject( COSBase obj ) throws COSVisitorException { try { writtenObjects.add( obj ); if(obj instanceof COSDictionary) { COSDictionary dict = (COSDictionary)obj; COSBase itemType = dict.getItem(COSName.TYPE); if (itemType instanceof COSName) { COSName item = (COSName) itemType; if (COSName.SIG.equals(item) || COSName.DOC_TIME_STAMP.equals(item)) { reachedSignature = true; } } } // find the physical reference currentObjectKey = getObjectKey( obj ); // add a x ref entry addXRefEntry( new COSWriterXRefEntry(getStandardOutput().getPos(), obj, currentObjectKey)); // write the object getStandardOutput().write(String.valueOf(currentObjectKey.getNumber()).getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(String.valueOf(currentObjectKey.getGeneration()).getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(OBJ); getStandardOutput().writeEOL(); obj.accept( this ); getStandardOutput().writeEOL(); getStandardOutput().write(ENDOBJ); getStandardOutput().writeEOL(); } catch (IOException e) { throw new COSVisitorException(e); } } /** * This will write the header to the PDF document. * * @param doc The document to get the data from. * * @throws IOException If there is an error writing to the stream. */ protected void doWriteHeader(COSDocument doc) throws IOException { getStandardOutput().write( doc.getHeaderString().getBytes("ISO-8859-1") ); getStandardOutput().writeEOL(); getStandardOutput().write(COMMENT); getStandardOutput().write(GARBAGE); getStandardOutput().writeEOL(); } /** * This will write the trailer to the PDF document. * * @param doc The document to create the trailer for. * * @throws IOException If there is an IOError while writing the document. * @throws COSVisitorException If there is an error while generating the data. */ protected void doWriteTrailer(COSDocument doc) throws IOException, COSVisitorException { getStandardOutput().write(TRAILER); getStandardOutput().writeEOL(); COSDictionary trailer = doc.getTrailer(); //sort xref, needed only if object keys not regenerated Collections.sort(getXRefEntries()); COSWriterXRefEntry lastEntry = getXRefEntries().get( getXRefEntries().size()-1); trailer.setInt(COSName.SIZE, (int)lastEntry.getKey().getNumber()+1); // Only need to stay, if an incremental update will be performed if (!incrementalUpdate) { trailer.removeItem( COSName.PREV ); } if (!doc.isXRefStream()) { trailer.removeItem( COSName.XREF_STM ); } // Remove a checksum if present trailer.removeItem( COSName.DOC_CHECKSUM ); trailer.accept(this); } /** * write the x ref section for the pdf file * * currently, the pdf is reconstructed from the scratch, so we write a single section * * todo support for incremental writing? * * @param doc The document to write the xref from. * * @throws IOException If there is an error writing the data to the stream. */ protected void doWriteXRef(COSDocument doc) throws IOException { if (doc.isXRefStream()) { // sort xref, needed only if object keys not regenerated Collections.sort(getXRefEntries()); COSWriterXRefEntry lastEntry = getXRefEntries().get( getXRefEntries().size()-1 ); // remember the position where x ref is written setStartxref(getStandardOutput().getPos()); // getStandardOutput().write(XREF); getStandardOutput().writeEOL(); // write start object number and object count for this x ref section // we assume starting from scratch writeXrefRange(0, lastEntry.getKey().getNumber() + 1); // write initial start object with ref to first deleted object and magic generation number writeXrefEntry(COSWriterXRefEntry.getNullEntry()); // write entry for every object long lastObjectNumber = 0; for (Iterator i = getXRefEntries().iterator(); i.hasNext();) { COSWriterXRefEntry entry = i.next(); while( lastObjectNumber xRefEntries2 = getXRefEntries(); for ( COSWriterXRefEntry cosWriterXRefEntry : xRefEntries2 ) { pdfxRefStream.addEntry(cosWriterXRefEntry); } COSDictionary trailer = doc.getTrailer(); // trailer.setLong(COSName.PREV, hybridPrev == -1 ? prev : hybridPrev); trailer.setLong(COSName.PREV, doc.getStartXref()); pdfxRefStream.addTrailerInfo(trailer); // the size is the highest object number+1. we add one more // for the xref stream object we are going to write pdfxRefStream.setSize(getNumber() + 2); setStartxref(getStandardOutput().getPos()); COSStream stream2 = pdfxRefStream.getStream(); doWriteObject(stream2); } if (!doc.isXRefStream() || hybridPrev != -1) { COSDictionary trailer = doc.getTrailer(); trailer.setLong(COSName.PREV, doc.getStartXref()); if (hybridPrev != -1) { COSName xrefStm = COSName.XREF_STM; trailer.removeItem(xrefStm); trailer.setLong(xrefStm, getStartxref()); } addXRefEntry(COSWriterXRefEntry.getNullEntry()); // sort xref, needed only if object keys not regenerated Collections.sort(getXRefEntries()); // remember the position where x ref was written setStartxref(getStandardOutput().getPos()); getStandardOutput().write(XREF); getStandardOutput().writeEOL(); // write start object number and object count for this x ref section // we assume starting from scratch Integer[] xRefRanges = getXRefRanges(getXRefEntries()); int xRefLength = xRefRanges.length; int x = 0; int j = 0; while(x < xRefLength && (xRefLength % 2) == 0) { writeXrefRange(xRefRanges[x], xRefRanges[x + 1]); for(int i = 0; i < xRefRanges[x + 1]; ++i) { writeXrefEntry(xRefEntries.get(j++)); } x += 2; } } } private void doWriteSignature(COSDocument doc) throws IOException, SignatureException { // need to calculate the ByteRange if (signaturePosition[0]>0 && byterangePosition[1] > 0) { int left = (int)getStandardOutput().getPos()-signaturePosition[1]; String newByteRange = "0 "+signaturePosition[0]+" "+signaturePosition[1]+" "+left+"]"; int leftByterange = byterangePosition[1]-byterangePosition[0]-newByteRange.length(); if(leftByterange<0) { throw new IOException("Can't write new ByteRange, not enough space"); } getStandardOutput().setPos(byterangePosition[0]); getStandardOutput().write(newByteRange.getBytes("ISO-8859-1")); for(int i=0;i" if (startPos + signature.length() > endPos) { throw new IOException("Can't write signature, not enough space"); } getStandardOutput().setPos(startPos); getStandardOutput().write(signature.getBytes("ISO-8859-1")); } finally { if(filterInputStream !=null) { filterInputStream.close(); } } } } private void writeXrefRange(long x, long y) throws IOException { getStandardOutput().write(String.valueOf(x).getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(String.valueOf(y).getBytes("ISO-8859-1")); getStandardOutput().writeEOL(); } private void writeXrefEntry(COSWriterXRefEntry entry) throws IOException { String offset = formatXrefOffset.format(entry.getOffset()); String generation = formatXrefGeneration.format(entry.getKey().getGeneration()); getStandardOutput().write(offset.getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(generation.getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(entry.isFree() ? XREF_FREE : XREF_USED); getStandardOutput().writeCRLF(); } /** * check the xref entries and write out the ranges. The format of the * returned array is exactly the same as the pdf specification. See section * 7.5.4 of ISO32000-1:2008, example 1 (page 40) for reference. *

* example: 0 1 2 5 6 7 8 10 *

* will create a array with follow ranges *

* 0 3 5 4 10 1 *

* this mean that the element 0 is followed by two other related numbers * that represent a cluster of the size 3. 5 is follow by three other * related numbers and create a cluster of size 4. etc. * * @param xRefEntriesList list with the xRef entries that was written * @return a integer array with the ranges */ protected Integer[] getXRefRanges(List xRefEntriesList) { int nr = 0; int last = -2; int count = 1; ArrayList list = new ArrayList(); for( Object object : xRefEntriesList ) { nr = (int)((COSWriterXRefEntry)object).getKey().getNumber(); if (nr == last + 1) { ++count; last = nr; } else if (last == -2) { last = nr; } else { list.add(last - count + 1); list.add(count); last = nr; count = 1; } } // If no new entry is found, we need to write out the last result if(xRefEntriesList.size() > 0) { list.add(last - count + 1); list.add(count); } return list.toArray(new Integer[list.size()]); } /** * This will get the object key for the object. * * @param obj The object to get the key for. * * @return The object key for the object. */ private COSObjectKey getObjectKey( COSBase obj ) { COSBase actual = obj; if( actual instanceof COSObject ) { actual = ((COSObject)obj).getObject(); } COSObjectKey key = null; if( actual != null ) { key = objectKeys.get(actual); } if( key == null ) { key = objectKeys.get(obj); } if (key == null) { setNumber(getNumber()+1); key = new COSObjectKey(getNumber(),0); objectKeys.put(obj, key); if( actual != null ) { objectKeys.put(actual, key); } } return key; } /** * visitFromArray method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromArray( COSArray obj ) throws COSVisitorException { try { int count = 0; getStandardOutput().write(ARRAY_OPEN); for (Iterator i = obj.iterator(); i.hasNext();) { COSBase current = i.next(); if( current instanceof COSDictionary ) { if (current.isDirect()) { visitFromDictionary((COSDictionary)current); } else { addObjectToWrite( current ); writeReference( current ); } } else if( current instanceof COSObject ) { COSBase subValue = ((COSObject)current).getObject(); if (incrementalUpdate || subValue instanceof COSDictionary || subValue == null) { addObjectToWrite( current ); writeReference( current ); } else { subValue.accept( this ); } } else if( current == null ) { COSNull.NULL.accept( this ); } else if( current instanceof COSString ) { COSString copy = new COSString(); copy.append(((COSString)current).getBytes()); copy.accept(this); } else { current.accept(this); } count++; if (i.hasNext()) { if (count % 10 == 0) { getStandardOutput().writeEOL(); } else { getStandardOutput().write(SPACE); } } } getStandardOutput().write(ARRAY_CLOSE); getStandardOutput().writeEOL(); return null; } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromBoolean method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromBoolean(COSBoolean obj) throws COSVisitorException { try { obj.writePDF( getStandardOutput() ); return null; } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromDictionary method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromDictionary(COSDictionary obj) throws COSVisitorException { try { getStandardOutput().write(DICT_OPEN); getStandardOutput().writeEOL(); for (Map.Entry entry : obj.entrySet()) { COSBase value = entry.getValue(); if (value != null) { entry.getKey().accept(this); getStandardOutput().write(SPACE); if( value instanceof COSDictionary ) { COSDictionary dict = (COSDictionary)value; if (!incrementalUpdate) { // write all XObjects as direct objects, this will save some size COSBase item = dict.getItem(COSName.XOBJECT); if (item != null) { item.setDirect(true); } item = dict.getItem(COSName.RESOURCES); if (item != null) { item.setDirect(true); } } if(dict.isDirect()) { // If the object should be written direct, we need // to pass the dictionary to the visitor again. visitFromDictionary(dict); } else { addObjectToWrite( dict ); writeReference( dict ); } } else if( value instanceof COSObject ) { COSBase subValue = ((COSObject)value).getObject(); if (incrementalUpdate || subValue instanceof COSDictionary || subValue == null) { addObjectToWrite( value ); writeReference( value ); } else { subValue.accept( this ); } } else { // If we reach the pdf signature, we need to determinate the position of the // content and byterange if(reachedSignature && COSName.CONTENTS.equals(entry.getKey())) { signaturePosition = new int[2]; signaturePosition[0] = (int)getStandardOutput().getPos(); value.accept(this); signaturePosition[1] = (int)getStandardOutput().getPos(); } else if(reachedSignature && COSName.BYTERANGE.equals(entry.getKey())) { byterangePosition = new int[2]; byterangePosition[0] = (int)getStandardOutput().getPos()+1; value.accept(this); byterangePosition[1] = (int)getStandardOutput().getPos()-1; reachedSignature = false; } else { value.accept(this); } } getStandardOutput().writeEOL(); } else { //then we won't write anything, there are a couple cases //were the value of an entry in the COSDictionary will //be a dangling reference that points to nothing //so we will just not write out the entry if that is the case } } getStandardOutput().write(DICT_CLOSE); getStandardOutput().writeEOL(); return null; } catch( IOException e ) { throw new COSVisitorException(e); } } /** * The visit from document method. * * @param doc The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromDocument(COSDocument doc) throws COSVisitorException { try { if(!incrementalUpdate) { doWriteHeader(doc); } doWriteBody(doc); // get the previous trailer COSDictionary trailer = doc.getTrailer(); long hybridPrev = -1; if (trailer != null) { hybridPrev = trailer.getLong(COSName.XREF_STM); } if(incrementalUpdate) { doWriteXRefInc(doc, hybridPrev); } else { doWriteXRef(doc); } // the trailer section should only be used for xref tables not for xref streams if (!incrementalUpdate || !doc.isXRefStream() || hybridPrev != -1) { doWriteTrailer(doc); } // write endof getStandardOutput().write(STARTXREF); getStandardOutput().writeEOL(); getStandardOutput().write(String.valueOf(getStartxref()).getBytes("ISO-8859-1")); getStandardOutput().writeEOL(); getStandardOutput().write(EOF); getStandardOutput().writeEOL(); if(incrementalUpdate) { doWriteSignature(doc); } return null; } catch (IOException e) { throw new COSVisitorException(e); } catch (SignatureException e) { throw new COSVisitorException(e); } } /** * visitFromFloat method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromFloat(COSFloat obj) throws COSVisitorException { try { obj.writePDF( getStandardOutput() ); return null; } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromFloat method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromInt(COSInteger obj) throws COSVisitorException { try { obj.writePDF( getStandardOutput() ); return null; } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromName method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromName(COSName obj) throws COSVisitorException { try { obj.writePDF( getStandardOutput() ); return null; } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromNull method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromNull(COSNull obj) throws COSVisitorException { try { obj.writePDF( getStandardOutput() ); return null; } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromObjRef method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. */ public void writeReference(COSBase obj) throws COSVisitorException { try { COSObjectKey key = getObjectKey(obj); getStandardOutput().write(String.valueOf(key.getNumber()).getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(String.valueOf(key.getGeneration()).getBytes("ISO-8859-1")); getStandardOutput().write(SPACE); getStandardOutput().write(REFERENCE); } catch (IOException e) { throw new COSVisitorException(e); } } /** * visitFromStream method comment. * * @param obj The object that is being visited. * * @throws COSVisitorException If there is an exception while visiting this object. * * @return null */ public Object visitFromStream(COSStream obj) throws COSVisitorException { InputStream input = null; try { if (willEncrypt) { document.getSecurityHandler().encryptStream(obj, currentObjectKey.getNumber() , currentObjectKey.getGeneration()); } COSObject lengthObject = null; // check if the length object is required to be direct, like in // a cross reference stream dictionary COSBase lengthEntry = obj.getDictionaryObject(COSName.LENGTH); String type = obj.getNameAsString(COSName.TYPE); if (lengthEntry != null && lengthEntry.isDirect() || "XRef".equals(type)) { // the length might be the non encoded length, // set the real one as direct object COSInteger cosInteger = COSInteger.get(obj.getFilteredLength()); cosInteger.setDirect(true); obj.setItem(COSName.LENGTH, cosInteger); } else { // make the length an implicit indirect object // set the length of the stream and write stream dictionary lengthObject = new COSObject(null); obj.setItem(COSName.LENGTH, lengthObject); } input = obj.getFilteredStream(); //obj.accept(this); // write the stream content visitFromDictionary(obj); getStandardOutput().write(STREAM); getStandardOutput().writeCRLF(); byte[] buffer = new byte[1024]; int amountRead = 0; int totalAmountWritten = 0; while ((amountRead = input.read(buffer, 0, 1024)) != -1) { getStandardOutput().write(buffer, 0, amountRead); totalAmountWritten += amountRead; } // set the length as an indirect object if (lengthObject != null) { lengthObject.setObject(COSInteger.get(totalAmountWritten)); } getStandardOutput().writeCRLF(); getStandardOutput().write(ENDSTREAM); getStandardOutput().writeEOL(); return null; } catch (Exception e) { throw new COSVisitorException(e); } finally { if (input != null) { try { input.close(); } catch (IOException e) { throw new COSVisitorException(e); } } } } /** * visitFromString method comment. * * @param obj The object that is being visited. * * @return null * * @throws COSVisitorException If there is an exception while visiting this object. */ public Object visitFromString(COSString obj) throws COSVisitorException { try { if(willEncrypt) { document.getSecurityHandler().encryptString( obj, currentObjectKey.getNumber(), currentObjectKey.getGeneration()); } obj.writePDF( getStandardOutput() ); } catch (Exception e) { throw new COSVisitorException(e); } return null; } /** * This will write the pdf document. * * @param doc The document to write. * * @throws COSVisitorException If an error occurs while generating the data. */ public void write(COSDocument doc) throws COSVisitorException { PDDocument pdDoc = new PDDocument( doc ); write( pdDoc ); } /** * This will write the pdf document. * * @param doc The document to write. * * @throws COSVisitorException If an error occurs while generating the data. * @throws IllegalStateException If the document has an encryption dictionary but no protection * policy. */ public void write(PDDocument doc) throws COSVisitorException { Long idTime = doc.getDocumentId() == null ? System.currentTimeMillis() : doc.getDocumentId(); document = doc; if(incrementalUpdate) { prepareIncrement(doc); } // if the document says we should remove encryption, then we shouldn't encrypt if(doc.isAllSecurityToBeRemoved()) { this.willEncrypt = false; // also need to get rid of the "Encrypt" in the trailer so readers // don't try to decrypt a document which is not encrypted COSDocument cosDoc = doc.getDocument(); COSDictionary trailer = cosDoc.getTrailer(); trailer.removeItem(COSName.ENCRYPT); } else { SecurityHandler securityHandler = document.getSecurityHandler(); if(securityHandler != null) { try { if (!securityHandler.hasProtectionPolicy()) { throw new IllegalStateException("PDF contains an encryption dictionary, please remove it with " + "setAllSecurityToBeRemoved() or set a protection policy with protect()"); } securityHandler.prepareDocumentForEncryption(document); this.willEncrypt = true; } catch(IOException e) { throw new COSVisitorException( e ); } catch(CryptographyException e) { throw new COSVisitorException( e ); } } else { this.willEncrypt = false; } } COSDocument cosDoc = document.getDocument(); COSDictionary trailer = cosDoc.getTrailer(); COSArray idArray = (COSArray)trailer.getDictionaryObject( COSName.ID ); boolean missingID = true; // check for an existing documentID if (idArray != null && idArray.size() == 2) { missingID = false; } if( missingID || incrementalUpdate) { try { //algorithm says to use time/path/size/values in doc to generate //the id. We don't have path or size, so do the best we can MessageDigest md = MessageDigest.getInstance( "MD5" ); md.update( Long.toString(idTime).getBytes("ISO-8859-1") ); COSDictionary info = (COSDictionary)trailer.getDictionaryObject( COSName.INFO ); if( info != null ) { Iterator values = info.getValues().iterator(); while( values.hasNext() ) { md.update( values.next().toString().getBytes("ISO-8859-1") ); } } // reuse origin documentID if available as first value COSString firstID = missingID ? new COSString( md.digest() ) : (COSString)idArray.get(0); // it's ok to use the same ID for the second part if the ID is created for the first time COSString secondID = missingID ? firstID : new COSString( md.digest() ); idArray = new COSArray(); idArray.add( firstID ); idArray.add( secondID ); trailer.setItem( COSName.ID, idArray ); } catch( NoSuchAlgorithmException e ) { throw new COSVisitorException( e ); } catch( UnsupportedEncodingException e ) { throw new COSVisitorException( e ); } } cosDoc.accept(this); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/0000755000000000000000000000000012645757432022276 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/TIFFFaxDecoder.java0000644000000000000000000015412512645757432025626 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.pdfbox.filter; class TIFFFaxDecoder { private int bitPointer, bytePointer; private byte[] data; private int w, h; private int fillOrder; // Data structures needed to store changing elements for the previous // and the current scanline private int changingElemSize = 0; private int[] prevChangingElems; private int[] currChangingElems; // Element at which to start search in getNextChangingElement private int lastChangingElement = 0; private int compression = 2; // Variables set by T4Options private int uncompressedMode = 0; private int fillBits = 0; private int oneD; 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, }; /** * @param fillOrder The fill order of the compressed data bytes. * @param w The width of the image in pixels * @param h The height of the image in pixels */ public TIFFFaxDecoder(int fillOrder, int w, int h) { this.fillOrder = fillOrder; this.w = w; this.h = h; this.bitPointer = 0; this.bytePointer = 0; this.prevChangingElems = new int[w + 1]; this.currChangingElems = new int[w + 1]; } // One-dimensional decoding methods public void decode1D(byte[] buffer, byte[] compData, int startX, int height) { this.data = compData; int lineOffset = 0; int scanlineStride = (w + 7)/8; bitPointer = 0; bytePointer = 0; for (int i = 0; i < height; i++) { decodeNextScanline(buffer, lineOffset, startX); lineOffset += scanlineStride; } } public void decodeNextScanline(byte[] buffer, int lineOffset, int bitOffset) { int bits = 0, code = 0, isT = 0; int current, entry, twoBits; boolean isWhite = true; // Initialize starting of the changing elements array changingElemSize = 0; // While scanline not complete while (bitOffset < w) { while (isWhite) { // White run current = nextNBits(10); entry = white[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x0f; if (bits == 12) { // Additional Make up code // Get the next 2 bits twoBits = nextLesserThan8Bits(2); // Consolidate the 2 new bits and last 2 bits into 4 bits current = ((current << 2) & 0x000c) | twoBits; entry = 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 throw new RuntimeException("EOL encountered in white run."); } else { // 11 bits - 0000 0111 1111 1111 = 0x07ff code = (entry >>> 5) & 0x07ff; bitOffset += code; updatePointer(10 - bits); if (isT == 0) { isWhite = false; currChangingElems[changingElemSize++] = bitOffset; } } } // Check whether this run completed one width, if so // advance to next byte boundary for compression = 2. if (bitOffset == w) { if (compression == 2) { advancePointer(); } break; } while (!isWhite) { // Black run current = nextLesserThan8Bits(4); entry = 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 code throw new RuntimeException("EOL encountered in black run."); } else { setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(9 - bits); if (isT == 0) { isWhite = true; currChangingElems[changingElemSize++] = bitOffset; } } } else if (code == 200) { // Is a Terminating code current = nextLesserThan8Bits(2); entry = twoBitBlack[current]; code = (entry >>> 5) & 0x07ff; bits = (entry >>> 1) & 0x0f; setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(2 - bits); isWhite = true; currChangingElems[changingElemSize++] = bitOffset; } else { // Is a Terminating code setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(4 - bits); isWhite = true; currChangingElems[changingElemSize++] = bitOffset; } } // Check whether this run completed one width if (bitOffset == w) { if (compression == 2) { advancePointer(); } break; } } currChangingElems[changingElemSize++] = bitOffset; } // Two-dimensional decoding methods public void decode2D(byte[] buffer, byte[] compData, int startX, int height, long tiffT4Options) { this.data = compData; compression = 3; bitPointer = 0; bytePointer = 0; int scanlineStride = (w + 7)/8; int a0, a1, b1, b2; int[] b = new int[2]; int entry, code, bits; boolean isWhite; int currIndex = 0; int[] temp; // fillBits - dealt with this in readEOL // 1D/2D encoding - dealt with this in readEOL // uncompressedMode - haven't dealt with this yet. oneD = (int)(tiffT4Options & 0x01); uncompressedMode = (int)((tiffT4Options & 0x02) >> 1); fillBits = (int)((tiffT4Options & 0x04) >> 2); // The data must start with an EOL code if (readEOL() != 1) { throw new RuntimeException("First scanline must be 1D encoded."); } int lineOffset = 0; int bitOffset; // Then the 1D encoded scanline data will occur, changing elements // array gets set. decodeNextScanline(buffer, lineOffset, startX); lineOffset += scanlineStride; for (int lines = 1; lines < height; lines++) { // Every line must begin with an EOL followed by a bit which // indicates whether the following scanline is 1D or 2D encoded. if (readEOL() == 0) { // 2D encoded scanline follows // Initialize previous scanlines changing elements, and // initialize current scanline's changing elements array temp = prevChangingElems; prevChangingElems = currChangingElems; currChangingElems = temp; currIndex = 0; // a0 has to be set just before the start of this scanline. a0 = -1; isWhite = true; bitOffset = startX; lastChangingElement = 0; while (bitOffset < w) { // Get the next changing element getNextChangingElement(a0, isWhite, b); b1 = b[0]; b2 = b[1]; // Get the next seven bits entry = nextLesserThan8Bits(7); // Run these through the 2DCodes table entry = (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; currChangingElems[currIndex++] = bitOffset; number = decodeBlackCodeWord(); setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; currChangingElems[currIndex++] = bitOffset; } else { number = decodeBlackCodeWord(); setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; currChangingElems[currIndex++] = bitOffset; number = decodeWhiteCodeWord(); bitOffset += number; currChangingElems[currIndex++] = bitOffset; } a0 = bitOffset; } else if (code <= 8) { // Vertical a1 = b1 + (code - 5); currChangingElems[currIndex++] = a1; // We write the current color till a1 - 1 pos, // since a1 is where the next color starts if (!isWhite) { setToBlack(buffer, lineOffset, bitOffset, a1 - bitOffset); } bitOffset = a0 = a1; isWhite = !isWhite; updatePointer(7 - bits); } else { throw new RuntimeException("Invalid code encountered while decoding 2D group 3 compressed data."); } } // Add the changing element beyond the current scanline for the // other color too currChangingElems[currIndex++] = bitOffset; changingElemSize = currIndex; } else { // 1D encoded scanline follows decodeNextScanline(buffer, lineOffset, startX); } lineOffset += scanlineStride; } } public synchronized void decodeT6(byte[] buffer, byte[] compData, int startX, int height, long tiffT6Options, boolean encodedByteAlign) { this.data = compData; compression = 4; bitPointer = 0; bytePointer = 0; int scanlineStride = (w + 7)/8; int a0, a1, b1, b2; int entry, code, bits; boolean isWhite; int currIndex; int[] temp; // Return values from getNextChangingElement int[] b = new int[2]; // uncompressedMode - have written some code for this, but this // has not been tested due to lack of test images using this optional uncompressedMode = (int)((tiffT6Options & 0x02) >> 1); // Local cached reference int[] cce = currChangingElems; // Assume invisible preceding row of all white pixels and insert // both black and white changing elements beyond the end of this // imaginary scanline. changingElemSize = 0; cce[changingElemSize++] = w; cce[changingElemSize++] = w; int lineOffset = 0; int bitOffset; for (int lines = 0; lines < height; lines++) { if (encodedByteAlign && bitPointer != 0) { bitPointer = 0; bytePointer++; } // a0 has to be set just before the start of the scanline. a0 = -1; isWhite = true; // Assign the changing elements of the previous scanline to // prevChangingElems and start putting this new scanline's // changing elements into the currChangingElems. temp = prevChangingElems; prevChangingElems = currChangingElems; cce = currChangingElems = temp; currIndex = 0; // Start decoding the scanline at startX in the raster bitOffset = startX; // Reset search start position for getNextChangingElement lastChangingElement = 0; // Till one whole scanline is decoded while (bitOffset < w) { // Get the next changing element getNextChangingElement(a0, isWhite, b); b1 = b[0]; b2 = b[1]; // Get the next seven bits entry = nextLesserThan8Bits(7); // Run these through the 2DCodes table entry = (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) { setToBlack(buffer, lineOffset, bitOffset, b2 - bitOffset); } bitOffset = a0 = b2; // Set pointer to only consume the correct number of bits. updatePointer(7 - bits); } else if (code == 1) { // Horizontal // Set pointer to only consume the correct number of bits. updatePointer(7 - bits); // identify the next 2 alternating color codes. int number; if (isWhite) { // Following are white and black runs number = decodeWhiteCodeWord(); bitOffset += number; cce[currIndex++] = bitOffset; number = decodeBlackCodeWord(); setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; cce[currIndex++] = bitOffset; } else { // First a black run and then a white run follows number = decodeBlackCodeWord(); setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; cce[currIndex++] = bitOffset; number = decodeWhiteCodeWord(); bitOffset += number; cce[currIndex++] = bitOffset; } a0 = bitOffset; } else if (code <= 8) { // Vertical a1 = b1 + (code - 5); cce[currIndex++] = a1; // We write the current color till a1 - 1 pos, // since a1 is where the next color starts if (!isWhite) { setToBlack(buffer, lineOffset, bitOffset, a1 - bitOffset); } bitOffset = a0 = a1; isWhite = !isWhite; updatePointer(7 - bits); } else if (code == 11) { if (nextLesserThan8Bits(3) != 7) { throw new RuntimeException("Invalid code encountered while decoding 2D group 4 compressed data."); } int zeros = 0; boolean exit = false; while (!exit) { while (nextLesserThan8Bits(1) != 1) { zeros++; } if (zeros > 5) { // Exit code // Zeros before exit code zeros = zeros - 6; if (!isWhite && (zeros > 0)) { cce[currIndex++] = bitOffset; } // Zeros before the exit code bitOffset += zeros; if (zeros > 0) { // Some zeros have been written isWhite = true; } // Read in the bit which specifies the color of // the following run if (nextLesserThan8Bits(1) == 0) { if (!isWhite) { cce[currIndex++] = bitOffset; } isWhite = true; } else { if (isWhite) { cce[currIndex++] = bitOffset; } isWhite = false; } exit = true; } if (zeros == 5) { if (!isWhite) { cce[currIndex++] = bitOffset; } bitOffset += zeros; // Last thing written was white isWhite = true; } else { bitOffset += zeros; cce[currIndex++] = bitOffset; setToBlack(buffer, lineOffset, bitOffset, 1); ++bitOffset; // Last thing written was black isWhite = false; } } } else { throw new RuntimeException("Invalid code encountered while decoding 2D group 4 compressed data."); } } // Add the changing element beyond the current scanline for the // other color too cce[currIndex++] = bitOffset; // Number of changing elements in this scanline. changingElemSize = currIndex; lineOffset += scanlineStride; } } private void setToBlack(byte[] buffer, int lineOffset, int bitOffset, int numBits) { int bitNum = 8*lineOffset + bitOffset; int lastBit = bitNum + numBits; int byteNum = bitNum >> 3; // Handle bits in first byte int shift = bitNum & 0x7; if (shift > 0) { int maskVal = 1 << (7 - shift); byte val = buffer[byteNum]; while (maskVal > 0 && bitNum < lastBit) { val |= maskVal; maskVal >>= 1; ++bitNum; } buffer[byteNum] = val; } // Fill in 8 bits at a time byteNum = bitNum >> 3; while (bitNum < lastBit - 7) { buffer[byteNum++] = (byte)255; bitNum += 8; } // Fill in remaining bits while (bitNum < lastBit) { byteNum = bitNum >> 3; buffer[byteNum] |= 1 << (7 - (bitNum & 0x7)); ++bitNum; } } // Returns run length private int decodeWhiteCodeWord() { int current, entry, bits, isT, twoBits, code = -1; int runLength = 0; boolean isWhite = true; while (isWhite) { current = nextNBits(10); entry = white[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x0f; if (bits == 12) { // Additional Make up code // Get the next 2 bits twoBits = nextLesserThan8Bits(2); // Consolidate the 2 new bits and last 2 bits into 4 bits current = ((current << 2) & 0x000c) | twoBits; entry = 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."); } else if (bits == 15) { // EOL throw new RuntimeException("EOL encountered in white run."); } else { // 11 bits - 0000 0111 1111 1111 = 0x07ff code = (entry >>> 5) & 0x07ff; runLength += code; updatePointer(10 - bits); if (isT == 0) { isWhite = false; } } } return runLength; } // Returns run length private int decodeBlackCodeWord() { int current, entry, bits, isT, 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 encountered in black run."); } else { runLength += code; updatePointer(9 - bits); if (isT == 0) { isWhite = true; } } } else if (code == 200) { // Is a Terminating code current = nextLesserThan8Bits(2); entry = 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; } private int readEOL() { if (fillBits == 0) { if (nextNBits(12) != 1) { throw new RuntimeException("Scanline must begin with EOL."); } } else if (fillBits == 1) { // First EOL code word xxxx 0000 0000 0001 will occur // As many fill bits will be present as required to make // the EOL code of 12 bits end on a byte boundary. int bitsLeft = 8 - bitPointer; if (nextNBits(bitsLeft) != 0) { throw new RuntimeException("All fill bits preceding EOL code must be 0."); } // If the number of bitsLeft is less than 8, then to have a 12 // bit EOL sequence, two more bytes are certainly going to be // required. The first of them has to be all zeros, so ensure // that. if (bitsLeft < 4) { if (nextNBits(8) != 0) { throw new RuntimeException("All fill bits preceding EOL code must be 0."); } } // There might be a random number of fill bytes with 0s, so // loop till the EOL of 0000 0001 is found, as long as all // the bytes preceding it are 0's. int n; while ((n = nextNBits(8)) != 1) { // If not all zeros if (n != 0) { throw new RuntimeException("All fill bits preceding EOL code must be 0."); } } } // If one dimensional encoding mode, then always return 1 if (oneD == 0) { return 1; } else { // Otherwise for 2D encoding mode, // The next one bit signifies 1D/2D encoding of next line. return nextLesserThan8Bits(1); } } private void getNextChangingElement(int a0, boolean isWhite, int[] ret) { // Local copies of instance variables int[] pce = this.prevChangingElems; int ces = this.changingElemSize; // If the previous match was at an odd element, we still // have to search the preceeding element. // int start = lastChangingElement & ~0x1; int start = lastChangingElement > 0 ? lastChangingElement - 1 : 0; if (isWhite) { start &= ~0x1; // Search even numbered elements } else { start |= 0x1; // Search odd numbered elements } int i = start; for (; i < ces; i += 2) { int temp = pce[i]; if (temp > a0) { lastChangingElement = i; ret[0] = temp; break; } } if (i + 1 < ces) { ret[1] = pce[i + 1]; } } private int nextNBits(int bitsToGet) { byte b, next, next2next; int l = data.length - 1; int bp = this.bytePointer; if (fillOrder == 1) { b = data[bp]; if (bp == l) { next = 0x00; next2next = 0x00; } else if ((bp + 1) == l) { next = data[bp + 1]; next2next = 0x00; } else { next = data[bp + 1]; next2next = data[bp + 2]; } } else if (fillOrder == 2) { b = flipTable[data[bp] & 0xff]; if (bp == l) { next = 0x00; next2next = 0x00; } else if ((bp + 1) == l) { next = flipTable[data[bp + 1] & 0xff]; next2next = 0x00; } else { next = flipTable[data[bp + 1] & 0xff]; next2next = flipTable[data[bp + 2] & 0xff]; } } else { throw new RuntimeException("TIFF_FILL_ORDER tag must be either 1 or 2."); } int bitsLeft = 8 - bitPointer; int bitsFromNextByte = bitsToGet - bitsLeft; int bitsFromNext2NextByte = 0; if (bitsFromNextByte > 8) { bitsFromNext2NextByte = bitsFromNextByte - 8; bitsFromNextByte = 8; } bytePointer++; int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft); int i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); int i3 = 0; if (bitsFromNext2NextByte != 0) { i2 <<= bitsFromNext2NextByte; i3 = (next2next & table2[bitsFromNext2NextByte]) >>> (8 - bitsFromNext2NextByte); i2 |= i3; bytePointer++; bitPointer = bitsFromNext2NextByte; } else { if (bitsFromNextByte == 8) { bitPointer = 0; bytePointer++; } else { bitPointer = bitsFromNextByte; } } int i = i1 | i2; return i; } private int nextLesserThan8Bits(int bitsToGet) { byte b, next; int l = data.length - 1; int bp = this.bytePointer; if (fillOrder == 1) { b = data[bp]; if (bp == l) { next = 0x00; } else { next = data[bp + 1]; } } else if (fillOrder == 2) { b = flipTable[data[bp] & 0xff]; if (bp == l) { next = 0x00; } else { next = flipTable[data[bp + 1] & 0xff]; } } else { throw new RuntimeException("TIFF_FILL_ORDER tag must be either 1 or 2."); } int bitsLeft = 8 - bitPointer; int bitsFromNextByte = bitsToGet - bitsLeft; int shift = bitsLeft - bitsToGet; int i1, i2; if (shift >= 0) { i1 = (b & table1[bitsLeft]) >>> shift; bitPointer += bitsToGet; if (bitPointer == 8) { bitPointer = 0; bytePointer++; } } else { i1 = (b & table1[bitsLeft]) << (-shift); i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); i1 |= i2; bytePointer++; bitPointer = bitsFromNextByte; } return i1; } // Move pointer backwards by given amount of bits private void updatePointer(int bitsToMoveBack) { int i = bitPointer - bitsToMoveBack; if (i < 0) { bytePointer--; bitPointer = 8 + i; } else { bitPointer = i; } } // Move to the next byte boundary private boolean advancePointer() { if (bitPointer != 0) { bytePointer++; bitPointer = 0; } return true; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java0000644000000000000000000001436212645757432025350 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.DataFormatException; import java.util.zip.DeflaterOutputStream; import java.util.zip.Inflater; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This is the used for the FlateDecode filter. * * @author Ben Litchfield * @author Marcel Kammer */ public class FlateFilter implements Filter { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(FlateFilter.class); private static final int BUFFER_SIZE = 16348; /** * {@inheritDoc} */ public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { COSBase baseObj = options.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP); COSDictionary dict = null; if (baseObj instanceof COSDictionary) { dict = (COSDictionary) baseObj; } else if (baseObj instanceof COSArray) { COSArray paramArray = (COSArray) baseObj; if (filterIndex < paramArray.size()) { dict = (COSDictionary) paramArray.getObject(filterIndex); } } else if (baseObj != null) { throw new IOException("Error: Expected COSArray or COSDictionary and not " + baseObj.getClass().getName()); } int predictor = -1; if (dict != null) { predictor = dict.getInt(COSName.PREDICTOR); } try { // Decode data using given predictor if (predictor > 1) { int colors = Math.min(dict.getInt(COSName.COLORS, 1), 32); int bitsPerPixel = dict.getInt(COSName.BITS_PER_COMPONENT, 8); int columns = dict.getInt(COSName.COLUMNS, 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); decompress(compressedData, baos); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); Predictor.decodePredictor(predictor, colors, bitsPerPixel, columns, bais, result); result.flush(); baos.reset(); bais.reset(); } else { decompress(compressedData, result); } } catch (DataFormatException exception) { // if the stream is corrupt a DataFormatException may occur LOG.error("FlateFilter: stop reading corrupt stream due to a DataFormatException"); // re-throw the exception, caller has to handle it IOException io = new IOException(); io.initCause(exception); throw io; } } // Use Inflater instead of InflateInputStream to avoid an EOFException due to a probably // missing Z_STREAM_END, see PDFBOX-1232 for details private void decompress(InputStream in, OutputStream out) throws IOException, DataFormatException { byte[] buf = new byte[2048]; int read = in.read(buf); if(read > 0) { Inflater inflater = new Inflater(); inflater.setInput(buf,0,read); byte[] res = new byte[32]; boolean dataWritten = false; while(true) { int resRead = 0; try { resRead = inflater.inflate(res); } catch(DataFormatException exception) { if (dataWritten) { // some data could be read -> don't throw an exception LOG.warn("FlateFilter: premature end of stream due to a DataFormatException"); break; } else { // nothing could be read -> re-throw exception throw exception; } } if(resRead != 0) { out.write(res,0,resRead); dataWritten = true; continue; } if(inflater.finished() || inflater.needsDictionary() || in.available() == 0) { break; } read = in.read(buf); inflater.setInput(buf,0,read); } } out.close(); } /** * {@inheritDoc} */ public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { DeflaterOutputStream out = new DeflaterOutputStream(result); int amountRead = 0; int mayRead = rawData.available(); if (mayRead > 0) { byte[] buffer = new byte[Math.min(mayRead,BUFFER_SIZE)]; while ((amountRead = rawData.read(buffer, 0, Math.min(mayRead,BUFFER_SIZE))) != -1) { out.write(buffer, 0, amountRead); } } out.close(); result.flush(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/Predictor.java0000644000000000000000000002454412645757432025105 0ustar rootroot/* * Copyright 2014 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.pdfbox.io.IOUtils; /** * Helper class to contain predictor decoding used by Flate and LZW filter. * To see the history, look at the FlateFilter class. */ public class Predictor { static void decodePredictor(int predictor, int colors, int bitsPerComponent, int columns, InputStream in, OutputStream out) throws IOException { if (predictor == 1) { // no prediction IOUtils.copy(in, out); } else { // calculate sizes final int bitsPerPixel = colors * bitsPerComponent; final int bytesPerPixel = (bitsPerPixel + 7) / 8; final int rowlength = (columns * bitsPerPixel + 7) / 8; byte[] actline = new byte[rowlength]; byte[] lastline = new byte[rowlength]; int linepredictor = predictor; while (in.available() > 0) { // test for PNG predictor; each value >= 10 (not only 15) indicates usage of PNG predictor if (predictor >= 10) { // PNG predictor; each row starts with predictor type (0, 1, 2, 3, 4) // read per line predictor linepredictor = in.read(); if (linepredictor == -1) { return; } // add 10 to tread value 0 as 10, 1 as 11, ... linepredictor += 10; } // read line int i, offset = 0; while (offset < rowlength && ((i = in.read(actline, offset, rowlength - offset)) != -1)) { offset += i; } // do prediction as specified in PNG-Specification 1.2 switch (linepredictor) { case 2: // PRED TIFF SUB if (bitsPerComponent == 8) { // for 8 bits per component it is the same algorithm as PRED SUB of PNG format for (int p = bytesPerPixel; p < rowlength; p++) { int sub = actline[p] & 0xff; int left = actline[p - bytesPerPixel] & 0xff; actline[p] = (byte) (sub + left); } break; } if (bitsPerComponent == 16) { for (int p = bytesPerPixel; p < rowlength; p += 2) { int sub = ((actline[p] & 0xff) << 8) + (actline[p + 1] & 0xff); int left = (((actline[p - bytesPerPixel] & 0xff) << 8) + (actline[p - bytesPerPixel + 1] & 0xff)); actline[p] = (byte) (((sub + left) >> 8) & 0xff); actline[p + 1] = (byte) ((sub + left) & 0xff); } break; } if (bitsPerComponent == 1 && colors == 1) { // bytesPerPixel cannot be used: // "A row shall occupy a whole number of bytes, rounded up if necessary. // Samples and their components shall be packed into bytes // from high-order to low-order bits." for (int p = 0; p < rowlength; p++) { for (int bit = 7; bit >= 0; --bit) { int sub = (actline[p] >> bit) & 1; if (p == 0 && bit == 7) { continue; } int left; if (bit == 7) { // use bit #0 from previous byte left = actline[p - 1] & 1; } else { // use "previous" bit left = (actline[p] >> (bit + 1)) & 1; } if (((sub + left) & 1) == 0) { // reset bit actline[p] = (byte) (actline[p] & ~(1 << bit)); } else { // set bit actline[p] = (byte) (actline[p] | (1 << bit)); } } } break; } // everything else, i.e. bpc 2 and 4, but has been tested for bpc 1 and 8 too int elements = columns * colors; for (int p = colors; p < elements; ++p) { int bytePosSub = p * bitsPerComponent / 8; int bitPosSub = 8 - p * bitsPerComponent % 8 - bitsPerComponent; int bytePosLeft = (p - colors) * bitsPerComponent / 8; int bitPosLeft = 8 - (p - colors) * bitsPerComponent % 8 - bitsPerComponent; int sub = getBitSeq(actline[bytePosSub], bitPosSub, bitsPerComponent); int left = getBitSeq(actline[bytePosLeft], bitPosLeft, bitsPerComponent); actline[bytePosSub] = (byte) calcSetBitSeq(actline[bytePosSub], bitPosSub, bitsPerComponent, sub + left); } break; case 10: // PRED NONE // do nothing break; case 11: // PRED SUB for (int p = bytesPerPixel; p < rowlength; p++) { int sub = actline[p]; int left = actline[p - bytesPerPixel]; actline[p] = (byte) (sub + left); } break; case 12: // PRED UP for (int p = 0; p < rowlength; p++) { int up = actline[p] & 0xff; int prior = lastline[p] & 0xff; actline[p] = (byte) ((up + prior) & 0xff); } break; case 13: // PRED AVG for (int p = 0; p < rowlength; p++) { int avg = actline[p] & 0xff; int left = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff : 0; int up = lastline[p] & 0xff; actline[p] = (byte) ((avg + (left + up) / 2) & 0xff); } break; case 14: // PRED PAETH for (int p = 0; p < rowlength; p++) { int paeth = actline[p] & 0xff; int a = p - bytesPerPixel >= 0 ? actline[p - bytesPerPixel] & 0xff : 0;// left int b = lastline[p] & 0xff;// upper int c = p - bytesPerPixel >= 0 ? lastline[p - bytesPerPixel] & 0xff : 0;// upperleft int value = a + b - c; int absa = Math.abs(value - a); int absb = Math.abs(value - b); int absc = Math.abs(value - c); if (absa <= absb && absa <= absc) { actline[p] = (byte) ((paeth + a) & 0xff); } else if (absb <= absc) { actline[p] = (byte) ((paeth + b) & 0xff); } else { actline[p] = (byte) ((paeth + c) & 0xff); } } break; default: break; } System.arraycopy(actline, 0, lastline, 0, rowlength); out.write(actline, 0, actline.length); } } } // get value from bit interval from a byte static int getBitSeq(int by, int startBit, int bitSize) { int mask = ((1 << bitSize) - 1); return (by >>> startBit) & mask; } // set value in a bit interval and return that value static int calcSetBitSeq(int by, int startBit, int bitSize, int val) { int mask = ((1 << bitSize) - 1); int truncatedVal = val & mask; mask = ~(mask << startBit); return (by & mask) | (truncatedVal << startBit); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/CryptFilter.java0000644000000000000000000000473712645757432025423 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * * @author adam.nichols */ public class CryptFilter implements Filter { /** * {@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { COSName encryptionName = (COSName)options.getDictionaryObject(COSName.NAME); if(encryptionName == null || encryptionName.equals(COSName.IDENTITY)) { // currently the only supported implementation is the Identity crypt filter Filter identityFilter = new IdentityFilter(); identityFilter.decode(compressedData, result, options, filterIndex); } else { throw new IOException("Unsupported crypt filter "+encryptionName.getName()); } } /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { COSName encryptionName = (COSName)options.getDictionaryObject(COSName.NAME); if(encryptionName == null || encryptionName.equals(COSName.IDENTITY)) { // currently the only supported implementation is the Identity crypt filter Filter identityFilter = new IdentityFilter(); identityFilter.encode(rawData, result, options, filterIndex); } else { throw new IOException("Unsupported crypt filter "+encryptionName.getName()); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/package.html0000644000000000000000000000175612645757432024570 0ustar rootroot This package will hold the PDFBox implementations of the filters that are used in PDF documents. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/RunLengthDecodeFilter.java0000644000000000000000000000724712645757432027333 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSDictionary; /** * This is a filter for the RunLength Decoder. * * From the PDF Reference *

 * The RunLengthDecode filter decodes data that has been encoded in a simple
 * byte-oriented format based on run length. The encoded data is a sequence of
 * runs, where each run consists of a length byte followed by 1 to 128 bytes of data. If
 * the length byte is in the range 0 to 127, the following length + 1 (1 to 128) bytes
 * are copied literally during decompression. If length is in the range 129 to 255, the
 * following single byte is to be copied 257 ? length (2 to 128) times during decompression.
 * A length value of 128 denotes EOD.
 *
 * The compression achieved by run-length encoding depends on the input data. In
 * the best case (all zeros), a compression of approximately 64:1 is achieved for long
 * files. The worst case (the hexadecimal sequence 00 alternating with FF) results in
 * an expansion of 127:128.
 * 
* * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class RunLengthDecodeFilter implements Filter { /** * Log instance. */ private static final Log log = LogFactory.getLog(RunLengthDecodeFilter.class); private static final int RUN_LENGTH_EOD = 128; /** * Constructor. */ public RunLengthDecodeFilter() { //default constructor } /** * {@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { int dupAmount = -1; byte[] buffer = new byte[128]; while( (dupAmount = compressedData.read()) != -1 && dupAmount != RUN_LENGTH_EOD ) { if( dupAmount <= 127 ) { int amountToCopy = dupAmount+1; int compressedRead = 0; while( amountToCopy > 0 ) { compressedRead = compressedData.read( buffer, 0, amountToCopy ); result.write( buffer, 0, compressedRead ); amountToCopy -= compressedRead; } } else { int dupByte = compressedData.read(); for( int i=0; i<257-dupAmount; i++ ) { result.write( dupByte ); } } } } /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { log.warn( "RunLengthDecodeFilter.encode is not implemented yet, skipping this stream." ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCII85Filter.java0000644000000000000000000000464512645757432025325 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.pdfbox.io.ASCII85InputStream; import org.apache.pdfbox.io.ASCII85OutputStream; import org.apache.pdfbox.cos.COSDictionary; /** * This is the used for the ASCIIHexDecode filter. * * @author Ben Litchfield * @version $Revision: 1.8 $ */ public class ASCII85Filter implements Filter { /** * {@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { ASCII85InputStream is = null; try { is = new ASCII85InputStream(compressedData); byte[] buffer = new byte[1024]; int amountRead = 0; while( (amountRead = is.read( buffer, 0, 1024) ) != -1 ) { result.write(buffer, 0, amountRead); } result.flush(); } finally { if( is != null ) { is.close(); } } } /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { ASCII85OutputStream os = new ASCII85OutputStream(result); byte[] buffer = new byte[1024]; int amountRead = 0; while( (amountRead = rawData.read( buffer, 0, 1024 )) != -1 ) { os.write( buffer, 0, amountRead ); } os.close(); result.flush(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxDecodeFilter.java0000644000000000000000000001260012645757432026717 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.io.ccitt.CCITTFaxG31DDecodeInputStream; import org.apache.pdfbox.io.ccitt.FillOrderChangeInputStream; /** * This is a filter for the CCITTFax Decoder. * * @author Ben Litchfield * @author Marcel Kammer * @author Paul King * @version $Revision: 1.13 $ */ public class CCITTFaxDecodeFilter implements Filter { /** * Log instance. */ private static final Log log = LogFactory.getLog(CCITTFaxDecodeFilter.class); /** * Constructor. */ public CCITTFaxDecodeFilter() { } /** * {@inheritDoc} */ public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex) throws IOException { COSBase decodeP = options.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP); COSDictionary decodeParms = null; if (decodeP instanceof COSDictionary) { decodeParms = (COSDictionary)decodeP; } else if (decodeP instanceof COSArray) { decodeParms = (COSDictionary)((COSArray)decodeP).getObject(filterIndex); } int cols = 1728, rows = 0; if (decodeParms != null) { cols = decodeParms.getInt(COSName.COLUMNS, 1728); rows = decodeParms.getInt(COSName.ROWS, 0); } int height = options.getInt(COSName.HEIGHT, COSName.H, 0); if (rows > 0 && height > 0) { // ensure that rows doesn't contain implausible data, see PDFBOX-771 rows = Math.min(rows, height); } else { // at least one of the values has to have a valid value rows = Math.max(rows, height); } int k = 0; boolean encodedByteAlign = false; boolean blackIsOne = false; if (decodeParms != null) { k = decodeParms.getInt(COSName.K, 0); encodedByteAlign = decodeParms.getBoolean(COSName.ENCODED_BYTE_ALIGN, false); blackIsOne = decodeParms.getBoolean(COSName.BLACK_IS_1, false); } int arraySize = (cols + 7) / 8 * rows; TIFFFaxDecoder faxDecoder = new TIFFFaxDecoder(1, cols, rows); // TODO possible options?? long tiffOptions = 0; byte[] compressed = IOUtils.toByteArray(compressedData); byte[] decompressed = null; if (k == 0) { InputStream in = new CCITTFaxG31DDecodeInputStream( new ByteArrayInputStream(compressed), cols, rows, encodedByteAlign); in = new FillOrderChangeInputStream(in); //Decorate to change fill order decompressed = IOUtils.toByteArray(in); in.close(); } else if (k > 0) { decompressed = new byte[arraySize]; faxDecoder.decode2D(decompressed, compressed, 0, rows, tiffOptions); } else if (k < 0) { decompressed = new byte[arraySize]; faxDecoder.decodeT6(decompressed, compressed, 0, rows, tiffOptions, encodedByteAlign); } // invert bitmap if (!blackIsOne) { // Inverting the bitmap // Note the previous approach with starting from an IndexColorModel didn't work // reliably. In some cases the image wouldn't be painted for some reason. // So a safe but slower approach was taken. invertBitmap(decompressed); } // repair missing color space if (!options.containsKey(COSName.COLORSPACE)) { options.setName(COSName.COLORSPACE, COSName.DEVICEGRAY.getName()); } result.write(decompressed); } /** * {@inheritDoc} */ public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { log.warn("CCITTFaxDecode.encode is not implemented yet, skipping this stream."); } private void invertBitmap(byte[] bufferData) { for (int i = 0, c = bufferData.length; i < c; i++) { bufferData[i] = (byte) (~bufferData[i] & 0xFF); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/Filter.java0000644000000000000000000000427712645757432024400 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.pdfbox.cos.COSDictionary; /** * This is the interface that will be used to apply filters to a byte stream. * * @author Ben Litchfield * @version $Revision: 1.7 $ */ public interface Filter { /** * This will decode some compressed data. * * @param compressedData The compressed byte stream. * @param result The place to write the uncompressed byte stream. * @param options The options to use to encode the data. * @param filterIndex The index to the filter being decoded. * * @throws IOException If there is an error decompressing the stream. */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException; /** * This will encode some data. * * @param rawData The raw data to encode. * @param result The place to write to encoded results to. * @param options The options to use to encode the data. * @param filterIndex The index to the filter being encoded. * * @throws IOException If there is an error compressing the stream. */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/JBIG2Filter.java0000644000000000000000000001225612645757432025112 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.SequenceInputStream; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; /** * Modeled on the JBIG2Decode filter. * * thanks to Timo Boehme */ public class JBIG2Filter implements Filter { /** Log instance. */ private static final Log LOG = LogFactory.getLog(JBIG2Filter.class); /** * Decode JBIG2 data using Java ImageIO library. * * {@inheritDoc} * */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { /** * A working JBIG2 ImageIO plugin is needed to decode JBIG2 encoded streams. * The following is known to be working. It can't be bundled with PDFBox because of an incompatible license. * http://code.google.com/p/jbig2-imageio/ */ Iterator readers = ImageIO.getImageReadersByFormatName("JBIG2"); if (!readers.hasNext()) { LOG.error( "Can't find an ImageIO plugin to decode the JBIG2 encoded datastream."); return; } ImageReader reader = readers.next(); COSBase decodeP = options.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP); COSDictionary decodeParms = null; if (decodeP instanceof COSDictionary) { decodeParms = (COSDictionary) decodeP; } else if (decodeP instanceof COSArray) { decodeParms = (COSDictionary) ((COSArray) decodeP).getObject(filterIndex); } COSInteger bits = (COSInteger) options.getDictionaryObject(COSName.BITS_PER_COMPONENT); COSStream st = null; if (decodeParms != null) { st = (COSStream) decodeParms.getDictionaryObject(COSName.JBIG2_GLOBALS); } if (st != null) { compressedData = new SequenceInputStream(st.getUnfilteredStream(), compressedData); } ImageInputStream iis = ImageIO.createImageInputStream(compressedData); reader.setInput(iis); BufferedImage bi = reader.read(0, reader.getDefaultReadParam()); iis.close(); reader.dispose(); if ( bi != null ) { // I am assuming since JBIG2 is always black and white // depending on your renderer this might or might be needed if(bi.getColorModel().getPixelSize() != bits.intValue()) { if(bits.intValue() != 1) { LOG.error("Do not know how to deal with JBIG2 with more than 1 bit"); return; } BufferedImage packedImage = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_BYTE_BINARY); Graphics graphics = packedImage.getGraphics(); graphics.drawImage(bi, 0, 0, null); graphics.dispose(); bi = packedImage; } DataBuffer dBuf = bi.getData().getDataBuffer(); if ( dBuf.getDataType() == DataBuffer.TYPE_BYTE ) { result.write( ( ( DataBufferByte ) dBuf ).getData() ); } else { LOG.error( "Image data buffer not of type byte but type " + dBuf.getDataType() ); } } else { LOG.error( "Something went wrong when decoding the JBIG2 encoded datastream."); } } /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { System.err.println( "Warning: JBIG2.encode is not implemented yet, skipping this stream." ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/DCTFilter.java0000644000000000000000000000357212645757432024730 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSDictionary; /** * This is the used for the DCTDecode filter. * * @author Ben Litchfield * @version $Revision: 1.10 $ */ public class DCTFilter implements Filter { /** * Log instance. */ private static final Log log = LogFactory.getLog(DCTFilter.class); /** * {@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { log.warn( "DCTFilter.decode is not implemented yet, skipping this stream." ); } /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { log.warn( "DCTFilter.encode is not implemented yet, skipping this stream." ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/FilterManager.java0000644000000000000000000001037212645757432025664 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.pdfbox.cos.COSName; /** * This will contain manage all the different types of filters that are available. * * @author Ben Litchfield * @version $Revision: 1.13 $ */ public class FilterManager { private final Map filters = new HashMap(); /** * Constructor. */ public FilterManager() { Filter flateFilter = new FlateFilter(); Filter ccittFaxFilter = new CCITTFaxDecodeFilter(); Filter lzwFilter = new LZWFilter(); Filter asciiHexFilter = new ASCIIHexFilter(); Filter ascii85Filter = new ASCII85Filter(); Filter runLengthFilter = new RunLengthDecodeFilter(); Filter cryptFilter = new CryptFilter(); Filter jpxFilter = new JPXFilter(); Filter jbig2Filter = new JBIG2Filter(); addFilter( COSName.FLATE_DECODE, flateFilter ); addFilter( COSName.FLATE_DECODE_ABBREVIATION, flateFilter ); addFilter( COSName.DCT_DECODE, jpxFilter); addFilter( COSName.DCT_DECODE_ABBREVIATION, jpxFilter); addFilter( COSName.CCITTFAX_DECODE, ccittFaxFilter ); addFilter( COSName.CCITTFAX_DECODE_ABBREVIATION, ccittFaxFilter ); addFilter( COSName.LZW_DECODE, lzwFilter ); addFilter( COSName.LZW_DECODE_ABBREVIATION, lzwFilter ); addFilter( COSName.ASCII_HEX_DECODE, asciiHexFilter ); addFilter( COSName.ASCII_HEX_DECODE_ABBREVIATION, asciiHexFilter ); addFilter( COSName.ASCII85_DECODE, ascii85Filter ); addFilter( COSName.ASCII85_DECODE_ABBREVIATION, ascii85Filter ); addFilter( COSName.RUN_LENGTH_DECODE, runLengthFilter ); addFilter( COSName.RUN_LENGTH_DECODE_ABBREVIATION, runLengthFilter ); addFilter( COSName.CRYPT, cryptFilter ); addFilter( COSName.JPX_DECODE, jpxFilter ); addFilter( COSName.JBIG2_DECODE, jbig2Filter ); } /** * This will get all of the filters that are available in the system. * * @return All available filters in the system. */ public Collection getFilters() { return filters.values(); } /** * This will add an available filter. * * @param filterName The name of the filter. * @param filter The filter to use. */ public void addFilter( COSName filterName, Filter filter ) { filters.put( filterName, filter ); } /** * This will get a filter by name. * * @param filterName The name of the filter to retrieve. * * @return The filter that matches the name. * * @throws IOException If the filter could not be found. */ public Filter getFilter( COSName filterName ) throws IOException { Filter filter = (Filter)filters.get( filterName ); if( filter == null ) { throw new IOException( "Unknown stream filter:" + filterName ); } return filter; } /** * This will get a filter by name. * * @param filterName The name of the filter to retrieve. * * @return The filter that matches the name. * * @throws IOException If the filter could not be found. */ public Filter getFilter( String filterName ) throws IOException { return getFilter( COSName.getPDFName( filterName ) ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/JPXFilter.java0000644000000000000000000001032512645757432024751 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import javax.imageio.ImageIO; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; /** * This is used for the JPXDecode filter. * * @author Timo Boehme * */ public class JPXFilter implements Filter { /** Log instance. */ private static final Log LOG = LogFactory.getLog(JPXFilter.class); /** * Decode JPEG and JPEG2000 data using Java ImageIO library. * * {@inheritDoc} * */ public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex) throws IOException { // skip one LF if there PushbackInputStream pbis = new PushbackInputStream(compressedData, 1); int by = pbis.read(); if (by != 0x0A) { pbis.unread(by); } BufferedImage bi = ImageIO.read(pbis); if (bi != null) { DataBuffer dBuf = bi.getData().getDataBuffer(); if (dBuf.getDataType() == DataBuffer.TYPE_BYTE) { // maybe some wrong/missing values have to be revised/added ColorModel colorModel = bi.getColorModel(); if (options.getItem(COSName.COLORSPACE) == null) { options.setItem(COSName.COLORSPACE, PDColorSpaceFactory.createColorSpace(null, colorModel.getColorSpace())); } options.setInt(COSName.BITS_PER_COMPONENT, colorModel.getPixelSize() / colorModel.getNumComponents()); options.setInt(COSName.HEIGHT, bi.getHeight()); options.setInt(COSName.WIDTH, bi.getWidth()); if (bi.getType() == BufferedImage.TYPE_3BYTE_BGR) { // PDFBOX-52 byte[] byteBuffer = ((DataBufferByte) dBuf).getData(); for (int i = 0; i < byteBuffer.length; i += 3) { //BGR //to //RGB byte tmp0 = byteBuffer[i]; byteBuffer[i] = byteBuffer[i + 2]; byteBuffer[i + 2] = tmp0; } result.write(byteBuffer); } else { result.write(((DataBufferByte) dBuf).getData()); } } else { LOG.error("Image data buffer not of type byte but type " + dBuf.getDataType()); } } else { LOG.error("ImageIO.read() did not return any data - is JAI installed?"); } } /** * {@inheritDoc} */ public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex) throws IOException { LOG.error("Warning: JPXFilter.encode is not implemented yet, skipping this stream."); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/IdentityFilter.java0000644000000000000000000000416212645757432026103 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.pdfbox.cos.COSDictionary; /** * The IdentityFilter filter just passes the data through without any modifications. * This is defined in section 7.6.5 of the PDF 1.7 spec and also stated in table * 26. * * @author adam.nichols */ public class IdentityFilter implements Filter { private static final int BUFFER_SIZE = 1024; /** * {@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { byte[] buffer = new byte[BUFFER_SIZE]; int amountRead = 0; while( (amountRead = compressedData.read( buffer, 0, BUFFER_SIZE )) != -1 ) { result.write( buffer, 0, amountRead ); } result.flush(); } /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { byte[] buffer = new byte[BUFFER_SIZE]; int amountRead = 0; while( (amountRead = rawData.read( buffer, 0, BUFFER_SIZE )) != -1 ) { result.write( buffer, 0, amountRead ); } result.flush(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java0000644000000000000000000001267012645757432025612 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.persistence.util.COSHEXTable; /** * This is the used for the ASCIIHexDecode filter. * * @author Ben Litchfield * @version $Revision: 1.9 $ */ public class ASCIIHexFilter implements Filter { /** * Log instance. */ private static final Log log = LogFactory.getLog(ASCIIHexFilter.class); /** * Whitespace. * 0 0x00 Null (NUL) * 9 0x09 Tab (HT) * 10 0x0A Line feed (LF) * 12 0x0C Form feed (FF) * 13 0x0D Carriage return (CR) * 32 0x20 Space (SP) */ private boolean isWhitespace(int c) { return c == 0 || c == 9 || c == 10 || c == 12 || c == 13 || c == 32; } private boolean isEOD(int c) { return (c == 62); // '>' - EOD } /** * {@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { int value = 0; int firstByte = 0; int secondByte = 0; while ((firstByte = compressedData.read()) != -1) { // always after first char while(isWhitespace(firstByte)) { firstByte = compressedData.read(); } if (firstByte == -1 || isEOD(firstByte)) { break; } if(REVERSE_HEX[firstByte] == -1) { log.error("Invalid Hex Code; int: " + firstByte + " char: " + (char) firstByte); } value = REVERSE_HEX[firstByte] * 16; secondByte = compressedData.read(); if (secondByte == -1 || isEOD(secondByte)) { // second value behaves like 0 in case of EOD result.write( value ); break; } if(secondByte >= 0) { if(REVERSE_HEX[secondByte] == -1) { log.error("Invalid Hex Code; int: " + secondByte + " char: " + (char) secondByte); } value += REVERSE_HEX[secondByte]; } result.write( value ); } result.flush(); } private static final int[] REVERSE_HEX = { -1, //0 -1, //1 -1, //2 -1, //3 -1, //4 -1, //5 -1, //6 -1, //7 -1, //8 -1, //9 -1, //10 -1, //11 -1, //12 -1, //13 -1, //14 -1, //15 -1, //16 -1, //17 -1, //18 -1, //19 -1, //20 -1, //21 -1, //22 -1, //23 -1, //24 -1, //25 -1, //26 -1, //27 -1, //28 -1, //29 -1, //30 -1, //31 -1, //32 -1, //33 -1, //34 -1, //35 -1, //36 -1, //37 -1, //38 -1, //39 -1, //40 -1, //41 -1, //42 -1, //43 -1, //44 -1, //45 -1, //46 -1, //47 0, //48 1, //49 2, //50 3, //51 4, //52 5, //53 6, //54 7, //55 8, //56 9, //57 -1, //58 -1, //59 -1, //60 -1, //61 -1, //62 -1, //63 -1, //64 10, //65 11, //66 12, //67 13, //68 14, //69 15, //70 -1, //71 -1, //72 -1, //73 -1, //74 -1, //75 -1, //76 -1, //77 -1, //78 -1, //79 -1, //80 -1, //81 -1, //82 -1, //83 -1, //84 -1, //85 -1, //86 -1, //87 -1, //88 -1, //89 -1, //90 -1, //91 -1, //92 -1, //93 -1, //94 -1, //95 -1, //96 10, //97 11, //98 12, //99 13, //100 14, //101 15, //102 }; /** * {@inheritDoc} */ public void encode( InputStream rawData, OutputStream result, COSDictionary options, int filterIndex ) throws IOException { int byteRead = 0; while( (byteRead = rawData.read()) != -1 ) { int value = (byteRead+256)%256; result.write( COSHEXTable.TABLE[value] ); } result.flush(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/filter/LZWFilter.java0000644000000000000000000002756012645757432024775 0ustar rootroot/* * Copyright 2014 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.filter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.imageio.stream.MemoryCacheImageInputStream; import javax.imageio.stream.MemoryCacheImageOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * * This is the filter used for the LZWDecode filter. * * @author Ben Litchfield * @author Tilman Hausherr */ public class LZWFilter implements Filter { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(LZWFilter.class); /** * The LZW clear table code. */ public static final long CLEAR_TABLE = 256; /** * The LZW end of data code. */ public static final long EOD = 257; //BEWARE: codeTable must be local to each method, because there is only // one instance of each filter /** * {@inheritDoc} */ public void decode(InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex) throws IOException { COSBase baseObj = options.getDictionaryObject(COSName.DECODE_PARMS, COSName.DP); COSDictionary decodeParams = null; if (baseObj instanceof COSDictionary) { decodeParams = (COSDictionary) baseObj; } else if (baseObj instanceof COSArray) { COSArray paramArray = (COSArray) baseObj; if (filterIndex < paramArray.size()) { decodeParams = (COSDictionary) paramArray.getObject(filterIndex); } } else if (baseObj != null) { throw new IOException("Error: Expected COSArray or COSDictionary and not " + baseObj.getClass().getName()); } int predictor = -1; int earlyChange = 1; if (decodeParams != null) { predictor = decodeParams.getInt(COSName.PREDICTOR); earlyChange = decodeParams.getInt(COSName.EARLY_CHANGE, 1); if (earlyChange != 0 && earlyChange != 1) { earlyChange = 1; } } if (predictor > 1) { int colors = Math.min(decodeParams.getInt(COSName.COLORS, 1), 32); int bitsPerPixel = decodeParams.getInt(COSName.BITS_PER_COMPONENT, 8); int columns = decodeParams.getInt(COSName.COLUMNS, 1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); doLZWDecode(compressedData, baos, earlyChange); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); Predictor.decodePredictor(predictor, colors, bitsPerPixel, columns, bais, result); result.flush(); baos.reset(); bais.reset(); } else { doLZWDecode(compressedData, result, earlyChange); } } private void doLZWDecode(InputStream compressedData, OutputStream result, int earlyChange) throws IOException { ArrayList codeTable = null; int chunk = 9; MemoryCacheImageInputStream in = new MemoryCacheImageInputStream(compressedData); long nextCommand = 0; long prevCommand = -1; try { while ((nextCommand = in.readBits(chunk)) != EOD) { if (nextCommand == CLEAR_TABLE) { chunk = 9; codeTable = createCodeTable(); prevCommand = -1; } else { if (nextCommand < codeTable.size()) { byte[] data = codeTable.get((int) nextCommand); byte firstByte = data[0]; result.write(data); if (prevCommand != -1) { checkIndexBounds(codeTable, prevCommand, in); data = codeTable.get((int) prevCommand); byte[] newData = new byte[data.length + 1]; for (int i = 0; i < data.length; ++i) { newData[i] = data[i]; } newData[data.length] = firstByte; codeTable.add(newData); } } else { checkIndexBounds(codeTable, prevCommand, in); byte[] data = codeTable.get((int) prevCommand); byte[] newData = new byte[data.length + 1]; for (int i = 0; i < data.length; ++i) { newData[i] = data[i]; } newData[data.length] = data[0]; result.write(newData); codeTable.add(newData); } chunk = calculateChunk(codeTable.size(), earlyChange); prevCommand = nextCommand; } } } catch (EOFException ex) { LOG.warn("Premature EOF in LZW stream, EOD code missing"); } result.flush(); } private void checkIndexBounds(List codeTable, long index, MemoryCacheImageInputStream in) throws IOException { if (index < 0) { throw new IOException("negative array index: " + index + " near offset " + in.getStreamPosition()); } if (index >= codeTable.size()) { throw new IOException("array index overflow: " + index + " >= " + codeTable.size() + " near offset " + in.getStreamPosition()); } } /** * {@inheritDoc} */ public void encode(InputStream rawData, OutputStream result, COSDictionary options, int filterIndex) throws IOException { ArrayList codeTable = createCodeTable(); int chunk = 9; byte[] inputPattern = null; MemoryCacheImageOutputStream out = new MemoryCacheImageOutputStream(result); out.writeBits(CLEAR_TABLE, chunk); int foundCode = -1; int r; while ((r = rawData.read()) != -1) { byte by = (byte) r; if (inputPattern == null) { inputPattern = new byte[] { by }; foundCode = by & 0xff; } else { byte[] inputPatternCopy = new byte[inputPattern.length + 1]; for (int i = 0; i < inputPattern.length; ++i) { inputPatternCopy[i] = inputPattern[i]; } inputPattern = inputPatternCopy; inputPattern[inputPattern.length - 1] = by; int newFoundCode = findPatternCode(codeTable, inputPattern); if (newFoundCode == -1) { // use previous chunk = calculateChunk(codeTable.size() - 1, 1); out.writeBits(foundCode, chunk); // create new table entry codeTable.add(inputPattern); if (codeTable.size() == 4096) { // code table is full out.writeBits(CLEAR_TABLE, chunk); chunk = 9; codeTable = createCodeTable(); } inputPattern = new byte[] { by }; foundCode = by & 0xff; } else { foundCode = newFoundCode; } } } if (foundCode != -1) { chunk = calculateChunk(codeTable.size() - 1, 1); out.writeBits(foundCode, chunk); } // PPDFBOX-1977: the decoder wouldn't know that the encoder would output // an EOD as code, so he would have increased his own code table and // possibly adjusted the chunk. Therefore, the encoder must behave as // if the code table had just grown and thus it must be checked it is // needed to adjust the chunk, based on an increased table size parameter chunk = calculateChunk(codeTable.size(), 1); out.writeBits(EOD, chunk); out.writeBits(0, 7); // pad with 0 out.flush(); // must do or file will be empty :-( } /** * Find the longest matching pattern in the code table. * * @param codeTable The LZW code table. * @param pattern The pattern to be searched for. * @return The index of the longest matching pattern or -1 if nothing is * found. */ private int findPatternCode(ArrayList codeTable, byte[] pattern) { int foundCode = -1; int foundLen = 0; for (int i = codeTable.size() - 1; i >= 0; --i) { if (i <= EOD) { // we're in the single byte area if (foundCode != -1) { return foundCode; // we already found pattern with size > 1 } else if (pattern.length > 1) { return -1; // we won't find anything here anyway } } byte[] tryPattern = codeTable.get(i); if (foundCode != -1 || tryPattern.length > foundLen) { if (Arrays.equals(tryPattern, pattern)) { foundCode = i; foundLen = tryPattern.length; } } } return foundCode; } /** * Init the code table with 1 byte entries and the EOD and CLEAR_TABLE * markers. */ private ArrayList createCodeTable() { ArrayList codeTable = new ArrayList(4096); for (int i = 0; i < 256; ++i) { codeTable.add(new byte[] { (byte) (i & 0xFF) }); } codeTable.add(null); // 256 EOD codeTable.add(null); // 257 CLEAR_TABLE return codeTable; } /** * Calculate the appropriate chunk size * * @param tabSize the size of the code table * @param earlyChange 0 or 1 for early chunk increase * * @return a value between 9 and 12 */ private int calculateChunk(int tabSize, int earlyChange) { if (tabSize >= 2048 - earlyChange) { return 12; } if (tabSize >= 1024 - earlyChange) { return 11; } if (tabSize >= 512 - earlyChange) { return 10; } return 9; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/PDFMerger.java0000644000000000000000000000570012645757432023431 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import org.apache.pdfbox.util.PDFMergerUtility; /** * This is the main program that will take a list of pdf documents and merge them, * saving the result in a new document. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDFMerger { private PDFMerger() { } /** * Infamous main method. * * @param args Command line arguments, should be at least 3. * * @throws Exception If there is an error parsing the document. */ public static void main( String[] args ) throws Exception { PDFMerger merge = new PDFMerger(); merge.merge( args ); } private void merge( String[] args ) throws Exception { String destinationFileName = ""; String sourceFileName; boolean nonSeq = false; int firstFileArgPos = 0; if (args.length > 0 && args[0].equals("-nonSeq")) { nonSeq = true; firstFileArgPos = 1; } if ( args.length - firstFileArgPos < 3 ) { usage(); } PDFMergerUtility merger = new PDFMergerUtility(); for( int i=firstFileArgPos; i \n" + " -nonSeq use the non-sequential parser\n" + " 2 or more source PDF documents to merge\n" + " The PDF document to save the merged documents to\n" ); System.exit( 1 ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/ImportFDF.java0000644000000000000000000001030012645757432023440 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import java.io.IOException; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.fdf.FDFDocument; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; /** * This example will take a PDF document and fill the fields with data from the * FDF fields. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class ImportFDF { /** * Creates a new instance of ImportFDF. */ public ImportFDF() { } /** * This will takes the values from the fdf document and import them into the * PDF document. * * @param pdfDocument The document to put the fdf data into. * @param fdfDocument The FDF document to get the data from. * * @throws IOException If there is an error setting the data in the field. */ public void importFDF( PDDocument pdfDocument, FDFDocument fdfDocument ) throws IOException { PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog(); PDAcroForm acroForm = docCatalog.getAcroForm(); if (acroForm == null) { return; } acroForm.setCacheFields(true); acroForm.importFDF( fdfDocument ); //TODO this can be removed when we create appearance streams ((COSDictionary) acroForm.getCOSObject()).setBoolean(COSName.getPDFName("NeedAppearances"), true); } /** * This will import an fdf document and write out another pdf. *
* see usage() for commandline * * @param args command line arguments * * @throws Exception If there is an error importing the FDF document. */ public static void main(String[] args) throws Exception { ImportFDF importer = new ImportFDF(); importer.importFDF( args ); } private void importFDF( String[] args ) throws Exception { PDDocument pdf = null; FDFDocument fdf = null; try { if( args.length != 3 ) { usage(); } else { ImportFDF importer = new ImportFDF(); pdf = PDDocument.load( args[0] ); fdf = FDFDocument.load( args[1] ); importer.importFDF( pdf, fdf ); pdf.save( args[2] ); } } finally { close( fdf ); close( pdf ); } } /** * This will print out a message telling how to use this example. */ private static void usage() { System.err.println( "usage: org.apache.pdfbox.ImportFDF " ); } /** * Close the document. * * @param doc The doc to close. * * @throws IOException If there is an error closing the document. */ public void close( FDFDocument doc ) throws IOException { if( doc != null ) { doc.close(); } } /** * Close the document. * * @param doc The doc to close. * * @throws IOException If there is an error closing the document. */ public void close( PDDocument doc ) throws IOException { if( doc != null ) { doc.close(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/PDFReader.java0000644000000000000000000003145712645757432023422 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import org.apache.pdfbox.pdfviewer.PageWrapper; import org.apache.pdfbox.pdfviewer.ReaderBottomPanel; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageable; import org.apache.pdfbox.util.ExtensionFileFilter; import org.apache.pdfbox.util.ImageIOUtil; import javax.swing.JFileChooser; import javax.swing.JScrollPane; import javax.swing.JPanel; import javax.swing.KeyStroke; import java.awt.image.BufferedImage; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; import java.io.IOException; import java.util.List; /** * An application to read PDF documents. This will provide Acrobat Reader like * funtionality. * * @author Ben Litchfield * */ public class PDFReader extends javax.swing.JFrame { private File currentDir=new File("."); private javax.swing.JMenuItem saveAsImageMenuItem; private javax.swing.JMenuItem exitMenuItem; private javax.swing.JMenu fileMenu; private javax.swing.JMenuBar menuBar; private javax.swing.JMenuItem openMenuItem; private javax.swing.JMenuItem printMenuItem; private javax.swing.JMenu viewMenu; private javax.swing.JMenuItem nextPageItem; private javax.swing.JMenuItem previousPageItem; private JPanel documentPanel = new JPanel(); private ReaderBottomPanel bottomStatusPanel = new ReaderBottomPanel(); private PDDocument document = null; private List pages= null; private int currentPage = 0; private int numberOfPages = 0; private String currentFilename = null; private static final String PASSWORD = "-password"; private static final String NONSEQ = "-nonSeq"; private static boolean useNonSeqParser = false; private static final String VERSION = Version.getVersion(); private static final String BASETITLE = "PDFBox " + VERSION; /** * Constructor. */ public PDFReader() { initComponents(); } /** * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() { menuBar = new javax.swing.JMenuBar(); fileMenu = new javax.swing.JMenu(); openMenuItem = new javax.swing.JMenuItem(); saveAsImageMenuItem = new javax.swing.JMenuItem(); exitMenuItem = new javax.swing.JMenuItem(); printMenuItem = new javax.swing.JMenuItem(); viewMenu = new javax.swing.JMenu(); nextPageItem = new javax.swing.JMenuItem(); previousPageItem = new javax.swing.JMenuItem(); setTitle(BASETITLE); addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent evt) { exitApplication(); } }); JScrollPane documentScroller = new JScrollPane(); documentScroller.setViewportView( documentPanel ); getContentPane().add( documentScroller, java.awt.BorderLayout.CENTER ); getContentPane().add( bottomStatusPanel, java.awt.BorderLayout.SOUTH ); fileMenu.setText("File"); openMenuItem.setText("Open"); openMenuItem.setToolTipText("Open PDF file"); openMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openMenuItemActionPerformed(evt); } }); fileMenu.add(openMenuItem); printMenuItem.setText( "Print" ); printMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { try { if (document != null) { PDPageable pageable = new PDPageable(document); PrinterJob job = pageable.getPrinterJob(); job.setPageable(pageable); if (job.printDialog()) { job.print(); } } } catch( PrinterException e ) { e.printStackTrace(); } } }); fileMenu.add( printMenuItem ); saveAsImageMenuItem.setText( "Save as image" ); saveAsImageMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { if (document != null) { saveImage(); } } }); fileMenu.add( saveAsImageMenuItem ); exitMenuItem.setText("Exit"); exitMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { exitApplication(); } }); fileMenu.add(exitMenuItem); menuBar.add(fileMenu); viewMenu.setText("View"); nextPageItem.setText("Next page"); nextPageItem.setAccelerator(KeyStroke.getKeyStroke('+')); nextPageItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { nextPage(); } }); viewMenu.add(nextPageItem); previousPageItem.setText("Previous page"); previousPageItem.setAccelerator(KeyStroke.getKeyStroke('-')); previousPageItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { previousPage(); } }); viewMenu.add(previousPageItem); menuBar.add(viewMenu); setJMenuBar(menuBar); java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); setBounds((screenSize.width-700)/2, (screenSize.height-600)/2, 700, 600); } private void updateTitle() { setTitle(BASETITLE + ": " + currentFilename + " (" + (currentPage + 1) + "/" + numberOfPages + ")"); } private void nextPage() { if (currentPage < numberOfPages-1) { currentPage++; updateTitle(); showPage(currentPage); } } private void previousPage() { if (currentPage > 0 ) { currentPage--; updateTitle(); showPage(currentPage); } } private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) { JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(currentDir); ExtensionFileFilter pdfFilter = new ExtensionFileFilter(new String[] {"PDF"}, "PDF Files"); chooser.setFileFilter(pdfFilter); int result = chooser.showOpenDialog(PDFReader.this); if (result == JFileChooser.APPROVE_OPTION) { String name = chooser.getSelectedFile().getPath(); currentDir = new File(name).getParentFile(); try { openPDFFile(name, ""); } catch (Exception e) { e.printStackTrace(); } } } private void exitApplication() { try { if( document != null ) { document.close(); } } catch( IOException io ) { //do nothing because we are closing the application } this.setVisible( false ); this.dispose(); } /** * @param args the command line arguments * * @throws Exception If anything goes wrong. */ public static void main(String[] args) throws Exception { PDFReader viewer = new PDFReader(); String password = ""; String filename = null; for( int i = 0; i < args.length; i++ ) { if( args[i].equals( PASSWORD ) ) { i++; if( i >= args.length ) { usage(); } password = args[i]; } if( args[i].equals( NONSEQ ) ) { useNonSeqParser = true; } else { filename = args[i]; } } // open the pdf if present if (filename != null) { viewer.openPDFFile( filename, password ); } viewer.setVisible(true); } private void openPDFFile(String filename, String password) throws Exception { if( document != null ) { document.close(); documentPanel.removeAll(); } File file = new File( filename ); parseDocument( file, password ); pages = document.getDocumentCatalog().getAllPages(); numberOfPages = pages.size(); currentFilename = file.getAbsolutePath(); currentPage = 0; updateTitle(); showPage(0); } private void showPage(int pageNumber) { try { PageWrapper wrapper = new PageWrapper( this ); wrapper.displayPage( (PDPage)pages.get(pageNumber) ); if (documentPanel.getComponentCount() > 0) { documentPanel.remove(0); } documentPanel.add( wrapper.getPanel() ); pack(); } catch (IOException exception) { exception.printStackTrace(); } } private void saveImage() { try { PDPage pageToSave = (PDPage)pages.get(currentPage); BufferedImage pageAsImage = pageToSave.convertToImage(); String imageFilename = currentFilename; if (imageFilename.toLowerCase().endsWith(".pdf")) { imageFilename = imageFilename.substring(0, imageFilename.length()-4); } imageFilename += "_" + (currentPage + 1 + ".png"); ImageIOUtil.writeImage(pageAsImage, imageFilename, 300); } catch (IOException exception) { exception.printStackTrace(); } } /** * This will parse a document. * * @param input The input stream for the document. * * @throws IOException If there is an error parsing the document. */ private void parseDocument( File file, String password )throws IOException { document = null; if (useNonSeqParser) { document = PDDocument.loadNonSeq(file, null, password); } else { document = PDDocument.load(file); if( document.isEncrypted() ) { try { document.decrypt( password ); } catch( org.apache.pdfbox.exceptions.CryptographyException e ) { e.printStackTrace(); } } } } /** * Get the bottom status panel. * * @return The bottom status panel. */ public ReaderBottomPanel getBottomStatusPanel() { return bottomStatusPanel; } /** * This will print out a message telling how to use this utility. */ private static void usage() { System.err.println("usage: java -jar pdfbox-app-" + VERSION + ".jar PDFReader [OPTIONS] \n"+ " -password Password to decrypt the document\n" + " -nonSeq Enables the new non-sequential parser\n" + " The PDF document to be loaded\n" ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encryption/0000755000000000000000000000000012645757432023203 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encryption/package.html0000644000000000000000000000173612645757432025473 0ustar rootroot These classes deal with encryption algorithms that are used in the PDF Document. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encryption/PDFEncryption.java0000644000000000000000000004626612645757432026550 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encryption; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.apache.pdfbox.exceptions.CryptographyException; /** * This class will deal with PDF encryption algorithms. * * @author Ben Litchfield * @version $Revision: 1.15 $ * * @deprecated use the new security layer instead * * @see org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler */ public final class PDFEncryption { private ARCFour rc4 = new ARCFour(); /** * The encryption padding defined in the PDF 1.4 Spec algorithm 3.2. */ public static final byte[] ENCRYPT_PADDING = { (byte)0x28, (byte)0xBF, (byte)0x4E, (byte)0x5E, (byte)0x4E, (byte)0x75, (byte)0x8A, (byte)0x41, (byte)0x64, (byte)0x00, (byte)0x4E, (byte)0x56, (byte)0xFF, (byte)0xFA, (byte)0x01, (byte)0x08, (byte)0x2E, (byte)0x2E, (byte)0x00, (byte)0xB6, (byte)0xD0, (byte)0x68, (byte)0x3E, (byte)0x80, (byte)0x2F, (byte)0x0C, (byte)0xA9, (byte)0xFE, (byte)0x64, (byte)0x53, (byte)0x69, (byte)0x7A }; /** * This will encrypt a piece of data. * * @param objectNumber The id for the object. * @param genNumber The generation id for the object. * @param key The key used to encrypt the data. * @param data The data to encrypt/decrypt. * @param output The stream to write to. * * @throws CryptographyException If there is an error encrypting the data. * @throws IOException If there is an io error. */ public final void encryptData( long objectNumber, long genNumber, byte[] key, InputStream data, OutputStream output ) throws CryptographyException, IOException { byte[] newKey = new byte[ key.length + 5 ]; System.arraycopy( key, 0, newKey, 0, key.length ); //PDF 1.4 reference pg 73 //step 1 //we have the reference //step 2 newKey[newKey.length -5] = (byte)(objectNumber & 0xff); newKey[newKey.length -4] = (byte)((objectNumber >> 8) & 0xff); newKey[newKey.length -3] = (byte)((objectNumber >> 16) & 0xff); newKey[newKey.length -2] = (byte)(genNumber & 0xff); newKey[newKey.length -1] = (byte)((genNumber >> 8) & 0xff); //step 3 byte[] digestedKey = null; try { MessageDigest md = MessageDigest.getInstance( "MD5" ); digestedKey = md.digest( newKey ); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } //step 4 int length = Math.min( newKey.length, 16 ); byte[] finalKey = new byte[ length ]; System.arraycopy( digestedKey, 0, finalKey, 0, length ); rc4.setKey( finalKey ); rc4.write( data, output ); output.flush(); } /** * This will get the user password from the owner password and the documents o value. * * @param ownerPassword The plaintext owner password. * @param o The document's o entry. * @param revision The document revision number. * @param length The length of the encryption. * * @return The plaintext padded user password. * * @throws CryptographyException If there is an error getting the user password. * @throws IOException If there is an error reading data. */ public final byte[] getUserPassword( byte[] ownerPassword, byte[] o, int revision, long length ) throws CryptographyException, IOException { try { ByteArrayOutputStream result = new ByteArrayOutputStream(); //3.3 STEP 1 byte[] ownerPadded = truncateOrPad( ownerPassword ); //3.3 STEP 2 MessageDigest md = MessageDigest.getInstance( "MD5" ); md.update( ownerPadded ); byte[] digest = md.digest(); //3.3 STEP 3 if( revision == 3 || revision == 4 ) { for( int i=0; i<50; i++ ) { md.reset(); md.update( digest ); digest = md.digest(); } } if( revision == 2 && length != 5 ) { throw new CryptographyException( "Error: Expected length=5 actual=" + length ); } //3.3 STEP 4 byte[] rc4Key = new byte[ (int)length ]; System.arraycopy( digest, 0, rc4Key, 0, (int)length ); //3.7 step 2 if( revision == 2 ) { rc4.setKey( rc4Key ); rc4.write( o, result ); } else if( revision == 3 || revision == 4) { /** byte[] iterationKey = new byte[ rc4Key.length ]; byte[] dataToEncrypt = o; for( int i=19; i>=0; i-- ) { System.arraycopy( rc4Key, 0, iterationKey, 0, rc4Key.length ); for( int j=0; j< iterationKey.length; j++ ) { iterationKey[j] = (byte)(iterationKey[j] ^ (byte)i); } rc4.setKey( iterationKey ); rc4.write( dataToEncrypt, result ); dataToEncrypt = result.toByteArray(); result.reset(); } result.write( dataToEncrypt, 0, dataToEncrypt.length ); */ byte[] iterationKey = new byte[ rc4Key.length ]; byte[] otemp = new byte[ o.length ]; //sm System.arraycopy( o, 0, otemp, 0, o.length ); //sm rc4.write( o, result);//sm for( int i=19; i>=0; i-- ) { System.arraycopy( rc4Key, 0, iterationKey, 0, rc4Key.length ); for( int j=0; j< iterationKey.length; j++ ) { iterationKey[j] = (byte)(iterationKey[j] ^ (byte)i); } rc4.setKey( iterationKey ); result.reset(); //sm rc4.write( otemp, result ); //sm otemp = result.toByteArray(); //sm } } return result.toByteArray(); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } } /** * This will tell if this is the owner password or not. * * @param ownerPassword The plaintext owner password. * @param u The U value from the PDF Document. * @param o The owner password hash. * @param permissions The document permissions. * @param id The document id. * @param revision The revision of the encryption. * @param length The length of the encryption key. * * @return true if the owner password matches the one from the document. * * @throws CryptographyException If there is an error while executing crypt functions. * @throws IOException If there is an error while checking owner password. */ public final boolean isOwnerPassword( byte[] ownerPassword, byte[] u, byte[] o, int permissions, byte[] id, int revision, int length) throws CryptographyException, IOException { byte[] userPassword = getUserPassword( ownerPassword, o, revision, length ); return isUserPassword( userPassword, u, o, permissions, id, revision, length ); } /** * This will tell if this is a valid user password. * * Algorithm 3.6 pg 80 * * @param password The password to test. * @param u The U value from the PDF Document. * @param o The owner password hash. * @param permissions The document permissions. * @param id The document id. * @param revision The revision of the encryption. * @param length The length of the encryption key. * * @return true If this is the correct user password. * * @throws CryptographyException If there is an error computing the value. * @throws IOException If there is an IO error while computing the owners password. */ public final boolean isUserPassword( byte[] password, byte[] u, byte[] o, int permissions, byte[] id, int revision, int length) throws CryptographyException, IOException { boolean matches = false; //STEP 1 byte[] computedValue = computeUserPassword( password, o, permissions, id, revision, length ); if( revision == 2 ) { //STEP 2 matches = arraysEqual( u, computedValue ); } else if( revision == 3 || revision == 4 ) { //STEP 2 matches = arraysEqual( u, computedValue, 16 ); } return matches; } /** * This will compare two byte[] for equality for count number of bytes. * * @param first The first byte array. * @param second The second byte array. * @param count The number of bytes to compare. * * @return true If the arrays contain the exact same data. */ private final boolean arraysEqual( byte[] first, byte[] second, int count ) { boolean equal = first.length >= count && second.length >= count; for( int i=0; i>> 0); byte one = (byte)(permissions >>> 8); byte two = (byte)(permissions >>> 16); byte three = (byte)(permissions >>> 24); md.update( zero ); md.update( one ); md.update( two ); md.update( three ); //step 5 md.update( id ); byte[] digest = md.digest(); //step 6 if( revision == 3 || revision == 4) { for( int i=0; i<50; i++ ) { md.reset(); md.update( digest, 0, length ); digest = md.digest(); } } //step 7 if( revision == 2 && length != 5 ) { throw new CryptographyException( "Error: length should be 5 when revision is two actual=" + length ); } System.arraycopy( digest, 0, result, 0, length ); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } return result; } /** * This algorithm is taked from PDF Reference 1.4 Algorithm 3.3 Page 79. * * @param ownerPassword The plain owner password. * @param userPassword The plain user password. * @param revision The version of the security. * @param length The length of the document. * * @return The computed owner password. * * @throws CryptographyException If there is an error computing O. * @throws IOException If there is an error computing O. */ public final byte[] computeOwnerPassword( byte[] ownerPassword, byte[] userPassword, int revision, int length ) throws CryptographyException, IOException { try { //STEP 1 byte[] ownerPadded = truncateOrPad( ownerPassword ); //STEP 2 MessageDigest md = MessageDigest.getInstance( "MD5" ); md.update( ownerPadded ); byte[] digest = md.digest(); //STEP 3 if( revision == 3 || revision == 4) { for( int i=0; i<50; i++ ) { md.reset(); md.update( digest, 0, length ); digest = md.digest(); } } if( revision == 2 && length != 5 ) { throw new CryptographyException( "Error: Expected length=5 actual=" + length ); } //STEP 4 byte[] rc4Key = new byte[ length ]; System.arraycopy( digest, 0, rc4Key, 0, length ); //STEP 5 byte[] paddedUser = truncateOrPad( userPassword ); //STEP 6 rc4.setKey( rc4Key ); ByteArrayOutputStream crypted = new ByteArrayOutputStream(); rc4.write( new ByteArrayInputStream( paddedUser ), crypted ); //STEP 7 if( revision == 3 || revision == 4 ) { byte[] iterationKey = new byte[ rc4Key.length ]; for( int i=1; i<20; i++ ) { System.arraycopy( rc4Key, 0, iterationKey, 0, rc4Key.length ); for( int j=0; j< iterationKey.length; j++ ) { iterationKey[j] = (byte)(iterationKey[j] ^ (byte)i); } rc4.setKey( iterationKey ); ByteArrayInputStream input = new ByteArrayInputStream( crypted.toByteArray() ); crypted.reset(); rc4.write( input, crypted ); } } //STEP 8 return crypted.toByteArray(); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e.getMessage() ); } } /** * This will take the password and truncate or pad it as necessary. * * @param password The password to pad or truncate. * * @return The padded or truncated password. */ private final byte[] truncateOrPad( byte[] password ) { byte[] padded = new byte[ ENCRYPT_PADDING.length ]; int bytesBeforePad = Math.min( password.length, padded.length ); System.arraycopy( password, 0, padded, 0, bytesBeforePad ); System.arraycopy( ENCRYPT_PADDING, 0, padded, bytesBeforePad, ENCRYPT_PADDING.length-bytesBeforePad ); return padded; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encryption/ARCFour.java0000644000000000000000000001140212645757432025305 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encryption; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * This class is an implementation of the alleged RC4 algorithm. * * @author Ben Litchfield * @version $Revision: 1.8 $ */ public class ARCFour { private int[] salt; private int b; private int c; /** * Constructor. * */ public ARCFour() { salt = new int[256]; } /** * This will reset the key to be used. * * @param key The RC4 key used during encryption. */ public void setKey( byte[] key ) { b = 0; c = 0; if(key.length < 1 || key.length > 32) { throw new IllegalArgumentException("number of bytes must be between 1 and 32"); } for(int i = 0; i < salt.length; i++) { salt[i] = i; } int keyIndex = 0; int saltIndex = 0; for( int i = 0; i < salt.length; i++) { saltIndex = (fixByte(key[keyIndex]) + salt[i] + saltIndex) % 256; swap( salt, i, saltIndex ); keyIndex = (keyIndex + 1) % key.length; } } /** * Thie will ensure that the value for a byte >=0. * * @param aByte The byte to test against. * * @return A value >=0 and < 256 */ private static final int fixByte( byte aByte ) { return aByte < 0 ? 256 + aByte : aByte; } /** * This will swap two values in an array. * * @param data The array to swap from. * @param firstIndex The index of the first element to swap. * @param secondIndex The index of the second element to swap. */ private static final void swap( int[] data, int firstIndex, int secondIndex ) { int tmp = data[ firstIndex ]; data[ firstIndex ] = data[ secondIndex ]; data[ secondIndex ] = tmp; } /** * This will encrypt and write the next byte. * * @param aByte The byte to encrypt. * @param output The stream to write to. * * @throws IOException If there is an error writing to the output stream. */ public void write( byte aByte, OutputStream output ) throws IOException { b = (b + 1) % 256; c = (salt[b] + c) % 256; swap( salt, b, c ); int saltIndex = (salt[b] + salt[c]) % 256; output.write(aByte ^ (byte)salt[saltIndex]); } /** * This will encrypt and write the data. * * @param data The data to encrypt. * @param output The stream to write to. * * @throws IOException If there is an error writing to the output stream. */ public void write( byte[] data, OutputStream output ) throws IOException { for( int i = 0; i < data.length; i++ ) { write( data[i], output ); } } /** * This will encrypt and write the data. * * @param data The data to encrypt. * @param output The stream to write to. * * @throws IOException If there is an error writing to the output stream. */ public void write( InputStream data, OutputStream output ) throws IOException { byte[] buffer = new byte[1024]; int amountRead = 0; while( (amountRead = data.read( buffer )) != -1 ) { write( buffer, 0, amountRead, output ); } } /** * This will encrypt and write the data. * * @param data The data to encrypt. * @param offset The offset into the array to start reading data from. * @param len The number of bytes to attempt to read. * @param output The stream to write to. * * @throws IOException If there is an error writing to the output stream. */ public void write( byte[] data, int offset, int len, OutputStream output) throws IOException { for( int i = offset; i < offset + len; i++ ) { write( data[i], output ); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/encryption/DocumentEncryption.java0000644000000000000000000003454412645757432027711 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.encryption; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.exceptions.InvalidPasswordException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.encryption.PDStandardEncryption; /** * This class will deal with encrypting/decrypting a document. * * @author Ben Litchfield * @version $Revision: 1.13 $ * * @deprecated use the new security API instead. * * @see org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler */ public class DocumentEncryption { private PDDocument pdDocument = null; private COSDocument document = null; private byte[] encryptionKey = null; private PDFEncryption encryption = new PDFEncryption(); private Set objects = new HashSet(); /** * A set that contains potential signature dictionaries. This is used * because the Contents entry of the signature is not encrypted. */ private Set potentialSignatures = new HashSet(); /** * Constructor. * * @param doc The document to decrypt. */ public DocumentEncryption( PDDocument doc ) { pdDocument = doc; document = doc.getDocument(); } /** * Constructor. * * @param doc The document to decrypt. */ public DocumentEncryption( COSDocument doc ) { pdDocument = new PDDocument( doc ); document = doc; } /** * This will encrypt the given document, given the owner password and user password. * The encryption method used is the standard filter. * * @throws CryptographyException If an error occurs during encryption. * @throws IOException If there is an error accessing the data. */ public void initForEncryption() throws CryptographyException, IOException { String ownerPassword = pdDocument.getOwnerPasswordForEncryption(); String userPassword = pdDocument.getUserPasswordForEncryption(); if( ownerPassword == null ) { ownerPassword = ""; } if( userPassword == null ) { userPassword = ""; } PDStandardEncryption encParameters = (PDStandardEncryption)pdDocument.getEncryptionDictionary(); int permissionInt = encParameters.getPermissions(); int revision = encParameters.getRevision(); int length = encParameters.getLength()/8; COSArray idArray = document.getDocumentID(); //check if the document has an id yet. If it does not then //generate one if( idArray == null || idArray.size() < 2 ) { idArray = new COSArray(); try { MessageDigest md = MessageDigest.getInstance( "MD5" ); BigInteger time = BigInteger.valueOf( System.currentTimeMillis() ); md.update( time.toByteArray() ); md.update( ownerPassword.getBytes("ISO-8859-1") ); md.update( userPassword.getBytes("ISO-8859-1") ); md.update( document.toString().getBytes() ); byte[] id = md.digest( this.toString().getBytes("ISO-8859-1") ); COSString idString = new COSString(); idString.append( id ); idArray.add( idString ); idArray.add( idString ); document.setDocumentID( idArray ); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } } COSString id = (COSString)idArray.getObject( 0 ); encryption = new PDFEncryption(); byte[] o = encryption.computeOwnerPassword( ownerPassword.getBytes("ISO-8859-1"), userPassword.getBytes("ISO-8859-1"), revision, length); byte[] u = encryption.computeUserPassword( userPassword.getBytes("ISO-8859-1"), o, permissionInt, id.getBytes(), revision, length); encryptionKey = encryption.computeEncryptedKey( userPassword.getBytes("ISO-8859-1"), o, permissionInt, id.getBytes(), revision, length); encParameters.setOwnerKey( o ); encParameters.setUserKey( u ); document.setEncryptionDictionary( encParameters.getCOSDictionary() ); } /** * This will decrypt the document. * * @param password The password for the document. * * @throws CryptographyException If there is an error decrypting the document. * @throws IOException If there is an error getting the stream data. * @throws InvalidPasswordException If the password is not a user or owner password. */ public void decryptDocument( String password ) throws CryptographyException, IOException, InvalidPasswordException { if( password == null ) { password = ""; } PDStandardEncryption encParameters = (PDStandardEncryption)pdDocument.getEncryptionDictionary(); int permissions = encParameters.getPermissions(); int revision = encParameters.getRevision(); int length = encParameters.getLength()/8; COSString id = (COSString)document.getDocumentID().getObject( 0 ); byte[] u = encParameters.getUserKey(); byte[] o = encParameters.getOwnerKey(); boolean isUserPassword = encryption.isUserPassword( password.getBytes("ISO-8859-1"), u, o, permissions, id.getBytes(), revision, length ); boolean isOwnerPassword = encryption.isOwnerPassword( password.getBytes("ISO-8859-1"), u, o, permissions, id.getBytes(), revision, length ); if( isUserPassword ) { encryptionKey = encryption.computeEncryptedKey( password.getBytes("ISO-8859-1"), o, permissions, id.getBytes(), revision, length ); } else if( isOwnerPassword ) { byte[] computedUserPassword = encryption.getUserPassword( password.getBytes("ISO-8859-1"), o, revision, length ); encryptionKey = encryption.computeEncryptedKey( computedUserPassword, o, permissions, id.getBytes(), revision, length ); } else { throw new InvalidPasswordException( "Error: The supplied password does not match " + "either the owner or user password in the document." ); } COSDictionary trailer = document.getTrailer(); COSArray fields = (COSArray)trailer.getObjectFromPath( "Root/AcroForm/Fields" ); //We need to collect all the signature dictionaries, for some //reason the 'Contents' entry of signatures is not really encrypted if( fields != null ) { for( int i=0; i entry : dictionary.entrySet() ) { //if we are a signature dictionary and contain a Contents entry then //we don't decrypt it. if( !(entry.getKey().getName().equals( "Contents" ) && entry.getValue() instanceof COSString && potentialSignatures.contains( dictionary ))) { decrypt( entry.getValue(), objNum, genNum ); } } } /** * This will decrypt a string. * * @param string the string to decrypt. * @param objNum The object number. * @param genNum The object generation number. * * @throws CryptographyException If an error occurs during decryption. * @throws IOException If an error occurs writing the new string. */ private void decryptString( COSString string, long objNum, long genNum ) throws CryptographyException, IOException { ByteArrayInputStream data = new ByteArrayInputStream( string.getBytes() ); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); encryption.encryptData( objNum, genNum, encryptionKey, data, buffer ); string.reset(); string.append( buffer.toByteArray() ); } /** * This will decrypt an array. * * @param array The array to decrypt. * @param objNum The object number. * @param genNum The object generation number. * * @throws CryptographyException If an error occurs during decryption. * @throws IOException If there is an error accessing the data. */ private void decryptArray( COSArray array, long objNum, long genNum ) throws CryptographyException, IOException { for( int i=0; iBen Litchfield * @author Pierre-Yves Landuré (pierre-yves@landure.org) * @version $Revision: 1.5 $ */ public class ConvertColorspace { private static final String PASSWORD = "-password"; private static final String CONVERSION = "-equiv"; private static final String DEST_COLORSPACE = "-toColorspace"; /** * private constructor. */ private ConvertColorspace() { //static class } /** * The method that replace RGB colors by CMYK ones. * * @param inputFile input file name. * @param colorEquivalents a dictionnary for the color equivalents. * @param destColorspace The destination colorspace, currently CMYK is supported. * * @throws IOException If there is an error parsing the document. */ private void replaceColors( PDDocument inputFile, Hashtable colorEquivalents, String destColorspace ) throws IOException { if( !destColorspace.equals( "CMYK" ) ) { throw new IOException( "Error: Unknown colorspace " + destColorspace ); } List pagesList = inputFile.getDocumentCatalog().getAllPages(); PDPage currentPage = null; PDFStreamParser parser = null; List pageTokens = null; List editedPageTokens = null; for(int pageCounter = 0; pageCounter < pagesList.size(); pageCounter++) // For each document page { currentPage = (PDPage)pagesList.get( pageCounter ); parser = new PDFStreamParser(currentPage.getContents().getStream()); parser.parse(); pageTokens = parser.getTokens(); editedPageTokens = new ArrayList(); for( int counter = 0; counter < pageTokens.size(); counter++) // For each page token { Object token = pageTokens.get( counter ); if( token instanceof PDFOperator ) // Test if PDFOperator { PDFOperator tokenOperator = (PDFOperator)token; if(tokenOperator.getOperation().equals("rg")) // Test if "rg" Operator. { if( destColorspace.equals( "CMYK" ) ) { replaceRGBTokensWithCMYKTokens( editedPageTokens, pageTokens, counter, colorEquivalents ); editedPageTokens.add( PDFOperator.getOperator( "k" )); } } else if(tokenOperator.getOperation().equals("RG")) // Test if "rg" Operator. { if( destColorspace.equals( "CMYK" ) ) { replaceRGBTokensWithCMYKTokens( editedPageTokens, pageTokens, counter, colorEquivalents ); editedPageTokens.add( PDFOperator.getOperator( "K" )); } } else if(tokenOperator.getOperation().equals("g")) // Test if "rg" Operator. { if( destColorspace.equals( "CMYK" ) ) { replaceGrayTokensWithCMYKTokens( editedPageTokens, pageTokens, counter, colorEquivalents ); editedPageTokens.add( PDFOperator.getOperator( "k" )); } } else if(tokenOperator.getOperation().equals("G")) // Test if "rg" Operator. { if( destColorspace.equals( "CMYK" ) ) { replaceGrayTokensWithCMYKTokens( editedPageTokens, pageTokens, counter, colorEquivalents ); editedPageTokens.add( PDFOperator.getOperator( "K" )); } } else { editedPageTokens.add( token ); } } else // Test if PDFOperator { editedPageTokens.add( token ); } } // For each page token // We replace original page content by the edited one. PDStream updatedPageContents = new PDStream(inputFile); ContentStreamWriter contentWriter = new ContentStreamWriter( updatedPageContents.createOutputStream() ); contentWriter.writeTokens( editedPageTokens ); currentPage.setContents( updatedPageContents ); } // For each document page } private void replaceRGBTokensWithCMYKTokens( List editedPageTokens, List pageTokens, int counter, Hashtable colorEquivalents ) { // Get current RGB color. float red = ((COSNumber)pageTokens.get( counter - 3 )).floatValue(); float green = ((COSNumber)pageTokens.get( counter - 2 )).floatValue(); float blue = ((COSNumber)pageTokens.get( counter - 1 )).floatValue(); int intRed = Math.round(red * 255.0f); int intGreen = Math.round(green * 255.0f); int intBlue = Math.round(blue * 255.0f); ColorSpaceInstance rgbColor = new ColorSpaceInstance(); rgbColor.colorspace = "RGB"; rgbColor.colorspaceValues = new int[] { intRed, intGreen, intBlue }; ColorSpaceInstance cmykColor = (ColorSpaceInstance)colorEquivalents.get(rgbColor); float[] cmyk = null; if( cmykColor != null ) { cmyk = new float[] { cmykColor.colorspaceValues[0] / 100.0f, cmykColor.colorspaceValues[1] / 100.0f, cmykColor.colorspaceValues[2] / 100.0f, cmykColor.colorspaceValues[3] / 100.0f }; } else { cmyk = convertRGBToCMYK( red, green, blue ); } //remove the RGB components that are already part of the editedPageTokens list editedPageTokens.remove( editedPageTokens.size() -1 ); editedPageTokens.remove( editedPageTokens.size() -1 ); editedPageTokens.remove( editedPageTokens.size() -1 ); // Add the new CMYK color editedPageTokens.add( new COSFloat( cmyk[0] ) ); editedPageTokens.add( new COSFloat( cmyk[1] ) ); editedPageTokens.add( new COSFloat( cmyk[2] ) ); editedPageTokens.add( new COSFloat( cmyk[3] ) ); } private void replaceGrayTokensWithCMYKTokens( List editedPageTokens, List pageTokens, int counter, Hashtable colorEquivalents ) { // Get current RGB color. float gray = ((COSNumber)pageTokens.get( counter - 1 )).floatValue(); ColorSpaceInstance grayColor = new ColorSpaceInstance(); grayColor.colorspace = "Grayscale"; grayColor.colorspaceValues = new int[] { Math.round( gray * 100 ) }; ColorSpaceInstance cmykColor = (ColorSpaceInstance)colorEquivalents.get(grayColor); float[] cmyk = null; if( cmykColor != null ) { cmyk = new float[] { cmykColor.colorspaceValues[0] / 100.0f, cmykColor.colorspaceValues[1] / 100.0f, cmykColor.colorspaceValues[2] / 100.0f, cmykColor.colorspaceValues[3] / 100.0f }; } else { cmyk = new float[] {0,0,0,gray}; } //remove the Gray components that are already part of the editedPageTokens list editedPageTokens.remove( editedPageTokens.size() -1 ); // Add the new CMYK color editedPageTokens.add( new COSFloat( cmyk[0] ) ); editedPageTokens.add( new COSFloat( cmyk[1] ) ); editedPageTokens.add( new COSFloat( cmyk[2] ) ); editedPageTokens.add( new COSFloat( cmyk[3] ) ); } private static float[] convertRGBToCMYK( float red, float green, float blue ) { // // RGB->CMYK from From // http://en.wikipedia.org/wiki/Talk:CMYK_color_model // float c = 1.0f - red; float m = 1.0f - green; float y = 1.0f - blue; float k = 1.0f; k = Math.min( Math.min( Math.min( c,k ), m), y ); c = ( c - k ) / ( 1 - k ); m = ( m - k ) / ( 1 - k ); y = ( y - k ) / ( 1 - k ); return new float[] { c,m,y,k}; } private static int[] stringToIntArray( String string ) { String[] ints = string.split( "," ); int[] retval = new int[ints.length]; for( int i=0; i= args.length ) { usage(); } password = args[i]; } if( args[i].equals( DEST_COLORSPACE ) ) { i++; if( i >= args.length ) { usage(); } destColorspace = args[i]; } if(args[i].equals( CONVERSION ) ) { i++; if( i >= args.length ) { usage(); } colorEquivalentMatcher = colorEquivalentPattern.matcher(args[i]); if(!colorEquivalentMatcher.matches()) { usage(); } String srcColorSpace = colorEquivalentMatcher.group(1); String srcColorvalues = colorEquivalentMatcher.group(2); String destColorSpace = colorEquivalentMatcher.group(3); String destColorvalues = colorEquivalentMatcher.group(4); ConvertColorspace.ColorSpaceInstance source = new ColorSpaceInstance(); source.colorspace = srcColorSpace; source.colorspaceValues = stringToIntArray( srcColorvalues ); ColorSpaceInstance dest = new ColorSpaceInstance(); dest.colorspace = destColorSpace; dest.colorspaceValues = stringToIntArray( destColorvalues ); colorEquivalents.put(source, dest); } else { if( inputFile == null ) { inputFile = args[i]; } else { outputFile = args[i]; } } } if( inputFile == null ) { usage(); } if( outputFile == null || outputFile.equals(inputFile)) { usage(); } PDDocument doc = null; try { doc = PDDocument.load( inputFile ); if( doc.isEncrypted() ) { doc.decrypt( password ); } ConvertColorspace converter = new ConvertColorspace(); converter.replaceColors(doc, colorEquivalents, destColorspace ); doc.save( outputFile ); } finally { if( doc != null ) { doc.close(); } } } /** * This will print the usage requirements and exit. */ private static void usage() { System.err.println( "Usage: java org.apache.pdfbox.ConvertColorspace [OPTIONS] " +"\n" + " -password Password to decrypt document\n" + " -equiv Color equivalent to use for conversion.\n" + " -destColorspace The destination colorspace, CMYK is the only '" + "supported colorspace." + " \n" + " The equiv format is : :(colorspace value)=:(colorspace value)" + " This option can be used as many times as necessary\n" + " The supported equiv colorspaces are RGB and CMYK.\n" + " RGB color values are integers between 0 and 255" + " CMYK color values are integer between 0 and 100.\n" + " Example: java org.apache.pdfbox.ConvertColorspace -equiv RGB:(255,0,0)=CMYK(0,99,100,0)" + " input.pdf output.pdf\n" + " The PDF document to use\n" + " The PDF file to write the result to. Must be different of input file\n" ); System.exit( 1 ); } /** * * */ private static class ColorSpaceInstance { private String colorspace = null; private int[] colorspaceValues = null; /** * {@inheritDoc} */ public int hashCode() { int code = colorspace.hashCode(); for( int i=0; i
* * usage: java org.apache.pdfbox.Decrypt <password> <inputfile> <outputfile> * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class Decrypt { private static final String ALIAS = "-alias"; private static final String PASSWORD = "-password"; private static final String KEYSTORE = "-keyStore"; private Decrypt() { } /** * This is the entry point for the application. * * @param args The command-line arguments. * * @throws Exception If there is an error decrypting the document. */ public static void main( String[] args ) throws Exception { Decrypt decrypt = new Decrypt(); decrypt.decrypt( args ); } private void decrypt( String[] args ) throws Exception { if( args.length < 2 || args.length > 5 ) { usage(); } else { String password = null; String infile = null; String outfile = null; String alias = null; String keyStore = null; for( int i=0; i= args.length ) { usage(); } alias = args[i]; } else if( args[i].equals( KEYSTORE ) ) { i++; if( i >= args.length ) { usage(); } keyStore = args[i]; } else if( args[i].equals( PASSWORD ) ) { i++; if( i >= args.length ) { usage(); } password = args[i]; } else if( infile == null ) { infile = args[i]; } else if( outfile == null ) { outfile = args[i]; } else { usage(); } } if( infile == null ) { usage(); } if( outfile == null ) { outfile = infile; } if( password == null ) { password = ""; } PDDocument document = null; try { document = PDDocument.load( infile ); if( document.isEncrypted() ) { DecryptionMaterial decryptionMaterial = null; if( keyStore != null ) { KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream(keyStore), password.toCharArray()); decryptionMaterial = new PublicKeyDecryptionMaterial(ks, alias, password); } else { decryptionMaterial = new StandardDecryptionMaterial(password); } document.openProtection(decryptionMaterial); AccessPermission ap = document.getCurrentAccessPermission(); if(ap.isOwnerPermission()) { document.setAllSecurityToBeRemoved(true); document.save( outfile ); } else { throw new IOException( "Error: You are only allowed to decrypt a document with the owner password." ); } } else { System.err.println( "Error: Document is not encrypted." ); } } finally { if( document != null ) { document.close(); } } } } /** * This will print a usage message. */ private static void usage() { System.err.println( "usage: java -jar pdfbox-app-x.y.z.jar Decrypt " + "[options] [outputfile]" ); System.err.println( "-alias The alias of the key in the certificate file " + "(mandatory if several keys are available)"); System.err.println( "-password The password to open the certificate and extract the private key from it." ); System.err.println( "-keyStore The KeyStore that holds the certificate." ); System.exit( -1 ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/Encrypt.java0000644000000000000000000002162312645757432023304 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import java.io.FileInputStream; import java.io.InputStream; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.encryption.AccessPermission; import org.apache.pdfbox.pdmodel.encryption.PublicKeyProtectionPolicy; import org.apache.pdfbox.pdmodel.encryption.PublicKeyRecipient; import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy; /** * This will read a document from the filesystem, encrypt it and and then write * the results to the filesystem.

* * @author Ben Litchfield * @version $Revision: 1.9 $ */ public class Encrypt { private Encrypt() { } /** * This is the entry point for the application. * * @param args The command-line arguments. * * @throws Exception If there is an error decrypting the document. */ public static void main( String[] args ) throws Exception { Encrypt encrypt = new Encrypt(); encrypt.encrypt( args ); } private void encrypt( String[] args ) throws Exception { if( args.length < 1 ) { usage(); } else { AccessPermission ap = new AccessPermission(); String infile = null; String outfile = null; String certFile = null; String userPassword = ""; String ownerPassword = ""; int keyLength = 40; PDDocument document = null; try { for( int i=0; i [outputfile]" ); System.err.println( " -O " + "Set the owner password(ignored if cert is set)" ); System.err.println( " -U " + "Set the user password(ignored if cert is set)" ); System.err.println( " -certFile Path to X.509 certificate" ); System.err.println( " -canAssemble Set the assemble permission" ); System.err.println( " -canExtractContent Set the extraction permission" ); System.err.println( " -canExtractForAccessibility Set the extraction permission" ); System.err.println( " -canFillInForm Set the fill in form permission" ); System.err.println( " -canModify Set the modify permission" ); System.err.println( " -canModifyAnnotations Set the modify annots permission" ); System.err.println( " -canPrint Set the print permission" ); System.err.println( " -canPrintDegraded Set the print degraded permission" ); System.err.println( " -keyLength The length of the key in bits (valid values: 40 and 128, default is 40)" ); System.err.println( "\nNote: By default all permissions are set to true!" ); System.exit( 1 ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/package.html0000644000000000000000000000173612645757432023301 0ustar rootroot This package holds executable classes that interact with the PDFBox application. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/PDFToImage.java0000644000000000000000000002406012645757432023535 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; import java.awt.HeadlessException; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.File; import java.util.List; import javax.imageio.ImageIO; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.util.PDFImageWriter; /** * Convert a PDF document to an image. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class PDFToImage { private static final String PASSWORD = "-password"; private static final String START_PAGE = "-startPage"; private static final String END_PAGE = "-endPage"; private static final String IMAGE_FORMAT = "-imageType"; private static final String OUTPUT_PREFIX = "-outputPrefix"; private static final String COLOR = "-color"; private static final String RESOLUTION = "-resolution"; private static final String CROPBOX = "-cropbox"; private static final String NONSEQ = "-nonSeq"; /** * private constructor. */ private PDFToImage() { //static class } /** * Infamous main method. * * @param args Command line arguments, should be one and a reference to a file. * * @throws Exception If there is an error parsing the document. */ public static void main( String[] args ) throws Exception { boolean useNonSeqParser = false; String password = ""; String pdfFile = null; String outputPrefix = null; String imageFormat = "jpg"; int startPage = 1; int endPage = Integer.MAX_VALUE; String color = "rgb"; int resolution; float cropBoxLowerLeftX = 0; float cropBoxLowerLeftY = 0; float cropBoxUpperRightX = 0; float cropBoxUpperRightY = 0; try { resolution = Toolkit.getDefaultToolkit().getScreenResolution(); } catch( HeadlessException e ) { resolution = 96; } for( int i = 0; i < args.length; i++ ) { if( args[i].equals( PASSWORD ) ) { i++; if( i >= args.length ) { usage(); } password = args[i]; } else if( args[i].equals( START_PAGE ) ) { i++; if( i >= args.length ) { usage(); } startPage = Integer.parseInt( args[i] ); } else if( args[i].equals( END_PAGE ) ) { i++; if( i >= args.length ) { usage(); } endPage = Integer.parseInt( args[i] ); } else if( args[i].equals( IMAGE_FORMAT ) ) { i++; imageFormat = args[i]; } else if( args[i].equals( OUTPUT_PREFIX ) ) { i++; outputPrefix = args[i]; } else if( args[i].equals( COLOR ) ) { i++; color = args[i]; } else if( args[i].equals( RESOLUTION ) ) { i++; resolution = Integer.parseInt(args[i]); } else if( args[i].equals( CROPBOX ) ) { i++; cropBoxLowerLeftX = Float.valueOf(args[i]).floatValue(); i++; cropBoxLowerLeftY = Float.valueOf(args[i]).floatValue(); i++; cropBoxUpperRightX = Float.valueOf(args[i]).floatValue(); i++; cropBoxUpperRightY = Float.valueOf(args[i]).floatValue(); } else if( args[i].equals( NONSEQ ) ) { useNonSeqParser = true; } else { if( pdfFile == null ) { pdfFile = args[i]; } } } if( pdfFile == null ) { usage(); } else { if(outputPrefix == null) { outputPrefix = pdfFile.substring( 0, pdfFile.lastIndexOf( '.' )); } PDDocument document = null; try { if (useNonSeqParser) { document = PDDocument.loadNonSeq(new File(pdfFile), null, password); } else { document = PDDocument.load( pdfFile ); if( document.isEncrypted() ) { document.decrypt( password ); } } int imageType = 24; if ("bilevel".equalsIgnoreCase(color)) { imageType = BufferedImage.TYPE_BYTE_BINARY; } else if ("indexed".equalsIgnoreCase(color)) { imageType = BufferedImage.TYPE_BYTE_INDEXED; } else if ("gray".equalsIgnoreCase(color)) { imageType = BufferedImage.TYPE_BYTE_GRAY; } else if ("rgb".equalsIgnoreCase(color)) { imageType = BufferedImage.TYPE_INT_RGB; } else if ("rgba".equalsIgnoreCase(color)) { imageType = BufferedImage.TYPE_INT_ARGB; } else { System.err.println( "Error: the number of bits per pixel must be 1, 8 or 24." ); System.exit( 2 ); } //if a CropBox has been specified, update the CropBox: //changeCropBoxes(PDDocument document,float a, float b, float c,float d) if ( cropBoxLowerLeftX!=0 || cropBoxLowerLeftY!=0 || cropBoxUpperRightX!=0 || cropBoxUpperRightY!=0 ) { changeCropBoxes(document, cropBoxLowerLeftX, cropBoxLowerLeftY, cropBoxUpperRightX, cropBoxUpperRightY); } //Make the call PDFImageWriter imageWriter = new PDFImageWriter(); boolean success = imageWriter.writeImage(document, imageFormat, password, startPage, endPage, outputPrefix, imageType, resolution); if (!success) { System.err.println( "Error: no writer found for image format '" + imageFormat + "'" ); System.exit(1); } } catch (Exception e) { System.err.println(e); } finally { if( document != null ) { document.close(); } } } } /** * This will print the usage requirements and exit. */ private static void usage() { System.err.println( "Usage: java -jar pdfbox-app-x.y.z.jar PDFToImage [OPTIONS] \n" + " -password Password to decrypt document\n" + " -imageType (" + getImageFormats() + ")\n" + " -outputPrefix Filename prefix for image files\n" + " -startPage The first page to start extraction(1 based)\n" + " -endPage The last page to extract(inclusive)\n" + " -color The color depth (valid: bilevel, indexed, gray, rgb, rgba)\n" + " -resolution The bitmap resolution in dpi\n" + " -cropbox The page area to export\n" + " -nonSeq Enables the new non-sequential parser\n" + " The PDF document to use\n" ); System.exit( 1 ); } private static String getImageFormats() { StringBuffer retval = new StringBuffer(); String[] formats = ImageIO.getReaderFormatNames(); for( int i = 0; i < formats.length; i++ ) { retval.append( formats[i] ); if( i + 1 < formats.length ) { retval.append( "," ); } } return retval.toString(); } private static void changeCropBoxes(PDDocument document,float a, float b, float c,float d) { List pages = document.getDocumentCatalog().getAllPages(); for( int i = 0; i < pages.size(); i++ ) { System.out.println("resizing page"); PDPage page = (PDPage)pages.get( i ); PDRectangle rectangle = new PDRectangle(); rectangle.setLowerLeftX(a); rectangle.setLowerLeftY(b); rectangle.setUpperRightX(c); rectangle.setUpperRightY(d); page.setMediaBox(rectangle); page.setCropBox(rectangle); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/0000755000000000000000000000000012645757432022777 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/NonSequentialPDFParser.java0000644000000000000000000024554512645757432030155 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.KeyStore; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.TreeMap; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNull; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.io.PushBackInputStream; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.io.RandomAccessBuffer; import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.encryption.AccessPermission; import org.apache.pdfbox.pdmodel.encryption.DecryptionMaterial; import org.apache.pdfbox.pdmodel.encryption.PDEncryptionDictionary; import org.apache.pdfbox.pdmodel.encryption.PublicKeyDecryptionMaterial; import org.apache.pdfbox.pdmodel.encryption.SecurityHandler; import org.apache.pdfbox.pdmodel.encryption.SecurityHandlersManager; import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * PDFParser which first reads startxref and xref tables in order to know valid * objects and parse only these objects. Thus it is closer to a conforming * parser than the sequential reading of {@link PDFParser}. * * This class can be used as a {@link PDFParser} replacement. First * {@link #parse()} must be called before page objects can be retrieved, e.g. * {@link #getPDDocument()}. * * This class is a much enhanced version of QuickParser presented * in PDFBOX-1104 by * Jeremy Villalobos. */ public class NonSequentialPDFParser extends PDFParser { private static final byte[] XREF_TABLE = new byte[] { 'x', 'r', 'e', 'f' }; private static final byte[] XREF_STREAM = new byte[] { '/','X', 'R', 'e', 'f' }; private static final long MINIMUM_SEARCH_OFFSET = 6; private static final int X = 'x'; public static final String SYSPROP_PARSEMINIMAL = "org.apache.pdfbox.pdfparser.nonSequentialPDFParser.parseMinimal"; public static final String SYSPROP_EOFLOOKUPRANGE = "org.apache.pdfbox.pdfparser.nonSequentialPDFParser.eofLookupRange"; private static final InputStream EMPTY_INPUT_STREAM = new ByteArrayInputStream(new byte[0]); protected static final int DEFAULT_TRAIL_BYTECOUNT = 2048; /** * EOF-marker. */ protected static final char[] EOF_MARKER = new char[] { '%', '%', 'E', 'O', 'F' }; /** * StartXRef-marker. */ protected static final char[] STARTXREF_MARKER = new char[] { 's', 't', 'a', 'r', 't', 'x', 'r', 'e', 'f' }; /** * obj-marker. */ protected static final char[] OBJ_MARKER = new char[] { 'o', 'b', 'j' }; /** * trailer-marker. */ private static final char[] TRAILER_MARKER = new char[] { 't', 'r', 'a', 'i', 'l', 'e', 'r' }; private long trailerOffset; private final File pdfFile; private long fileLen; private final RandomAccessBufferedFileInputStream raStream; /** * is parser using auto healing capacity ? */ private boolean isLenient = true; /** * Contains all found objects of a brute force search. */ private HashMap bfSearchObjectOffsets = null; private HashMap bfSearchCOSObjectKeyOffsets = null; private Vector bfSearchXRefOffsets = null; /** * The security handler. */ protected SecurityHandler securityHandler = null; private String keyStoreFilename = null; private String alias = null; private String password = ""; private int readTrailBytes = DEFAULT_TRAIL_BYTECOUNT; // how many trailing // bytes to read for // EOF marker /** * If true object references in catalog are not followed; pro: * page objects will be only parsed when needed; cons: some information of * catalog might not be available (e.g. outline). Catalog parsing without * pages is not an option since a number of entries will also refer to page * objects (like OpenAction). */ private boolean parseMinimalCatalog = "true".equals(System.getProperty(SYSPROP_PARSEMINIMAL)); private boolean initialParseDone = false; private boolean allPagesParsed = false; private static final Log LOG = LogFactory.getLog(NonSequentialPDFParser.class); /** * true if the NonSequentialPDFParser is initialized by a * InputStream, in this case a temporary file is created. At the end of the * {@linkplain #parse()} method,the temporary file will be deleted. */ private boolean isTmpPDFFile = false; public static final String TMP_FILE_PREFIX = "tmpPDF"; // ------------------------------------------------------------------------ /** * Constructs parser for given file using memory buffer. * * @param filename the filename of the pdf to be parsed * * @throws IOException If something went wrong. */ public NonSequentialPDFParser(String filename) throws IOException { this(new File(filename), null); } /** * Constructs parser for given file using given buffer for temporary * storage. * * @param file the pdf to be parsed * @param raBuf the buffer to be used for parsing * * @throws IOException If something went wrong. */ /** * Constructs parser for given file using given buffer for temporary * storage. * * @param file the pdf to be parsed * @param raBuf the buffer to be used for parsing * * @throws IOException If something went wrong. */ public NonSequentialPDFParser(File file, RandomAccess raBuf) throws IOException { this(file, raBuf, ""); } /** * Constructs parser for given file using given buffer for temporary * storage. * * @param file the pdf to be parsed * @param raBuf the buffer to be used for parsing * * @throws IOException If something went wrong. */ /** * Constructs parser for given file using given buffer for temporary * storage. * * @param file the pdf to be parsed * @param raBuf the buffer to be used for parsing * @param decryptionPassword password to be used for decryption * * @throws IOException If something went wrong. */ public NonSequentialPDFParser(File file, RandomAccess raBuf, String decryptionPassword) throws IOException { super(EMPTY_INPUT_STREAM, null, false); pdfFile = file; raStream = new RandomAccessBufferedFileInputStream(pdfFile); init(file, raBuf, decryptionPassword); } private void init(File file, RandomAccess raBuf, String decryptionPassword) throws IOException { String eofLookupRangeStr = System.getProperty(SYSPROP_EOFLOOKUPRANGE); if (eofLookupRangeStr != null) { try { setEOFLookupRange(Integer.parseInt(eofLookupRangeStr)); } catch (NumberFormatException nfe) { LOG.warn("System property " + SYSPROP_EOFLOOKUPRANGE + " does not contain an integer value, but: '" + eofLookupRangeStr + "'"); } } setDocument((raBuf == null) ? new COSDocument(new RandomAccessBuffer(), false) : new COSDocument(raBuf, false)); pdfSource = new PushBackInputStream(raStream, 4096); password = decryptionPassword; } /** * Constructor. * * @param input input stream representing the pdf. * @throws IOException If something went wrong. */ public NonSequentialPDFParser(InputStream input) throws IOException { this(input, null, ""); } /** * Constructor. * * @param input input stream representing the pdf. * @param raBuf the buffer to be used for parsing * @param decryptionPassword password to be used for decryption. * @throws IOException If something went wrong. */ public NonSequentialPDFParser(InputStream input, RandomAccess raBuf, String decryptionPassword) throws IOException { super(EMPTY_INPUT_STREAM, null, false); pdfFile = createTmpFile(input); raStream = new RandomAccessBufferedFileInputStream(pdfFile); init(pdfFile, raBuf, decryptionPassword); } /** * Create a temporary file with the input stream. If the creation succeed, * the {@linkplain #isTmpPDFFile} is set to true. This Temporary file will * be deleted at end of the parse method * * @param input * @return the temporary file * @throws IOException If something went wrong. */ private File createTmpFile(InputStream input) throws IOException { File tmpFile = null; FileOutputStream fos = null; try { tmpFile = File.createTempFile(TMP_FILE_PREFIX, ".pdf"); fos = new FileOutputStream(tmpFile); IOUtils.copy(input, fos); isTmpPDFFile = true; return tmpFile; } finally { IOUtils.closeQuietly(input); IOUtils.closeQuietly(fos); } } // ------------------------------------------------------------------------ /** * Sets how many trailing bytes of PDF file are searched for EOF marker and * 'startxref' marker. If not set we use default value * {@link #DEFAULT_TRAIL_BYTECOUNT}. * * * *

In case system property {@link #SYSPROP_EOFLOOKUPRANGE} is defined * this value will be set on initialization but can be overwritten * later.

* * @param byteCount number of trailing bytes */ public void setEOFLookupRange(int byteCount) { if (byteCount > 15) { readTrailBytes = byteCount; } } /** * The initial parse will first parse only the trailer, the xrefstart and * all xref tables to have a pointer (offset) to all the pdf's objects. It * can handle linearized pdfs, which will have an xref at the end pointing * to an xref at the beginning of the file. Last the root object is parsed. * * @throws IOException If something went wrong. */ protected void initialParse() throws IOException { COSDictionary trailer = null; // ---- parse startxref long startXRefOffset = getStartxrefOffset(); if (startXRefOffset > 0) { trailer = parseXref(startXRefOffset); } else if (isFDFDocment || isLenient) { // signal start of new XRef xrefTrailerResolver.nextXrefObj(startXRefOffset); bfSearchForObjects(); for (COSObjectKey objectKey : bfSearchCOSObjectKeyOffsets.keySet()) { xrefTrailerResolver.setXRef(objectKey, bfSearchCOSObjectKeyOffsets.get(objectKey)); } // parse the last trailer. pdfSource.seek(trailerOffset); if (!parseTrailer()) { throw new IOException("Expected trailer object at position: " + pdfSource.getOffset()); } xrefTrailerResolver.setStartxref(startXRefOffset); trailer = xrefTrailerResolver.getCurrentTrailer(); document.setTrailer(trailer); } // ---- prepare decryption if necessary prepareDecryption(); // PDFBOX-1557 - ensure that all COSObject are loaded in the trailer // PDFBOX-1606 - after securityHandler has been instantiated for (COSBase trailerEntry : trailer.getValues()) { if (trailerEntry instanceof COSObject) { COSObject tmpObj = (COSObject) trailerEntry; parseObjectDynamically(tmpObj, false); } } // ---- parse catalog or root object COSObject root = (COSObject) xrefTrailerResolver.getTrailer().getItem(COSName.ROOT); if (root == null) { throw new IOException("Missing root object specification in trailer."); } COSBase rootObject = parseObjectDynamically(root, false); // ---- resolve all objects if (isFDFDocment) { // A FDF doesn't have a catalog, all FDF fields are within the root object if (rootObject instanceof COSDictionary) { parseDictObjects((COSDictionary) rootObject, (COSName[]) null); allPagesParsed = true; document.setDecrypted(); } } else { if (!(rootObject instanceof COSDictionary)) { throw new IOException("Expected root dictionary, but got this: " + rootObject); } COSDictionary rootDictionary = (COSDictionary)rootObject; // in some pdfs the type value "Catalog" is missing in the root object if (isLenient() && !rootDictionary.containsKey(COSName.TYPE)) { rootDictionary.setItem(COSName.TYPE, COSName.CATALOG); } if(!parseMinimalCatalog) { COSObject catalogObj = document.getCatalog(); if (catalogObj != null) { if (catalogObj.getObject() instanceof COSDictionary) { parseDictObjects((COSDictionary) catalogObj.getObject(), (COSName[]) null); COSBase infoBase = trailer.getDictionaryObject(COSName.INFO); if (infoBase instanceof COSDictionary) { parseDictObjects((COSDictionary) infoBase, (COSName[]) null); } allPagesParsed = true; document.setDecrypted(); } } } } // PDFBOX-1922: read the version again now that all objects have been resolved readVersionInTrailer(trailer); initialParseDone = true; } /** * Resolves all not already parsed objects of a dictionary recursively. * * @param dictionaryObject dictionary to be parsed * @throws IOException if something went wrong * */ private void parseDictionaryRecursive(COSObject dictionaryObject) throws IOException { parseObjectDynamically(dictionaryObject, true); COSDictionary dictionary = (COSDictionary)dictionaryObject.getObject(); for(COSBase value : dictionary.getValues()) { if (value instanceof COSObject) { COSObject object = (COSObject)value; if (object.getObject() == null) { parseDictionaryRecursive(object); } } } } /** * Prepare for decryption. * * @throws IOException if something went wrong */ private void prepareDecryption() throws IOException { COSBase trailerEncryptItem = document.getTrailer().getItem(COSName.ENCRYPT); if (trailerEncryptItem != null && !(trailerEncryptItem instanceof COSNull)) { if (trailerEncryptItem instanceof COSObject) { COSObject trailerEncryptObj = (COSObject) trailerEncryptItem; parseDictionaryRecursive(trailerEncryptObj); } try { PDEncryptionDictionary encParameters = new PDEncryptionDictionary(document.getEncryptionDictionary()); DecryptionMaterial decryptionMaterial = null; if (keyStoreFilename != null) { KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream(keyStoreFilename), password.toCharArray()); decryptionMaterial = new PublicKeyDecryptionMaterial(ks, alias, password); } else { decryptionMaterial = new StandardDecryptionMaterial(password); } securityHandler = SecurityHandlersManager.getInstance().getSecurityHandler(encParameters.getFilter()); securityHandler.prepareForDecryption(encParameters, document.getDocumentID(), decryptionMaterial); AccessPermission permission = securityHandler.getCurrentAccessPermission(); if (!permission.canExtractContent()) { LOG.warn("PDF file '" + pdfFile.getPath() + "' does not allow extracting content."); } } catch (Exception e) { throw new IOException("Error (" + e.getClass().getSimpleName() + ") while creating security handler for decryption: " + e.getMessage() /* * , e TODO: remove * remark with Java 1.6 */); } } } /** * Parses cross reference tables. * * @param startXRefOffset start offset of the first table * @return the trailer dictionary * @throws IOException if something went wrong */ private COSDictionary parseXref(long startXRefOffset) throws IOException { setPdfSource(startXRefOffset); parseStartXref(); long startXrefOffset = document.getStartXref(); // check the startxref offset long fixedOffset = checkXRefOffset(startXrefOffset); if (fixedOffset > -1) { startXrefOffset = fixedOffset; document.setStartXref(startXrefOffset); } long prev = startXrefOffset; // ---- parse whole chain of xref tables/object streams using PREV // reference while (prev > 0) { // seek to xref table setPdfSource(prev); // skip white spaces skipSpaces(); // -- parse xref if (pdfSource.peek() == X) { // xref table and trailer // use existing parser to parse xref table parseXrefTable(prev); // parse the last trailer. trailerOffset = pdfSource.getOffset(); //PDFBOX-1739 skip extra xref entries in RegisSTAR documents while (isLenient && pdfSource.peek() != 't') { if (pdfSource.getOffset() == trailerOffset) { // warn only the first time LOG.warn("Expected trailer object at position " + trailerOffset + ", keep trying"); } readLine(); } if (!parseTrailer()) { throw new IOException("Expected trailer object at position: " + pdfSource.getOffset()); } COSDictionary trailer = xrefTrailerResolver.getCurrentTrailer(); // check for a XRef stream, it may contain some object ids of compressed objects if(trailer.containsKey(COSName.XREF_STM)) { int streamOffset = trailer.getInt(COSName.XREF_STM); // check the xref stream reference fixedOffset = checkXRefOffset(streamOffset); if (fixedOffset > -1 && fixedOffset != streamOffset) { streamOffset = (int)fixedOffset; trailer.setInt(COSName.XREF_STM, streamOffset); } setPdfSource(streamOffset); skipSpaces(); parseXrefObjStream(prev, false); } prev = trailer.getInt(COSName.PREV); if (prev > 0) { // check the xref table reference fixedOffset = checkXRefOffset(prev); if (fixedOffset > -1 && fixedOffset != prev) { prev = fixedOffset; trailer.setLong(COSName.PREV, prev); } } } else { // parse xref stream prev = parseXrefObjStream(prev, true); if (prev > 0) { // check the xref table reference fixedOffset = checkXRefOffset(prev); if (fixedOffset > -1 && fixedOffset != prev) { prev = fixedOffset; COSDictionary trailer = xrefTrailerResolver.getCurrentTrailer(); trailer.setLong(COSName.PREV, prev); } } } } // ---- build valid xrefs out of the xref chain xrefTrailerResolver.setStartxref(startXrefOffset); COSDictionary trailer = xrefTrailerResolver.getTrailer(); document.setTrailer(trailer); // check the offsets of all referenced objects checkXrefOffsets(); return trailer; } /** * Parses an xref object stream starting with indirect object id. * * @return value of PREV item in dictionary or -1 if no such * item exists */ private long parseXrefObjStream(long objByteOffset, boolean isStandalone) throws IOException { // ---- parse indirect object head readObjectNumber(); readGenerationNumber(); readPattern(OBJ_MARKER); COSDictionary dict = parseCOSDictionary(); COSStream xrefStream = parseCOSStream(dict, getDocument().getScratchFile()); parseXrefStream(xrefStream, (int) objByteOffset,isStandalone); return dict.getLong(COSName.PREV); } // ------------------------------------------------------------------------ /** Get current offset in file at which next byte would be read. */ private final long getPdfSourceOffset() { return pdfSource.getOffset(); } /** * Sets {@link #pdfSource} to start next parsing at given file offset. * * @param fileOffset file offset * @throws IOException If something went wrong. */ protected final void setPdfSource(long fileOffset) throws IOException { pdfSource.seek(fileOffset); // alternative using 'old fashioned' input stream // if ( pdfSource != null ) // pdfSource.close(); // // pdfSource = new PushBackInputStream( // new BufferedInputStream( // new FileInputStream( file ), 16384), 4096); // pdfSource.skip( _fileOffset ); } /** * Enable handling of alternative pdfSource implementation. * @throws IOException If something went wrong. */ protected final void releasePdfSourceInputStream() throws IOException { // if ( pdfSource != null ) // pdfSource.close(); } private final void closeFileStream() throws IOException { if (pdfSource != null) { pdfSource.close(); } } // ------------------------------------------------------------------------ /** * Looks for and parses startxref. We first look for last '%%EOF' marker * (within last {@link #DEFAULT_TRAIL_BYTECOUNT} bytes (or range set via * {@link #setEOFLookupRange(int)}) and go back to find * startxref. * * @return the offset of StartXref * @throws IOException If something went wrong. */ protected final long getStartxrefOffset() throws IOException { byte[] buf; long skipBytes; // ---- read trailing bytes into buffer fileLen = pdfFile.length(); FileInputStream fIn = null; try { fIn = new FileInputStream(pdfFile); final int trailByteCount = (fileLen < readTrailBytes) ? (int) fileLen : readTrailBytes; buf = new byte[trailByteCount]; fIn.skip(skipBytes = fileLen - trailByteCount); int off = 0; int readBytes; while (off < trailByteCount) { readBytes = fIn.read(buf, off, trailByteCount - off); // in order to not get stuck in a loop we check readBytes (this // should never happen) if (readBytes < 1) { throw new IOException("No more bytes to read for trailing buffer, but expected: " + (trailByteCount - off)); } off += readBytes; } } finally { if (fIn != null) { try { fIn.close(); } catch (IOException ioe) { } } } // ---- find last '%%EOF' int bufOff = lastIndexOf(EOF_MARKER, buf, buf.length); if (bufOff < 0) { if (isLenient) { // in lenient mode the '%%EOF' isn't needed bufOff = buf.length; LOG.debug("Missing end of file marker '" + (new String(EOF_MARKER)) + "'"); } else { throw new IOException("Missing end of file marker '" + (new String(EOF_MARKER)) + "'"); } } // ---- find last startxref preceding EOF marker bufOff = lastIndexOf(STARTXREF_MARKER, buf, bufOff); if (bufOff < 0) { if (isLenient) { trailerOffset = lastIndexOf(TRAILER_MARKER, buf, buf.length); if (trailerOffset > 0) { trailerOffset += skipBytes; } return -1; } else { throw new IOException("Missing 'startxref' marker."); } } return skipBytes + bufOff; } // ------------------------------------------------------------------------ /** * Searches last appearance of pattern within buffer. Lookup before _lastOff * and goes back until 0. * * @param pattern pattern to search for * @param buf buffer to search pattern in * @param endOff offset (exclusive) where lookup starts at * * @return start offset of pattern within buffer or -1 if * pattern could not be found */ protected int lastIndexOf(final char[] pattern, final byte[] buf, final int endOff) { final int lastPatternChOff = pattern.length - 1; int bufOff = endOff; int patOff = lastPatternChOff; char lookupCh = pattern[patOff]; while (--bufOff >= 0) { if (buf[bufOff] == lookupCh) { if (--patOff < 0) { // whole pattern matched return bufOff; } // matched current char, advance to preceding one lookupCh = pattern[patOff]; } else if (patOff < lastPatternChOff) { // no char match but already matched some chars; reset lookupCh = pattern[patOff = lastPatternChOff]; } } return -1; } // ------------------------------------------------------------------------ /** * Reads given pattern from {@link #pdfSource}. Skipping whitespace at start * and end. * * @param pattern pattern to be skipped * @throws IOException if pattern could not be read */ protected final void readPattern(final char[] pattern) throws IOException { skipSpaces(); for (char c : pattern) { if (pdfSource.read() != c) { throw new IOException("Expected pattern '" + new String(pattern) + "' but missed at character '" + c + "' at offset " + pdfSource.getOffset()); } } skipSpaces(); } // ------------------------------------------------------------------------ private COSDictionary pagesDictionary = null; /** * Returns PAGES {@link COSDictionary} object or throws {@link IOException} * if PAGES dictionary does not exist. */ private COSDictionary getPagesObject() throws IOException { if (pagesDictionary != null) { return pagesDictionary; } COSObject pages = (COSObject) document.getCatalog().getItem(COSName.PAGES); if (pages == null) { throw new IOException("Missing PAGES entry in document catalog."); } COSBase object = parseObjectDynamically(pages, false); if (!(object instanceof COSDictionary)) { throw new IOException("PAGES not a dictionary object, but: " + object.getClass().getSimpleName()); } pagesDictionary = (COSDictionary) object; return pagesDictionary; } // ------------------------------------------------------------------------ /** Parses all objects needed by pages and closes input stream. */ /** * {@inheritDoc} */ @Override public void parse() throws IOException { boolean exceptionOccurred = true; // set to false if all is processed try { // PDFBOX-1922 read the version header and rewind // this part copied from the sequential parser parseHeader(); pdfSource.seek(0); if (!initialParseDone) { initialParse(); } // a FDF doesn't have any pages if (!isFDFDocment) { final int pageCount = getPageNumber(); if (!allPagesParsed) { for (int pNr = 0; pNr < pageCount; pNr++) { getPage(pNr); } allPagesParsed = true; document.setDecrypted(); } } exceptionOccurred = false; } finally { try { closeFileStream(); } catch (IOException ioe) { } deleteTempFile(); if (exceptionOccurred && (document != null)) { try { document.close(); document = null; } catch (IOException ioe) { } } } } /** * Return the pdf file. * * @return the pdf file */ protected File getPdfFile() { return this.pdfFile; } /** * Return true if parser is lenient. Meaning auto healing capacity of the parser are used. * * @return true if parser is lenient */ public boolean isLenient () { return isLenient; } /** * Change the parser leniency flag. * * This method can only be called before the parsing of the file. * * @param lenient * * @throws IllegalArgumentException if the method is called after parsing. */ public void setLenient(boolean lenient) throws IllegalArgumentException { if (initialParseDone) { throw new IllegalArgumentException("Cannot change leniency after parsing"); } this.isLenient = lenient; } /** * Remove the temporary file. A temporary file is created if this class is * instantiated with an InputStream */ protected void deleteTempFile() { if (isTmpPDFFile) { try { if (!pdfFile.delete()) { LOG.warn("Temporary file '" + pdfFile.getName() + "' can't be deleted"); } } catch (SecurityException e) { LOG.warn("Temporary file '" + pdfFile.getName() + "' can't be deleted", e); } } } // ------------------------------------------------------------------------ /** * Returns security handler of the document or null if document * is not encrypted or {@link #parse()} wasn't called before. * * @return the security handler. */ public SecurityHandler getSecurityHandler() { return securityHandler; } // ------------------------------------------------------------------------ /** * This will get the PD document that was parsed. When you are done with * this document you must call close() on it to release resources. * * Overwriting super method was necessary in order to set security handler. * * @return The document at the PD layer. * * @throws IOException If there is an error getting the document. */ @Override public PDDocument getPDDocument() throws IOException { PDDocument pdDocument = super.getPDDocument(); if (securityHandler != null) { pdDocument.setSecurityHandler(securityHandler); } return pdDocument; } // ------------------------------------------------------------------------ /** * Returns the number of pages in a document. * * @return the number of pages. * * @throws IOException if PAGES or other needed object is missing */ public int getPageNumber() throws IOException { int pageCount = getPagesObject().getInt(COSName.COUNT); if (pageCount < 0) { throw new IOException("No page number specified."); } return pageCount; } // ------------------------------------------------------------------------ /** * Returns the page requested with all the objects loaded into it. * * @param pageNr starts from 0 to the number of pages. * @return the page with the given pagenumber. * @throws IOException If something went wrong. */ public PDPage getPage(int pageNr) throws IOException { getPagesObject(); // ---- get list of top level pages COSArray kids = (COSArray) pagesDictionary.getDictionaryObject(COSName.KIDS); if (kids == null) { throw new IOException("Missing 'Kids' entry in pages dictionary."); } // ---- get page we are looking for (possibly going recursively into // subpages) COSObject pageObj = getPageObject(pageNr, kids, 0); if (pageObj == null) { throw new IOException("Page " + pageNr + " not found."); } // parse all objects necessary to load page. COSDictionary pageDict = (COSDictionary) pageObj.getObject(); // parse all objects necessary to load page. if (parseMinimalCatalog && (!allPagesParsed)) { parseDictObjects(pageDict); } return new PDPage(pageDict); } /** * Returns the object for a specific page. The page tree is made up of kids. * The kids have COSArray with COSObjects inside of them. The COSObject can * be parsed using the dynamic parsing method We want to only parse the * minimum COSObjects and still return a complete page. ready to be used. * * @param num the requested page number; numbering starts with 0 * @param startKids Kids array to start with looking up page number * @param startPageCount * * @return page object or null if no such page exists * * @throws IOException */ private COSObject getPageObject(int num, COSArray startKids, int startPageCount) throws IOException { int curPageCount = startPageCount; Iterator kidsIter = startKids.iterator(); while (kidsIter.hasNext()) { COSObject obj = (COSObject) kidsIter.next(); COSBase base = obj.getObject(); if (base == null) { base = parseObjectDynamically(obj, false); obj.setObject(base); } COSDictionary dic = (COSDictionary) base; int count = dic.getInt(COSName.COUNT); if (count >= 0) { // skip this branch if requested page comes later if ((curPageCount + count) <= num) { curPageCount += count; continue; } } COSArray kids = (COSArray) dic.getDictionaryObject(COSName.KIDS); if (kids != null) { // recursively scan subpages COSObject ans = getPageObject(num, kids, curPageCount); // if ans is not null, we got what we were looking for if (ans != null) { return ans; } } else { // found page? if (curPageCount == num) { return obj; } // page has no kids and it is not the page we are looking for curPageCount++; } } return null; } /** * Creates a unique object id using object number and object generation * number. (requires object number < 2^31)) */ private final long getObjectId(final COSObject obj) { return (obj.getObjectNumber().longValue() << 32) | obj.getGenerationNumber().longValue(); } /** * Adds all from newObjects to toBeParsedList if it is not an COSObject or * we didn't add this COSObject already (checked via addedObjects). */ private final void addNewToList(final Queue toBeParsedList, final Collection newObjects, final Set addedObjects) { for (COSBase newObject : newObjects) { if (newObject instanceof COSObject) { final long objId = getObjectId((COSObject) newObject); if (!addedObjects.add(objId)) { continue; } } toBeParsedList.add(newObject); } } /** * Adds newObject to toBeParsedList if it is not an COSObject or we didn't * add this COSObject already (checked via addedObjects). */ private final void addNewToList(final Queue toBeParsedList, final COSBase newObject, final Set addedObjects) { if (newObject instanceof COSObject) { final long objId = getObjectId((COSObject) newObject); if (!addedObjects.add(objId)) { return; } } toBeParsedList.add(newObject); } /** * Will parse every object necessary to load a single page from the pdf * document. We try our best to order objects according to offset in file * before reading to minimize seek operations. * * @param dict the COSObject from the parent pages. * @param excludeObjects dictionary object reference entries with these * names will not be parsed * * @throws IOException */ private void parseDictObjects(COSDictionary dict, COSName... excludeObjects) throws IOException { // ---- create queue for objects waiting for further parsing final Queue toBeParsedList = new LinkedList(); // offset ordered object map final TreeMap> objToBeParsed = new TreeMap>(); // in case of compressed objects offset points to stmObj final Set parsedObjects = new HashSet(); final Set addedObjects = new HashSet(); // ---- add objects not to be parsed to list of already parsed objects if (excludeObjects != null) { for (COSName objName : excludeObjects) { COSBase baseObj = dict.getItem(objName); if (baseObj instanceof COSObject) { parsedObjects.add(getObjectId((COSObject) baseObj)); } } } addNewToList(toBeParsedList, dict.getValues(), addedObjects); // ---- go through objects to be parsed while (!(toBeParsedList.isEmpty() && objToBeParsed.isEmpty())) { // -- first get all COSObject from other kind of objects and // put them in objToBeParsed; afterwards toBeParsedList is empty COSBase baseObj; while ((baseObj = toBeParsedList.poll()) != null) { if (baseObj instanceof COSStream) { addNewToList(toBeParsedList, ((COSStream) baseObj).getValues(), addedObjects); } else if (baseObj instanceof COSDictionary) { addNewToList(toBeParsedList, ((COSDictionary) baseObj).getValues(), addedObjects); } else if (baseObj instanceof COSArray) { final Iterator arrIter = ((COSArray) baseObj).iterator(); while (arrIter.hasNext()) { addNewToList(toBeParsedList, arrIter.next(), addedObjects); } } else if (baseObj instanceof COSObject) { COSObject obj = (COSObject) baseObj; long objId = getObjectId(obj); COSObjectKey objKey = new COSObjectKey(obj.getObjectNumber().intValue(), obj.getGenerationNumber() .intValue()); if (!(parsedObjects.contains(objId) /* * || document.hasObjectInPool ( objKey ) */)) { Long fileOffset = xrefTrailerResolver.getXrefTable().get(objKey); // it is allowed that object references point to null, // thus we have to test if (fileOffset != null && fileOffset != 0) { if (fileOffset > 0) { objToBeParsed.put(fileOffset, Collections.singletonList(obj)); } else { // negative offset means we have a compressed // object within object stream; // get offset of object stream fileOffset = xrefTrailerResolver.getXrefTable().get(new COSObjectKey(-fileOffset, 0)); if ((fileOffset == null) || (fileOffset <= 0)) { throw new IOException( "Invalid object stream xref object reference for key '" + objKey + "': " + fileOffset); } List stmObjects = objToBeParsed.get(fileOffset); if (stmObjects == null) { objToBeParsed.put(fileOffset, stmObjects = new ArrayList()); } stmObjects.add(obj); } } else { // NULL object COSObject pdfObject = document.getObjectFromPool(objKey); pdfObject.setObject(COSNull.NULL); } } } } // ---- read first COSObject with smallest offset; // resulting object will be added to toBeParsedList if (objToBeParsed.isEmpty()) { break; } for (COSObject obj : objToBeParsed.remove(objToBeParsed.firstKey())) { COSBase parsedObj = parseObjectDynamically(obj, false); obj.setObject(parsedObj); addNewToList(toBeParsedList, parsedObj, addedObjects); parsedObjects.add(getObjectId(obj)); } } } /** * This will parse the next object from the stream and add it to the local * state. This is taken from {@link PDFParser} and reduced to parsing an * indirect object. * * @param obj object to be parsed (we only take object number and generation * number for lookup start offset) * @param requireExistingNotCompressedObj if true object to be * parsed must not be contained within compressed stream * @return the parsed object (which is also added to document object) * * @throws IOException If an IO error occurs. */ protected final COSBase parseObjectDynamically(COSObject obj, boolean requireExistingNotCompressedObj) throws IOException { return parseObjectDynamically(obj.getObjectNumber().intValue(), obj.getGenerationNumber().intValue(), requireExistingNotCompressedObj); } /** * This will parse the next object from the stream and add it to the local * state. This is taken from {@link PDFParser} and reduced to parsing an * indirect object. * * @param objNr object number of object to be parsed * @param objGenNr object generation number of object to be parsed * @param requireExistingNotCompressedObj if true the object to * be parsed must be defined in xref (comment: null objects may * be missing from xref) and it must not be a compressed object * within object stream (this is used to circumvent being stuck * in a loop in a malicious PDF) * * @return the parsed object (which is also added to document object) * * @throws IOException If an IO error occurs. */ protected COSBase parseObjectDynamically(int objNr, int objGenNr, boolean requireExistingNotCompressedObj) throws IOException { // ---- create object key and get object (container) from pool final COSObjectKey objKey = new COSObjectKey(objNr, objGenNr); final COSObject pdfObject = document.getObjectFromPool(objKey); if (pdfObject.getObject() == null) { // not previously parsed // ---- read offset or object stream object number from xref table Long offsetOrObjstmObNr = xrefTrailerResolver.getXrefTable().get(objKey); // sanity test to circumvent loops with broken documents if (requireExistingNotCompressedObj && ((offsetOrObjstmObNr == null) || (offsetOrObjstmObNr <= 0))) { throw new IOException("Object must be defined and must not be compressed object: " + objKey.getNumber() + ":" + objKey.getGeneration()); } if (offsetOrObjstmObNr == null) { // not defined object -> NULL object (Spec. 1.7, chap. 3.2.9) pdfObject.setObject(COSNull.NULL); } else if (offsetOrObjstmObNr > 0) { // offset of indirect object in file // ---- go to object start setPdfSource(offsetOrObjstmObNr); // ---- we must have an indirect object final long readObjNr = readObjectNumber(); final long readObjGen = readGenerationNumber(); readPattern(OBJ_MARKER); // ---- consistency check if ((readObjNr != objKey.getNumber()) || (readObjGen != objKey.getGeneration())) { throw new IOException("XREF for " + objKey.getNumber() + ":" + objKey.getGeneration() + " points to wrong object: " + readObjNr + ":" + readObjGen); } skipSpaces(); COSBase pb = parseDirObject(); String endObjectKey = readString(); if (endObjectKey.equals("stream")) { pdfSource.unread(endObjectKey.getBytes("ISO-8859-1")); pdfSource.unread(' '); if (pb instanceof COSDictionary) { COSStream stream = parseCOSStream((COSDictionary) pb, getDocument().getScratchFile()); if (securityHandler != null) { try { securityHandler.decryptStream(stream, objNr, objGenNr); } catch (CryptographyException ce) { throw new IOException("Error decrypting stream object " + objNr + ": " + ce.getMessage() /* , ce // TODO: remove remark with Java 1.6 */); } } pb = stream; } else { // this is not legal // the combination of a dict and the stream/endstream // forms a complete stream object throw new IOException("Stream not preceded by dictionary (offset: " + offsetOrObjstmObNr + ")."); } skipSpaces(); endObjectKey = readLine(); // we have case with a second 'endstream' before endobj if (!endObjectKey.startsWith("endobj")) { if (endObjectKey.startsWith("endstream")) { endObjectKey = endObjectKey.substring(9).trim(); if (endObjectKey.length() == 0) { // no other characters in extra endstream line endObjectKey = readLine(); // read next line } } } } else if (securityHandler != null) { decrypt(pb, objNr, objGenNr); } pdfObject.setObject(pb); if (!endObjectKey.startsWith("endobj")) { if (isLenient) { LOG.warn("Object (" + readObjNr + ":" + readObjGen + ") at offset " + offsetOrObjstmObNr + " does not end with 'endobj' but with '" + endObjectKey + "'"); } else { throw new IOException("Object (" + readObjNr + ":" + readObjGen + ") at offset " + offsetOrObjstmObNr + " does not end with 'endobj' but with '" + endObjectKey + "'"); } } releasePdfSourceInputStream(); } else { // xref value is object nr of object stream containing object to // be parsed; // since our object was not found it means object stream was not // parsed so far final int objstmObjNr = (int) (-offsetOrObjstmObNr); final COSBase objstmBaseObj = parseObjectDynamically(objstmObjNr, 0, true); if (objstmBaseObj instanceof COSStream) { // parse object stream PDFObjectStreamParser parser = new PDFObjectStreamParser((COSStream) objstmBaseObj, document, forceParsing); parser.parse(); // get set of object numbers referenced for this object // stream final Set refObjNrs = xrefTrailerResolver.getContainedObjectNumbers(objstmObjNr); // register all objects which are referenced to be contained // in object stream for (COSObject next : parser.getObjects()) { COSObjectKey stmObjKey = new COSObjectKey(next); if (refObjNrs.contains(stmObjKey.getNumber())) { COSObject stmObj = document.getObjectFromPool(stmObjKey); stmObj.setObject(next.getObject()); } } } } } return pdfObject.getObject(); } // ------------------------------------------------------------------------ /** * * @param dict the dictionary to be decrypted * @param objNr the object number * @param objGenNr the object generation number * @throws IOException ff something went wrong */ protected final void decryptDictionary(COSDictionary dict, long objNr, long objGenNr) throws IOException { if (dict.getItem(COSName.CF) != null) { // PDFBOX-2936: avoid orphan /CF dictionaries found in US govt "I-" files return; } COSBase type = dict.getDictionaryObject(COSName.TYPE); boolean isSignature = COSName.SIG.equals(type) || COSName.DOC_TIME_STAMP.equals(type); for (Entry entry : dict.entrySet()) { if (isSignature && COSName.CONTENTS.equals(entry.getKey())) { // do not decrypt the signature contents string continue; } if (entry.getValue() instanceof COSString) { decryptString((COSString) entry.getValue(), objNr, objGenNr); } else if (entry.getValue() instanceof COSArray) { try { securityHandler.decryptArray((COSArray) entry.getValue(), objNr, objGenNr); } catch (CryptographyException ce) { throw new IOException("Error decrypting stream object " + objNr + ": " + ce.getMessage() /* , ce // TODO: remove remark with Java 1.6 */); } } else if (entry.getValue() instanceof COSDictionary) { decryptDictionary((COSDictionary) entry.getValue(), objNr, objGenNr); } } } /** * Decrypts given COSString. * * @param str the string to be decrypted * @param objNr the object number * @param objGenNr the object generation number * @throws IOException ff something went wrong */ protected final void decryptString(COSString str, long objNr, long objGenNr) throws IOException { try { securityHandler.decryptString(str, objNr, objGenNr); } catch (CryptographyException ce) { throw new IOException("Error decrypting string: " + ce.getMessage() /* , ce // TODO: remove remark with Java 1.6 */); } } /** * Decrypts given object. * * @param pb the object to be decrypted * @param objNr the object number * @param objGenNr the object generation number * @throws IOException ff something went wrong */ protected final void decrypt(COSBase pb, int objNr, int objGenNr) throws IOException { if (pb instanceof COSString) { decryptString((COSString) pb, objNr, objGenNr); } else if (pb instanceof COSDictionary) { decryptDictionary((COSDictionary) pb, objNr, objGenNr); } else if (pb instanceof COSArray) { final COSArray array = (COSArray) pb; for (int aIdx = 0, len = array.size(); aIdx < len; aIdx++) { decrypt(array.get(aIdx), objNr, objGenNr); } } } /** Returns length value referred to or defined in given object. */ private COSNumber getLength(final COSBase lengthBaseObj, final COSBase streamType) throws IOException { if (lengthBaseObj == null) { return null; } COSNumber retVal = null; // ---- maybe length was given directly if (lengthBaseObj instanceof COSNumber) { retVal = (COSNumber) lengthBaseObj; } // ---- length in referenced object else if (lengthBaseObj instanceof COSObject) { COSObject lengthObj = (COSObject) lengthBaseObj; if (lengthObj.getObject() == null) { // not read so far // keep current stream position final long curFileOffset = getPdfSourceOffset(); releasePdfSourceInputStream(); boolean isObjectStream = COSName.OBJ_STM.equals(streamType); parseObjectDynamically(lengthObj, isObjectStream); // reset current stream position setPdfSource(curFileOffset); if (lengthObj.getObject() == null) { throw new IOException("Length object content was not read."); } } if (!(lengthObj.getObject() instanceof COSNumber)) { throw new IOException("Wrong type of referenced length object " + lengthObj + ": " + lengthObj.getObject().getClass().getSimpleName()); } retVal = (COSNumber) lengthObj.getObject(); } else { throw new IOException("Wrong type of length object: " + lengthBaseObj.getClass().getSimpleName()); } return retVal; } // ------------------------------------------------------------------------ private final int streamCopyBufLen = 8192; private final byte[] streamCopyBuf = new byte[streamCopyBufLen]; /** * This will read a COSStream from the input stream using length attribute * within dictionary. If length attribute is a indirect reference it is * first resolved to get the stream length. This means we copy stream data * without testing for 'endstream' or 'endobj' and thus it is no problem if * these keywords occur within stream. We require 'endstream' to be found * after stream data is read. * * @param dic dictionary that goes with this stream. * @param file file to write the stream to when reading. * * @return parsed pdf stream. * * @throws IOException if an error occurred reading the stream, like * problems with reading length attribute, stream does not end * with 'endstream' after data read, stream too short etc. */ @Override protected COSStream parseCOSStream(COSDictionary dic, RandomAccess file) throws IOException { final COSStream stream = new COSStream(dic, file); OutputStream out = null; try { readString(); // read 'stream'; this was already tested in // parseObjectsDynamically() // ---- skip whitespaces before start of data // PDF Ref 1.7, chap. 3.2.7: // 'stream' should be followed by either a CRLF (0x0d 0x0a) or LF // but nothing else. int whitespace = pdfSource.read(); // see brother_scan_cover.pdf, it adds whitespaces // after the stream but before the start of the // data, so just read those first while (whitespace == 0x20) { whitespace = pdfSource.read(); } if (whitespace == 0x0D) { whitespace = pdfSource.read(); if (whitespace != 0x0A) { // the spec says this is invalid but it happens in the // real world so we must support it pdfSource.unread(whitespace); } } else if (whitespace != 0x0A) { // no whitespace after 'stream'; PDF ref. says 'should' so // that is ok pdfSource.unread(whitespace); } /* * This needs to be dic.getItem because when we are parsing, the underlying object might still be null. */ COSNumber streamLengthObj = getLength(dic.getItem(COSName.LENGTH), dic.getItem(COSName.TYPE)); if (streamLengthObj == null) { if (isLenient) { LOG.warn("The stream doesn't provide any stream length, using fallback readUntilEnd"); } else { throw new IOException("Missing length for stream."); } } boolean useReadUntilEnd = false; // ---- get output stream to copy data to if (streamLengthObj != null && validateStreamLength(streamLengthObj.longValue())) { out = stream.createFilteredStream(streamLengthObj); long remainBytes = streamLengthObj.longValue(); int bytesRead = 0; while (remainBytes > 0) { final int readBytes = pdfSource.read(streamCopyBuf, 0, (remainBytes > streamCopyBufLen) ? streamCopyBufLen : (int) remainBytes); if (readBytes <= 0) { useReadUntilEnd = true; out.close(); pdfSource.unread(bytesRead); break; } out.write(streamCopyBuf, 0, readBytes); remainBytes -= readBytes; bytesRead += readBytes; } } else { useReadUntilEnd = true; } if (useReadUntilEnd) { out = stream.createFilteredStream(); readUntilEndStream(new EndstreamOutputStream(out)); } String endStream = readString(); if (endStream.equals("endobj") && isLenient) { LOG.warn("stream ends with 'endobj' instead of 'endstream' at offset " + pdfSource.getOffset()); // avoid follow-up warning about missing endobj pdfSource.unread("endobj".getBytes("ISO-8859-1")); } else if (endStream.length() > 9 && isLenient && endStream.substring(0,9).equals("endstream")) { LOG.warn("stream ends with '" + endStream + "' instead of 'endstream' at offset " + pdfSource.getOffset()); // unread the "extra" bytes pdfSource.unread(endStream.substring(9).getBytes("ISO-8859-1")); } else if (!endStream.equals("endstream")) { throw new IOException( "Error reading stream, expected='endstream' actual='" + endStream + "' at offset " + pdfSource.getOffset()); } } finally { if (out != null) { out.close(); } } return stream; } private boolean validateStreamLength(long streamLength) throws IOException { boolean streamLengthIsValid = true; long originOffset = pdfSource.getOffset(); long expectedEndOfStream = originOffset + streamLength; if (expectedEndOfStream > fileLen) { streamLengthIsValid = false; LOG.error("The end of the stream is out of range, using workaround to read the stream"); LOG.error("Stream start offset: " + originOffset); LOG.error("Expected endofstream offset: " + expectedEndOfStream); } else { pdfSource.seek(expectedEndOfStream); skipSpaces(); if (!checkBytesAtOffset("endstream".getBytes("ISO-8859-1"))) { streamLengthIsValid = false; LOG.error("The end of the stream doesn't point to the correct offset, using workaround to read the stream"); LOG.error("Stream start offset: " + originOffset); LOG.error("Expected endofstream offset: " + expectedEndOfStream); } pdfSource.seek(originOffset); } return streamLengthIsValid; } /** * Check if the cross reference table/stream can be found at the current offset. * * @param startXRefOffset * @return the revised offset * @throws IOException */ private long checkXRefOffset(long startXRefOffset) throws IOException { // repair mode isn't available in non-lenient mode if (!isLenient) { return startXRefOffset; } setPdfSource(startXRefOffset-1); // save th previous character int previous = pdfSource.read(); if (pdfSource.peek() == X && checkBytesAtOffset(XREF_TABLE)) { return startXRefOffset; } // the previous character has to be a whitespace if (isWhitespace(previous)) { int nextValue = pdfSource.peek(); // maybe there isn't a xref table but a xref stream // is the next character a digit? if (nextValue > 47 && nextValue < 58) { try { // Maybe it's a XRef stream readObjectNumber(); readGenerationNumber(); readPattern(OBJ_MARKER); setPdfSource(startXRefOffset); return startXRefOffset; } catch (IOException exception) { // there wasn't an object of a xref stream // try to repair the offset pdfSource.seek(startXRefOffset); } } } // try to find a fixed offset return calculateXRefFixedOffset(startXRefOffset); } /** * Check if the given bytes can be found at the current offset. * * @param string the bytes to look for * @return true if the bytes are in place, false if not * @throws IOException if something went wrong */ private boolean checkBytesAtOffset(byte[] string) throws IOException { boolean bytesMatching = false; if (pdfSource.peek() == string[0]) { int length = string.length; byte[] bytesRead = new byte[length]; int numberOfBytes = pdfSource.read(bytesRead, 0, length); while (numberOfBytes < length) { int readMore = pdfSource.read(bytesRead, numberOfBytes, length - numberOfBytes); if (readMore < 0) { break; } numberOfBytes += readMore; } if (Arrays.equals(string, bytesRead)) { bytesMatching = true; } pdfSource.unread(bytesRead, 0, numberOfBytes); } return bytesMatching; } /** * Try to find a fixed offset for the given xref table/stream. * * @param objectOffset the given offset where to look at * @return the fixed offset * * @throws IOException if something went wrong */ private long calculateXRefFixedOffset(long objectOffset) throws IOException { if (objectOffset < 0) { LOG.error("Invalid object offset " + objectOffset + " when searching for a xref table/stream"); return 0; } // start a brute force search for all xref tables and try to find the offset we are looking for long newOffset = bfSearchForXRef(objectOffset); if (newOffset > -1) { LOG.debug("Fixed reference for xref table/stream " + objectOffset + " -> " + newOffset); return newOffset; } LOG.error("Can't find the object axref table/stream at offset " + objectOffset); return 0; } /** * Check the XRef table by dereferencing all objects and fixing * the offset if necessary. * * @throws IOException if something went wrong. */ private void checkXrefOffsets() throws IOException { // repair mode isn't available in non-lenient mode if (!isLenient) { return; } Map xrefOffset = xrefTrailerResolver.getXrefTable(); if (xrefOffset != null) { for (COSObjectKey objectKey : xrefOffset.keySet()) { Long objectOffset = xrefOffset.get(objectKey); // a negative offset number represents a object number itself // see type 2 entry in xref stream if (objectOffset != null && objectOffset >= 0) { long objectNr = objectKey.getNumber(); long objectGen = objectKey.getGeneration(); String objectString = createObjectString(objectNr, objectGen); if (!checkObjectId(objectString, objectOffset)) { long newOffset = bfSearchForObject(objectString); if (newOffset > -1) { xrefOffset.put(objectKey, newOffset); LOG.debug("Fixed reference for object " + objectNr + " " + objectGen + " " + objectOffset + " -> " + newOffset); } else { LOG.error("Can't find the object " + objectNr + " " + objectGen + " (origin offset " + objectOffset + ")"); } } } } } } /** * Check if the given string can be found at the given offset. * * @param objectString the string we are looking for * @param offset the given where to look * @return returns true if the given string can be found at the givwen offset * @throws IOException if something went wrong */ private boolean checkObjectId(String objectString, long offset) throws IOException { boolean objectFound = false; long originOffset = pdfSource.getOffset(); pdfSource.seek(offset); objectFound = checkBytesAtOffset(objectString.getBytes("ISO-8859-1")); pdfSource.seek(originOffset); return objectFound; } /** * Create a string for the given object id. * * @param objectID the object id * @param genID the generation id * @return the generated string */ private String createObjectString(long objectID, long genID) { return Long.toString(objectID) + " " + Long.toString(genID) + " obj"; } /** * Search for the offset of the given object among the objects found by a brute force search. * * @param objectString the object we are looking for * @return the offset of the object * @throws IOException if something went wrong */ private long bfSearchForObject(String objectString) throws IOException { long newOffset = -1; bfSearchForObjects(); if (bfSearchObjectOffsets.containsKey(objectString)) { newOffset = bfSearchObjectOffsets.get(objectString); } return newOffset; } /** * Brute force search for every object in the pdf. * * @throws IOException if something went wrong */ private void bfSearchForObjects() throws IOException { if (bfSearchObjectOffsets == null) { bfSearchObjectOffsets = new HashMap(); bfSearchCOSObjectKeyOffsets = new HashMap(); long originOffset = pdfSource.getOffset(); long currentOffset = MINIMUM_SEARCH_OFFSET; String objString = " obj"; byte[] string = objString.getBytes("ISO-8859-1"); do { pdfSource.seek(currentOffset); if (checkBytesAtOffset(string)) { long tempOffset = currentOffset - 1; pdfSource.seek(tempOffset); int genID = pdfSource.peek(); // is the next char a digit? if (genID > 47 && genID < 58) { genID -= 48; tempOffset--; pdfSource.seek(tempOffset); if (pdfSource.peek() == 32) { while (tempOffset > MINIMUM_SEARCH_OFFSET && pdfSource.peek() == 32) { pdfSource.seek(--tempOffset); } int length = 0; while (tempOffset > MINIMUM_SEARCH_OFFSET && pdfSource.peek() > 47 && pdfSource.peek() < 58) { pdfSource.seek(--tempOffset); length++; } if (length > 0) { pdfSource.read(); byte[] objIDBytes = pdfSource.readFully(length); String objIdString = new String(objIDBytes, 0, objIDBytes.length, "ISO-8859-1"); Long objectID = null; try { objectID = Long.valueOf(objIdString); } catch (NumberFormatException excpetion) { objectID = null; } if (objectID != null) { bfSearchObjectOffsets.put( createObjectString(objectID, genID), ++tempOffset); bfSearchCOSObjectKeyOffsets.put(new COSObjectKey(objectID, genID), tempOffset); } } } } } currentOffset++; } while (!pdfSource.isEOF()); // reestablish origin position pdfSource.seek(originOffset); } } /** * Search for the offset of the given xref table/stream among those found by a brute force search. * * @return the offset of the xref entry * @throws IOException if something went wrong */ private long bfSearchForXRef(long xrefOffset) throws IOException { long newOffset = -1; bfSearchForXRefs(); if (bfSearchXRefOffsets != null) { long currentDifference = -1; int currentOffsetIndex = -1; int numberOfOffsets = bfSearchXRefOffsets.size(); // find the most likely value // TODO to be optimized, this won't work in every case for (int i = 0; i < numberOfOffsets; i++) { long newDifference = xrefOffset - bfSearchXRefOffsets.get(i); // find the nearest offset if (currentDifference == -1 || (Math.abs(currentDifference) > Math.abs(newDifference))) { currentDifference = newDifference; currentOffsetIndex = i; } } if (currentOffsetIndex > -1) { newOffset = bfSearchXRefOffsets.remove(currentOffsetIndex); } } return newOffset; } /** * Brute force search for all xref entries. * * @throws IOException if something went wrong */ private void bfSearchForXRefs() throws IOException { if (bfSearchXRefOffsets == null) { // a pdf may contain more than one xref entry bfSearchXRefOffsets = new Vector(); long originOffset = pdfSource.getOffset(); pdfSource.seek(MINIMUM_SEARCH_OFFSET); // search for xref tables while (!pdfSource.isEOF()) { if (checkBytesAtOffset(XREF_TABLE)) { long newOffset = pdfSource.getOffset(); pdfSource.seek(newOffset - 1); // ensure that we don't read "startxref" instead of "xref" if (isWhitespace()) { bfSearchXRefOffsets.add(newOffset); } pdfSource.seek(newOffset + 4); } pdfSource.read(); } pdfSource.seek(MINIMUM_SEARCH_OFFSET); // search for XRef streams String objString = " obj"; byte[] string = objString.getBytes("ISO-8859-1"); while (!pdfSource.isEOF()) { if (checkBytesAtOffset(XREF_STREAM)) { // search backwards for the beginning of the stream long newOffset = -1; long xrefOffset = pdfSource.getOffset(); long currentOffset = xrefOffset; boolean objFound = false; for (int i = 1; i < 30 && !objFound; i++) { currentOffset = xrefOffset - (i * 10); if (currentOffset > 0) { pdfSource.seek(currentOffset); for (int j = 0; j < 10; j++) { if (checkBytesAtOffset(string)) { long tempOffset = currentOffset - 1; pdfSource.seek(tempOffset); int genID = pdfSource.peek(); // is the next char a digit? if (genID > 47 && genID < 58) { genID -= 48; tempOffset--; pdfSource.seek(tempOffset); if (pdfSource.peek() == 32) { int length = 0; pdfSource.seek(--tempOffset); while (tempOffset > MINIMUM_SEARCH_OFFSET && pdfSource.peek() > 47 && pdfSource.peek() < 58) { pdfSource.seek(--tempOffset); length++; } if (length > 0) { pdfSource.read(); newOffset = pdfSource.getOffset(); } } } LOG.debug("Fixed reference for xref stream " + xrefOffset + " -> " + newOffset); objFound = true; break; } else { currentOffset++; pdfSource.read(); } } } } if (newOffset > -1) { bfSearchXRefOffsets.add(newOffset); } pdfSource.seek(xrefOffset + 5); } pdfSource.read(); } pdfSource.seek(originOffset); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFObjectStreamParser.java0000644000000000000000000001171712645757432027742 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; /** * This will parse a PDF 1.5 object stream and extract all of the objects from the stream. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class PDFObjectStreamParser extends BaseParser { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFObjectStreamParser.class); private List streamObjects = null; private List objectNumbers = null; private COSStream stream; /** * Constructor. * * @since Apache PDFBox 1.3.0 * @param strm The stream to parse. * @param doc The document for the current parsing. * @param forceParsing flag to skip malformed or otherwise unparseable * input where possible * @throws IOException If there is an error initializing the stream. */ public PDFObjectStreamParser( COSStream strm, COSDocument doc, boolean forceParsing) throws IOException { super(strm.getUnfilteredStream(), forceParsing); setDocument( doc ); stream = strm; } /** * Constructor. * * @param strm The stream to parse. * @param doc The document for the current parsing. * * @throws IOException If there is an error initializing the stream. */ public PDFObjectStreamParser(COSStream strm, COSDocument doc) throws IOException { this(strm, doc, FORCE_PARSING); } /** * This will parse the tokens in the stream. This will close the * stream when it is finished parsing. * * @throws IOException If there is an error while parsing the stream. */ public void parse() throws IOException { try { //need to first parse the header. int numberOfObjects = stream.getInt( "N" ); objectNumbers = new ArrayList( numberOfObjects ); streamObjects = new ArrayList( numberOfObjects ); for( int i=0; i= objectNumbers.size()) { LOG.error("/ObjStm (object stream) has more objects than /N " + numberOfObjects); break; } COSInteger objNum = COSInteger.get( objectNumbers.get( objectCounter).intValue() ); object.setObjectNumber( objNum ); streamObjects.add( object ); if(LOG.isDebugEnabled()) { LOG.debug( "parsed=" + object ); } // According to the spec objects within an object stream shall not be enclosed // by obj/endobj tags, but there are some pdfs in the wild using those tags // skip endobject marker if present if (!pdfSource.isEOF() && pdfSource.peek() == 'e') { readLine(); } objectCounter++; } } finally { pdfSource.close(); } } /** * This will get the objects that were parsed from the stream. * * @return All of the objects in the stream. */ public List getObjects() { return streamObjects; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/VisualSignatureParser.java0000644000000000000000000002577512645757432030164 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.IOException; import java.io.InputStream; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.pdfwriter.COSWriter; import org.apache.pdfbox.persistence.util.COSObjectKey; public class VisualSignatureParser extends BaseParser { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFParser.class); /** * Constructor. * * @param input the inputstream to be read. * * @throws IOException If something went wrong */ public VisualSignatureParser(InputStream input) throws IOException { super(input); } /** * This will parse the tokens making up the visual signature. * * @throws IOException If there is an error while parsing the visual signature. */ public void parse() throws IOException { document = new COSDocument(); skipToNextObj(); boolean wasLastParsedObjectEOF = false; try { while(!wasLastParsedObjectEOF) { if(pdfSource.isEOF()) { break; } try { wasLastParsedObjectEOF = parseObject(); } catch(IOException e) { /* * Warning is sent to the PDFBox.log and to the Console that * we skipped over an object */ LOG.warn("Parsing Error, Skipping Object", e); skipToNextObj(); } skipSpaces(); } } catch(IOException e) { /* * PDF files may have random data after the EOF marker. Ignore errors if * last object processed is EOF. */ if(!wasLastParsedObjectEOF) { throw e; } } } private void skipToNextObj() throws IOException { byte[] b = new byte[16]; Pattern p = Pattern.compile("\\d+\\s+\\d+\\s+obj.*", Pattern.DOTALL); /* Read a buffer of data each time to see if it starts with a * known keyword. This is not the most efficient design, but we should * rarely be needing this function. We could update this to use the * circular buffer, like in readUntilEndStream(). */ while(!pdfSource.isEOF()) { int l = pdfSource.read(b); if(l < 1) { break; } String s = new String(b, "US-ASCII"); if(s.startsWith("trailer") || s.startsWith("xref") || s.startsWith("startxref") || s.startsWith("stream") || p.matcher(s).matches()) { pdfSource.unread(b); break; } else { pdfSource.unread(b, 1, l - 1); } } } private boolean parseObject() throws IOException { boolean isEndOfFile = false; skipSpaces(); //peek at the next character to determine the type of object we are parsing char peekedChar = (char) pdfSource.peek(); //ignore endobj and endstream sections. while(peekedChar == 'e') { //there are times when there are multiple endobj, so lets //just read them and move on. readString(); skipSpaces(); peekedChar = (char) pdfSource.peek(); } if(pdfSource.isEOF()) { // end of file we will return a false and call it a day. } else if(peekedChar == 'x') { //xref table. Note: The contents of the Xref table are currently ignored return true; } else if(peekedChar == 't' || peekedChar == 's') { // Note: startxref can occur in either a trailer section or by itself if(peekedChar == 't') { return true; } if(peekedChar == 's') { skipToNextObj(); //verify that EOF exists String eof = readExpectedString("%%EOF"); if(eof.indexOf("%%EOF") == -1 && !pdfSource.isEOF()) { throw new IOException("expected='%%EOF' actual='" + eof + "' next=" + readString() + " next=" + readString()); } isEndOfFile = true; } } else { //we are going to parse an normal object long number = -1; int genNum = -1; String objectKey = null; boolean missingObjectNumber = false; try { char peeked = (char) pdfSource.peek(); if(peeked == '<') { missingObjectNumber = true; } else { number = readObjectNumber(); } } catch(IOException e) { //ok for some reason "GNU Ghostscript 5.10" puts two endobj //statements after an object, of course this is nonsense //but because we want to support as many PDFs as possible //we will simply try again number = readObjectNumber(); } if(!missingObjectNumber) { skipSpaces(); genNum = readGenerationNumber(); objectKey = readString(3); //System.out.println( "parseObject() num=" + number + //" genNumber=" + genNum + " key='" + objectKey + "'" ); if(!objectKey.equals("obj")) { throw new IOException("expected='obj' actual='" + objectKey + "' " + pdfSource); } } else { number = -1; genNum = -1; } skipSpaces(); COSBase pb = parseDirObject(); String endObjectKey = readString(); if(endObjectKey.equals("stream")) { pdfSource.unread(endObjectKey.getBytes()); pdfSource.unread(' '); if(pb instanceof COSDictionary) { pb = parseCOSStream((COSDictionary) pb, getDocument().getScratchFile()); } else { // this is not legal // the combination of a dict and the stream/endstream forms a complete stream object throw new IOException("stream not preceded by dictionary"); } endObjectKey = readString(); } COSObjectKey key = new COSObjectKey(number, genNum); COSObject pdfObject = document.getObjectFromPool(key); pb.setNeedToBeUpdate(true); pdfObject.setObject(pb); if(!endObjectKey.equals("endobj")) { if(endObjectKey.startsWith("endobj")) { /* * Some PDF files don't contain a new line after endobj so we * need to make sure that the next object number is getting read separately * and not part of the endobj keyword. Ex. Some files would have "endobj28" * instead of "endobj" */ pdfSource.unread(endObjectKey.substring(6).getBytes()); } else if(!pdfSource.isEOF()) { try { //It is possible that the endobj is missing, there //are several PDFs out there that do that so skip it and move on. Float.parseFloat(endObjectKey); pdfSource.unread(COSWriter.SPACE); pdfSource.unread(endObjectKey.getBytes()); } catch(NumberFormatException e) { //we will try again incase there was some garbage which //some writers will leave behind. String secondEndObjectKey = readString(); if(!secondEndObjectKey.equals("endobj")) { if(isClosing()) { //found a case with 17506.pdf object 41 that was like this //41 0 obj [/Pattern /DeviceGray] ] endobj //notice the second array close, here we are reading it //and ignoring and attempting to continue pdfSource.read(); } skipSpaces(); String thirdPossibleEndObj = readString(); if(!thirdPossibleEndObj.equals("endobj")) { throw new IOException("expected='endobj' firstReadAttempt='" + endObjectKey + "' " + "secondReadAttempt='" + secondEndObjectKey + "' " + pdfSource); } } } } } skipSpaces(); } return isEndOfFile; } /** * Returns the underlying COSDocument. * * @return the COSDocument * * @throws IOException If something went wrong */ public COSDocument getDocument() throws IOException { if(document == null) { throw new IOException("You must call parse() before calling getDocument()"); } return document; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java0000644000000000000000000016575712645757432025716 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNull; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.exceptions.WrappedIOException; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.io.PushBackInputStream; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * This class is used to contain parsing logic that will be used by both the * PDFParser and the COSStreamParser. * * @author Ben Litchfield * @version $Revision$ */ public abstract class BaseParser { private static final long OBJECT_NUMBER_THRESHOLD = 10000000000L; private static final long GENERATION_NUMBER_THRESHOLD = 65535; static final int MAX_LENGTH_LONG = Long.toString(Long.MAX_VALUE).length(); /** * system property allowing to define size of push back buffer. */ public static final String PROP_PUSHBACK_SIZE = "org.apache.pdfbox.baseParser.pushBackSize"; /** * Log instance. */ private static final Log LOG = LogFactory.getLog(BaseParser.class); private static final int E = 'e'; private static final int N = 'n'; private static final int D = 'd'; private static final int S = 's'; private static final int T = 't'; private static final int R = 'r'; private static final int A = 'a'; private static final int M = 'm'; private static final int O = 'o'; private static final int B = 'b'; private static final int J = 'j'; private final int strmBufLen = 2048; private final byte[] strmBuf = new byte[ strmBufLen ]; /** * This is a byte array that will be used for comparisons. */ public static final byte[] ENDSTREAM = new byte[] { E, N, D, S, T, R, E, A, M }; /** * This is a byte array that will be used for comparisons. */ public static final byte[] ENDOBJ = new byte[] { E, N, D, O, B, J }; /** * This is a string constant that will be used for comparisons. */ public static final String DEF = "def"; /** * This is a string constant that will be used for comparisons. */ private static final String ENDOBJ_STRING = "endobj"; /** * This is a string constant that will be used for comparisons. */ private static final String ENDSTREAM_STRING = "endstream"; /** * This is a string constant that will be used for comparisons. */ private static final String STREAM_STRING = "stream"; /** * This is a string constant that will be used for comparisons. */ private static final String TRUE = "true"; /** * This is a string constant that will be used for comparisons. */ private static final String FALSE = "false"; /** * This is a string constant that will be used for comparisons. */ private static final String NULL = "null"; /** * Default value of the {@link #forceParsing} flag. */ static boolean FORCE_PARSING = true; static { // get preferences value for force parsing try { FORCE_PARSING = Boolean.getBoolean("org.apache.pdfbox.forceParsing"); } catch (SecurityException e) { // PDFBOX-1946 since Boolean.getBoolean calls System.getProperty, this can occur /* ignore and use default */ } } /** * This is the stream that will be read from. */ protected PushBackInputStream pdfSource; /** * This is the document that will be parsed. */ protected COSDocument document; /** * Flag to skip malformed or otherwise unparseable input where possible. */ protected final boolean forceParsing; /** * Default constructor. */ public BaseParser() { forceParsing = FORCE_PARSING; } /** * Constructor. * * @since Apache PDFBox 1.3.0 * @param input The input stream to read the data from. * @param forceParsingValue flag to skip malformed or otherwise unparseable * input where possible * @throws IOException If there is an error reading the input stream. */ public BaseParser(InputStream input, boolean forceParsingValue) throws IOException { int pushbacksize = 65536; try { pushbacksize = Integer.getInteger( PROP_PUSHBACK_SIZE, 65536 ); } catch (SecurityException e) // getInteger calls System.getProperties, which can get exception { // ignore and use default } pdfSource = new PushBackInputStream( new BufferedInputStream(input, 16384), pushbacksize ); forceParsing = forceParsingValue; } /** * Constructor. * * @param input The input stream to read the data from. * @throws IOException If there is an error reading the input stream. */ public BaseParser(InputStream input) throws IOException { this(input, FORCE_PARSING); } /** * Constructor. * * @param input The array to read the data from. * @throws IOException If there is an error reading the byte data. */ protected BaseParser(byte[] input) throws IOException { this(new ByteArrayInputStream(input)); } /** * Set the document for this stream. * * @param doc The current document. */ public void setDocument( COSDocument doc ) { document = doc; } private static boolean isHexDigit(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); // the line below can lead to problems with certain versions of the IBM JIT compiler // (and is slower anyway) //return (HEXDIGITS.indexOf(ch) != -1); } /** * This will parse a PDF dictionary value. * * @return The parsed Dictionary object. * * @throws IOException If there is an error parsing the dictionary object. */ private COSBase parseCOSDictionaryValue() throws IOException { COSBase retval = null; long numOffset = pdfSource.getOffset(); COSBase number = parseDirObject(); skipSpaces(); char next = (char)pdfSource.peek(); if( next >= '0' && next <= '9' ) { long genOffset = pdfSource.getOffset(); COSBase generationNumber = parseDirObject(); skipSpaces(); char r = (char)pdfSource.read(); if( r != 'R' ) { throw new IOException("expected='R' actual='" + r + "' at offset " + pdfSource.getOffset()); } if (!(number instanceof COSInteger)) { throw new IOException("expected number, actual=" + number + " at offset " + numOffset); } if (!(generationNumber instanceof COSInteger)) { throw new IOException("expected number, actual=" + number + " at offset " + genOffset); } COSObjectKey key = new COSObjectKey(((COSInteger) number).intValue(), ((COSInteger) generationNumber).intValue()); retval = document.getObjectFromPool(key); } else { retval = number; } return retval; } /** * This will parse a PDF dictionary. * * @return The parsed dictionary. * * @throws IOException IF there is an error reading the stream. */ protected COSDictionary parseCOSDictionary() throws IOException { char c = (char)pdfSource.read(); if( c != '<') { throw new IOException( "expected='<' actual='" + c + "' at offset " + pdfSource.getOffset()); } c = (char)pdfSource.read(); if( c != '<') { throw new IOException( "expected='<' actual='" + c + "' at offset " + pdfSource.getOffset()); } skipSpaces(); COSDictionary obj = new COSDictionary(); boolean done = false; while( !done ) { skipSpaces(); c = (char)pdfSource.peek(); if( c == '>') { done = true; } else if(c != '/') { //an invalid dictionary, we are expecting //the key, read until we can recover LOG.warn("Invalid dictionary, found: '" + c + "' but expected: '/'"); int read = pdfSource.read(); while(read != -1 && read != '/' && read != '>') { // in addition to stopping when we find / or >, we also want // to stop when we find endstream or endobj. if(read==E) { read = pdfSource.read(); if(read==N) { read = pdfSource.read(); if(read==D) { read = pdfSource.read(); boolean isStream = read == S && pdfSource.read() == T && pdfSource.read() == R && pdfSource.read() == E && pdfSource.read() == A && pdfSource.read() == M; boolean isObj = !isStream && read == O && pdfSource.read() == B && pdfSource.read() == J; if (isStream || isObj) { return obj; // we're done reading this object! } } } } read = pdfSource.read(); } if(read != -1) { pdfSource.unread(read); } else { return obj; } } else { COSName key = parseCOSName(); COSBase value = parseCOSDictionaryValue(); skipSpaces(); if( ((char)pdfSource.peek()) == 'd' ) { //if the next string is 'def' then we are parsing a cmap stream //and want to ignore it, otherwise throw an exception. String potentialDEF = readString(); if( !potentialDEF.equals( DEF ) ) { pdfSource.unread( potentialDEF.getBytes("ISO-8859-1") ); } else { skipSpaces(); } } if( value == null ) { LOG.warn("Bad Dictionary Declaration " + pdfSource ); } else { value.setDirect(true); obj.setItem( key, value ); } } } char ch = (char)pdfSource.read(); if( ch != '>' ) { throw new IOException( "expected='>' actual='" + ch + "' at offset " + pdfSource.getOffset()); } ch = (char)pdfSource.read(); if( ch != '>' ) { throw new IOException( "expected='>' actual='" + ch + "' at offset " + pdfSource.getOffset()); } return obj; } /** * This will read a COSStream from the input stream. * * @param file The file to write the stream to when reading. * @param dic The dictionary that goes with this stream. * * @return The parsed pdf stream. * * @throws IOException If there is an error reading the stream. */ protected COSStream parseCOSStream( COSDictionary dic, RandomAccess file ) throws IOException { COSStream stream = new COSStream( dic, file ); OutputStream out = null; try { String streamString = readString(); //long streamLength; if (!streamString.equals(STREAM_STRING)) { throw new IOException("expected='stream' actual='" + streamString + "' at offset " + pdfSource.getOffset()); } //PDF Ref 3.2.7 A stream must be followed by either //a CRLF or LF but nothing else. int whitespace = pdfSource.read(); //see brother_scan_cover.pdf, it adds whitespaces //after the stream but before the start of the //data, so just read those first while (whitespace == 0x20) { whitespace = pdfSource.read(); } if( whitespace == 0x0D ) { whitespace = pdfSource.read(); if( whitespace != 0x0A ) { pdfSource.unread( whitespace ); //The spec says this is invalid but it happens in the real //world so we must support it. } } else if (whitespace == 0x0A) { //that is fine } else { //we are in an error. //but again we will do a lenient parsing and just assume that everything //is fine pdfSource.unread( whitespace ); } /*This needs to be dic.getItem because when we are parsing, the underlying object * might still be null. */ COSBase streamLength = dic.getItem(COSName.LENGTH); //Need to keep track of the out = stream.createFilteredStream( streamLength ); // try to read stream length - even if it is an indirect object int length = -1; if ( streamLength instanceof COSNumber ) { length = ( (COSNumber) streamLength).intValue(); } // commented out next chunk since for the sequentially working PDFParser // we do not know if length object is redefined later on and the currently // read indirect object might be obsolete (e.g. not referenced in xref table); // this would result in reading wrong number of bytes; // Thus the only reliable information is a direct length. // This exclusion shouldn't harm much since in case of indirect objects they will // typically be defined after the stream object, thus keeping the directly // provided length will fix most cases // else if ( ( streamLength instanceof COSObject ) && // ( ( (COSObject) streamLength ).getObject() instanceof COSNumber ) ) // { // length = ( (COSNumber) ( (COSObject) streamLength ).getObject() ).intValue(); // } if ( length == -1 ) { // Couldn't determine length from dict: just // scan until we find endstream: readUntilEndStream(new EndstreamOutputStream(out)); } else { // Copy length bytes over: int left = length; while ( left > 0 ) { final int chunk = Math.min( left, strmBufLen ); final int readCount = pdfSource.read( strmBuf, 0, chunk ); if ( readCount == -1 ) { break; } out.write( strmBuf, 0, readCount ); left -= readCount; } // in order to handle broken documents we test if 'endstream' is reached // if not, length value possibly was wrong, fall back to scanning for endstream // fill buffer with next bytes and test for 'endstream' (with leading whitespaces) int readCount = pdfSource.read( strmBuf, 0, 20 ); if ( readCount > 0 ) { boolean foundEndstream = false; int nextEndstreamCIdx = 0; for ( int cIdx = 0; cIdx < readCount; cIdx++ ) { final int ch = strmBuf[ cIdx ] & 0xff; if ( ch == ENDSTREAM[ nextEndstreamCIdx ] ) { if ( ++nextEndstreamCIdx >= ENDSTREAM.length ) { foundEndstream = true; break; } } else if ( ( nextEndstreamCIdx > 0 ) || ( ! isWhitespace( ch ) ) ) { // not found break; } } // push back test bytes pdfSource.unread( strmBuf, 0, readCount ); // if 'endstream' was not found fall back to scanning if ( ! foundEndstream ) { LOG.warn("Specified stream length " + length + " is wrong. Fall back to reading stream until 'endstream'."); // push back all read stream bytes // we got a buffered stream wrapper around filteredStream thus first flush to underlying stream out.flush(); InputStream writtenStreamBytes = stream.getFilteredStream(); ByteArrayOutputStream bout = new ByteArrayOutputStream( length ); IOUtils.copy(writtenStreamBytes, bout); IOUtils.closeQuietly(writtenStreamBytes); try { pdfSource.unread( bout.toByteArray() ); } catch ( IOException ioe ) { throw new WrappedIOException( "Could not push back " + bout.size() + " bytes in order to reparse stream. " + "Try increasing push back buffer using system property " + PROP_PUSHBACK_SIZE, ioe ); } // close and create new filtered stream IOUtils.closeQuietly(out); out = stream.createFilteredStream( streamLength ); // scan until we find endstream: readUntilEndStream(new EndstreamOutputStream(out)); } } } skipSpaces(); String endStream = readString(); if (!endStream.equals(ENDSTREAM_STRING)) { /* * Sometimes stream objects don't have an endstream tag so readUntilEndStream(out) * also can stop on endobj tags. If that's the case we need to make sure to unread * the endobj so parseObject() can handle that case normally. */ if (endStream.startsWith(ENDOBJ_STRING)) { byte[] endobjarray = endStream.getBytes("ISO-8859-1"); pdfSource.unread(endobjarray); } /* * Some PDF files don't contain a new line after endstream so we * need to make sure that the next object number is getting read separately * and not part of the endstream keyword. Ex. Some files would have "endstream8" * instead of "endstream" */ else if(endStream.startsWith(ENDSTREAM_STRING)) { String extra = endStream.substring(9, endStream.length()); byte[] array = extra.getBytes("ISO-8859-1"); pdfSource.unread(array); } else { /* * If for some reason we get something else here, Read until we find the next * "endstream" */ readUntilEndStream(new EndstreamOutputStream(out)); endStream = readString(); if( !endStream.equals( ENDSTREAM_STRING ) ) { throw new IOException("expected='endstream' actual='" + endStream + "' at offset " + pdfSource.getOffset()); } } } } finally { if( out != null ) { out.close(); } } return stream; } /** * This method will read through the current stream object until * we find the keyword "endstream" meaning we're at the end of this * object. Some pdf files, however, forget to write some endstream tags * and just close off objects with an "endobj" tag so we have to handle * this case as well. * * This method is optimized using buffered IO and reduced number of * byte compare operations. * * @param out stream we write out to. * * @throws IOException */ protected void readUntilEndStream( final OutputStream out ) throws IOException { int bufSize; int charMatchCount = 0; byte[] keyw = ENDSTREAM; final int quickTestOffset = 5; // last character position of shortest keyword ('endobj') // read next chunk into buffer; already matched chars are added to beginning of buffer while ( ( bufSize = pdfSource.read( strmBuf, charMatchCount, strmBufLen - charMatchCount ) ) > 0 ) { bufSize += charMatchCount; int bIdx = charMatchCount; int quickTestIdx; // iterate over buffer, trying to find keyword match for ( int maxQuicktestIdx = bufSize - quickTestOffset; bIdx < bufSize; bIdx++ ) { // reduce compare operations by first test last character we would have to // match if current one matches; if it is not a character from keywords // we can move behind the test character; // this shortcut is inspired by the Boyer-Moore string search algorithm // and can reduce parsing time by approx. 20% if ( ( charMatchCount == 0 ) && ( ( quickTestIdx = bIdx + quickTestOffset ) < maxQuicktestIdx ) ) { final byte ch = strmBuf[quickTestIdx]; if ( ( ch > 't' ) || ( ch < 'a' ) ) { // last character we would have to match if current character would match // is not a character from keywords -> jump behind and start over bIdx = quickTestIdx; continue; } } final byte ch = strmBuf[bIdx]; // could be negative - but we only compare to ASCII if ( ch == keyw[ charMatchCount ] ) { if ( ++charMatchCount == keyw.length ) { // match found bIdx++; break; } } else { if ( ( charMatchCount == 3 ) && ( ch == ENDOBJ[ charMatchCount ] ) ) { // maybe ENDSTREAM is missing but we could have ENDOBJ keyw = ENDOBJ; charMatchCount++; } else { // no match; incrementing match start by 1 would be dumb since we already know matched chars // depending on current char read we may already have beginning of a new match: // 'e': first char matched; // 'n': if we are at match position idx 7 we already read 'e' thus 2 chars matched // for each other char we have to start matching first keyword char beginning with next // read position charMatchCount = ( ch == E ) ? 1 : ( ( ch == N ) && ( charMatchCount == 7 ) ) ? 2 : 0; // search again for 'endstream' keyw = ENDSTREAM; } } } // for int contentBytes = Math.max( 0, bIdx - charMatchCount ); // write buffer content until first matched char to output stream if ( contentBytes > 0 ) { out.write( strmBuf, 0, contentBytes ); } if ( charMatchCount == keyw.length ) { // keyword matched; unread matched keyword (endstream/endobj) and following buffered content pdfSource.unread( strmBuf, contentBytes, bufSize - contentBytes ); break; } else { // copy matched chars at start of buffer System.arraycopy( keyw, 0, strmBuf, 0, charMatchCount ); } } // while out.flush(); // this writes a lonely CR or drops trailing CR LF and LF } /** * This is really a bug in the Document creators code, but it caused a crash * in PDFBox, the first bug was in this format: * /Title ( (5) * /Creator which was patched in 1 place. * However it missed the case where the Close Paren was escaped * * The second bug was in this format * /Title (c:\) * /Producer * * This patch moves this code out of the parseCOSString method, so it can be used twice. * * * @param bracesParameter the number of braces currently open. * * @return the corrected value of the brace counter * @throws IOException */ private int checkForMissingCloseParen(final int bracesParameter) throws IOException { int braces = bracesParameter; byte[] nextThreeBytes = new byte[3]; int amountRead = pdfSource.read(nextThreeBytes); //lets handle the special case seen in Bull River Rules and Regulations.pdf //The dictionary looks like this // 2 0 obj // << // /Type /Info // /Creator (PaperPort http://www.scansoft.com) // /Producer (sspdflib 1.0 http://www.scansoft.com) // /Title ( (5) // /Author () // /Subject () // // Notice the /Title, the braces are not even but they should // be. So lets assume that if we encounter an this scenario // then that // means that there is an error in the pdf and assume that // was the end of the document. // if (amountRead == 3) { if (( nextThreeBytes[0] == 0x0d // Look for a carriage return && nextThreeBytes[1] == 0x0a // Look for a new line && nextThreeBytes[2] == 0x2f ) // Look for a slash / // Add a second case without a new line || (nextThreeBytes[0] == 0x0d // Look for a carriage return && nextThreeBytes[1] == 0x2f )) // Look for a slash / { braces = 0; } } if (amountRead > 0) { pdfSource.unread( nextThreeBytes, 0, amountRead ); } return braces; } /** * This will parse a PDF string. * * @param isDictionary indicates if the stream is a dictionary or not * @return The parsed PDF string. * * @throws IOException If there is an error reading from the stream. * @deprecated Not needed anymore. Use {@link #parseCOSString()} instead. PDFBOX-1437 */ @Deprecated protected COSString parseCOSString(boolean isDictionary) throws IOException { return parseCOSString(); } /** * This will parse a PDF string. * * @return The parsed PDF string. * * @throws IOException If there is an error reading from the stream. */ protected COSString parseCOSString() throws IOException { char nextChar = (char)pdfSource.read(); COSString retval = new COSString(); char openBrace; char closeBrace; if( nextChar == '(' ) { openBrace = '('; closeBrace = ')'; } else if( nextChar == '<' ) { return parseCOSHexString(); } else { throw new IOException( "parseCOSString string should start with '(' or '<' and not '" + nextChar + "' " + pdfSource ); } //This is the number of braces read // int braces = 1; int c = pdfSource.read(); while( braces > 0 && c != -1) { char ch = (char)c; int nextc = -2; // not yet read if(ch == closeBrace) { braces--; braces = checkForMissingCloseParen(braces); if( braces != 0 ) { retval.append( ch ); } } else if( ch == openBrace ) { braces++; retval.append( ch ); } else if( ch == '\\' ) { //patched by ram char next = (char)pdfSource.read(); switch(next) { case 'n': retval.append( '\n' ); break; case 'r': retval.append( '\r' ); break; case 't': retval.append( '\t' ); break; case 'b': retval.append( '\b' ); break; case 'f': retval.append( '\f' ); break; case ')': // PDFBox 276 /Title (c:\) braces = checkForMissingCloseParen(braces); if( braces != 0 ) { retval.append( next ); } else { retval.append('\\'); } break; case '(': case '\\': retval.append( next ); break; case 10: case 13: //this is a break in the line so ignore it and the newline and continue c = pdfSource.read(); while( isEOL(c) && c != -1) { c = pdfSource.read(); } nextc = c; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { StringBuffer octal = new StringBuffer(); octal.append( next ); c = pdfSource.read(); char digit = (char)c; if( digit >= '0' && digit <= '7' ) { octal.append( digit ); c = pdfSource.read(); digit = (char)c; if( digit >= '0' && digit <= '7' ) { octal.append( digit ); } else { nextc = c; } } else { nextc = c; } int character = 0; try { character = Integer.parseInt( octal.toString(), 8 ); } catch( NumberFormatException e ) { throw new IOException( "Error: Expected octal character, actual='" + octal + "'" ); } retval.append( character ); break; } default: { // dropping the backslash // see 7.3.4.2 Literal Strings for further information retval.append( next ); } } } else { retval.append( ch ); } if (nextc != -2) { c = nextc; } else { c = pdfSource.read(); } } if (c != -1) { pdfSource.unread(c); } return retval; } /** * This will parse a PDF HEX string with fail fast semantic * meaning that we stop if a not allowed character is found. * This is necessary in order to detect malformed input and * be able to skip to next object start. * * We assume starting '<' was already read. * * @return The parsed PDF string. * * @throws IOException If there is an error reading from the stream. */ private final COSString parseCOSHexString() throws IOException { final StringBuilder sBuf = new StringBuilder(); while( true ) { int c = pdfSource.read(); if ( isHexDigit((char)c) ) { sBuf.append( (char) c ); } else if ( c == '>' ) { break; } else if ( c < 0 ) { throw new IOException( "Missing closing bracket for hex string. Reached EOS." ); } else if ( ( c == ' ' ) || ( c == '\n' ) || ( c == '\t' ) || ( c == '\r' ) || ( c == '\b' ) || ( c == '\f' ) ) { continue; } else { // if invalid chars was found: discard last // hex character if it is not part of a pair if (sBuf.length()%2!=0) { sBuf.deleteCharAt(sBuf.length()-1); } // read till the closing bracket was found do { c = pdfSource.read(); } while ( c != '>' && c >= 0 ); // might have reached EOF while looking for the closing bracket // this can happen for malformed PDFs only. Make sure that there is // no endless loop. if ( c < 0 ) { throw new IOException( "Missing closing bracket for hex string. Reached EOS." ); } // exit loop break; } } return COSString.createFromHexString( sBuf.toString(), forceParsing ); } /** * This will parse a PDF array object. * * @return The parsed PDF array. * * @throws IOException If there is an error parsing the stream. */ protected COSArray parseCOSArray() throws IOException { char ch = (char)pdfSource.read(); if( ch != '[') { throw new IOException( "expected='[' actual='" + ch + "' at offset " + pdfSource.getOffset()); } COSArray po = new COSArray(); COSBase pbo; skipSpaces(); int i; while( ((i = pdfSource.peek()) > 0) && ((char)i != ']') ) { pbo = parseDirObject(); if( pbo instanceof COSObject ) { // We have to check if the expected values are there or not PDFBOX-385 if (po.get(po.size()-1) instanceof COSInteger) { COSInteger genNumber = (COSInteger)po.remove( po.size() -1 ); if (po.get(po.size()-1) instanceof COSInteger) { COSInteger number = (COSInteger)po.remove( po.size() -1 ); COSObjectKey key = new COSObjectKey(number.intValue(), genNumber.intValue()); pbo = document.getObjectFromPool(key); } else { // the object reference is somehow wrong pbo = null; } } else { pbo = null; } } if( pbo != null ) { po.add( pbo ); } else { //it could be a bad object in the array which is just skipped LOG.warn("Corrupt object reference" ); // This could also be an "endobj" or "endstream" which means we can assume that // the array has ended. String isThisTheEnd = readString(); pdfSource.unread(isThisTheEnd.getBytes("ISO-8859-1")); if(ENDOBJ_STRING.equals(isThisTheEnd) || ENDSTREAM_STRING.equals(isThisTheEnd)) { return po; } } skipSpaces(); } pdfSource.read(); //read ']' skipSpaces(); return po; } /** * Determine if a character terminates a PDF name. * * @param ch The character * @return true if the character terminates a PDF name, otherwise false. */ protected boolean isEndOfName(char ch) { return (ch == ' ' || ch == 13 || ch == 10 || ch == 9 || ch == '>' || ch == '<' || ch == '[' || ch =='/' || ch ==']' || ch ==')' || ch =='(' || ch == -1 //EOF ); } /** * This will parse a PDF name from the stream. * * @return The parsed PDF name. * * @throws IOException If there is an error reading from the stream. */ protected COSName parseCOSName() throws IOException { int c = pdfSource.read(); if( (char)c != '/') { throw new IOException("expected='/' actual='" + (char)c + "'-" + c + " at offset " + pdfSource.getOffset()); } // costruisce il nome StringBuilder buffer = new StringBuilder(); c = pdfSource.read(); while( c != -1 ) { char ch = (char)c; if(ch == '#') { char ch1 = (char)pdfSource.read(); char ch2 = (char)pdfSource.read(); // Prior to PDF v1.2, the # was not a special character. Also, // it has been observed that various PDF tools do not follow the // spec with respect to the # escape, even though they report // PDF versions of 1.2 or later. The solution here is that we // interpret the # as an escape only when it is followed by two // valid hex digits. // if (isHexDigit(ch1) && isHexDigit(ch2)) { String hex = "" + ch1 + ch2; try { buffer.append( (char) Integer.parseInt(hex, 16)); } catch (NumberFormatException e) { throw new IOException("Error: expected hex number, actual='" + hex + "'"); } c = pdfSource.read(); } else { pdfSource.unread(ch2); c = ch1; buffer.append( ch ); } } else if (isEndOfName(ch)) { break; } else { buffer.append( ch ); c = pdfSource.read(); } } if (c != -1) { pdfSource.unread(c); } return COSName.getPDFName( buffer.toString() ); } /** * This will parse a boolean object from the stream. * * @return The parsed boolean object. * * @throws IOException If an IO error occurs during parsing. */ protected COSBoolean parseBoolean() throws IOException { COSBoolean retval = null; char c = (char)pdfSource.peek(); if( c == 't' ) { String trueString = new String( pdfSource.readFully( 4 ), "ISO-8859-1" ); if( !trueString.equals( TRUE ) ) { throw new IOException( "Error parsing boolean: expected='true' actual='" + trueString + "' at offset " + pdfSource.getOffset()); } else { retval = COSBoolean.TRUE; } } else if( c == 'f' ) { String falseString = new String( pdfSource.readFully( 5 ), "ISO-8859-1" ); if( !falseString.equals( FALSE ) ) { throw new IOException( "Error parsing boolean: expected='true' actual='" + falseString + "' at offset " + pdfSource.getOffset()); } else { retval = COSBoolean.FALSE; } } else { throw new IOException( "Error parsing boolean expected='t or f' actual='" + c + "' at offset " + pdfSource.getOffset()); } return retval; } /** * This will parse a directory object from the stream. * * @return The parsed object. * * @throws IOException If there is an error during parsing. */ protected COSBase parseDirObject() throws IOException { COSBase retval = null; skipSpaces(); int nextByte = pdfSource.peek(); char c = (char)nextByte; switch(c) { case '<': { int leftBracket = pdfSource.read();//pull off first left bracket c = (char)pdfSource.peek(); //check for second left bracket pdfSource.unread( leftBracket ); if(c == '<') { retval = parseCOSDictionary(); skipSpaces(); } else { retval = parseCOSString(); } break; } case '[': // array { retval = parseCOSArray(); break; } case '(': retval = parseCOSString(); break; case '/': // name retval = parseCOSName(); break; case 'n': // null { String nullString = readString(); if( !nullString.equals( NULL) ) { throw new IOException("Expected='null' actual='" + nullString + "' at offset " + pdfSource.getOffset()); } retval = COSNull.NULL; break; } case 't': { String trueString = new String( pdfSource.readFully(4), "ISO-8859-1" ); if( trueString.equals( TRUE ) ) { retval = COSBoolean.TRUE; } else { throw new IOException( "expected true actual='" + trueString + "' " + pdfSource ); } break; } case 'f': { String falseString = new String( pdfSource.readFully(5), "ISO-8859-1" ); if( falseString.equals( FALSE ) ) { retval = COSBoolean.FALSE; } else { throw new IOException( "expected false actual='" + falseString + "' " + pdfSource ); } break; } case 'R': pdfSource.read(); retval = new COSObject(null); break; case (char)-1: return null; default: { if( Character.isDigit(c) || c == '-' || c == '+' || c == '.') { StringBuilder buf = new StringBuilder(); int ic = pdfSource.read(); c = (char)ic; while( Character.isDigit( c )|| c == '-' || c == '+' || c == '.' || c == 'E' || c == 'e' ) { buf.append( c ); ic = pdfSource.read(); c = (char)ic; } if( ic != -1 ) { pdfSource.unread( ic ); } retval = COSNumber.get( buf.toString() ); } else { //This is not suppose to happen, but we will allow for it //so we are more compatible with POS writers that don't //follow the spec String badString = readString(); //throw new IOException( "Unknown dir object c='" + c + //"' peek='" + (char)pdfSource.peek() + "' " + pdfSource ); if( badString == null || badString.length() == 0 ) { int peek = pdfSource.peek(); // we can end up in an infinite loop otherwise throw new IOException( "Unknown dir object c='" + c + "' cInt=" + (int)c + " peek='" + (char)peek + "' peekInt=" + peek + " " + pdfSource.getOffset() ); } // if it's an endstream/endobj, we want to put it back so the caller will see it if(ENDOBJ_STRING.equals(badString) || ENDSTREAM_STRING.equals(badString)) { pdfSource.unread(badString.getBytes("ISO-8859-1")); } } } } return retval; } /** * This will read the next string from the stream. * * @return The string that was read from the stream. * * @throws IOException If there is an error reading from the stream. */ protected String readString() throws IOException { skipSpaces(); StringBuilder buffer = new StringBuilder(); int c = pdfSource.read(); while( !isEndOfName((char)c) && !isClosing(c) && c != -1 ) { buffer.append( (char)c ); c = pdfSource.read(); } if (c != -1) { pdfSource.unread(c); } return buffer.toString(); } /** * This will read bytes until the end of line marker occurs. * * @param theString The next expected string in the stream. * * @return The characters between the current position and the end of the line. * * @throws IOException If there is an error reading from the stream or theString does not match what was read. */ protected String readExpectedString( String theString ) throws IOException { int c = pdfSource.read(); while( isWhitespace(c) && c != -1) { c = pdfSource.read(); } StringBuilder buffer = new StringBuilder( theString.length() ); int charsRead = 0; while( !isEOL(c) && c != -1 && charsRead < theString.length() ) { char next = (char)c; buffer.append( next ); if( theString.charAt( charsRead ) == next ) { charsRead++; } else { pdfSource.unread(buffer.toString().getBytes("ISO-8859-1")); throw new IOException( "Error: Expected to read '" + theString + "' instead started reading '" +buffer.toString() + "'" ); } c = pdfSource.read(); } while( isEOL(c) && c != -1 ) { c = pdfSource.read(); } if (c != -1) { pdfSource.unread(c); } return buffer.toString(); } /** * This will read the next string from the stream up to a certain length. * * @param length The length to stop reading at. * * @return The string that was read from the stream of length 0 to length. * * @throws IOException If there is an error reading from the stream. */ protected String readString( int length ) throws IOException { skipSpaces(); int c = pdfSource.read(); //average string size is around 2 and the normal string buffer size is //about 16 so lets save some space. StringBuilder buffer = new StringBuilder(length); while( !isWhitespace(c) && !isClosing(c) && c != -1 && buffer.length() < length && c != '[' && c != '<' && c != '(' && c != '/' ) { buffer.append( (char)c ); c = pdfSource.read(); } if (c != -1) { pdfSource.unread(c); } return buffer.toString(); } /** * This will tell if the next character is a closing brace( close of PDF array ). * * @return true if the next byte is ']', false otherwise. * * @throws IOException If an IO error occurs. */ protected boolean isClosing() throws IOException { return isClosing(pdfSource.peek()); } /** * This will tell if the next character is a closing brace( close of PDF array ). * * @param c The character to check against end of line * @return true if the next byte is ']', false otherwise. */ protected boolean isClosing(int c) { return c == ']'; } /** * This will read bytes until the first end of line marker occurs. * Note: if you later unread the results of this function, you'll * need to add a newline character to the end of the string. * * @return The characters between the current position and the end of the line. * * @throws IOException If there is an error reading from the stream. */ protected String readLine() throws IOException { if (pdfSource.isEOF()) { throw new IOException( "Error: End-of-File, expected line"); } StringBuilder buffer = new StringBuilder( 11 ); int c; while ((c = pdfSource.read()) != -1) { if (isEOL(c)) { break; } buffer.append( (char)c ); } return buffer.toString(); } /** * This will tell if the next byte to be read is an end of line byte. * * @return true if the next byte is 0x0A or 0x0D. * * @throws IOException If there is an error reading from the stream. */ protected boolean isEOL() throws IOException { return isEOL(pdfSource.peek()); } /** * This will tell if the next byte to be read is an end of line byte. * * @param c The character to check against end of line * @return true if the next byte is 0x0A or 0x0D. */ protected boolean isEOL(int c) { return c == 10 || c == 13; } /** * This will tell if the next byte is whitespace or not. * * @return true if the next byte in the stream is a whitespace character. * * @throws IOException If there is an error reading from the stream. */ protected boolean isWhitespace() throws IOException { return isWhitespace( pdfSource.peek() ); } /** * This will tell if the next byte is whitespace or not. These values are * specified in table 1 (page 12) of ISO 32000-1:2008. * @param c The character to check against whitespace * @return true if the next byte in the stream is a whitespace character. */ protected boolean isWhitespace( int c ) { return c == 0 || c == 9 || c == 12 || c == 10 || c == 13 || c == 32; } /** * This will skip all spaces and comments that are present. * * @throws IOException If there is an error reading from the stream. */ protected void skipSpaces() throws IOException { //log( "skipSpaces() " + pdfSource ); int c = pdfSource.read(); // identical to, but faster as: isWhiteSpace(c) || c == 37 while(c == 0 || c == 9 || c == 12 || c == 10 || c == 13 || c == 32 || c == 37)//37 is the % character, a comment { if ( c == 37 ) { // skip past the comment section c = pdfSource.read(); while(!isEOL(c) && c != -1) { c = pdfSource.read(); } } else { c = pdfSource.read(); } } if (c != -1) { pdfSource.unread(c); } //log( "skipSpaces() done peek='" + (char)pdfSource.peek() + "'" ); } /** * This will read a long from the Stream and throw an {@link IllegalArgumentException} if the long value * has more than 10 digits (i.e. : bigger than {@link #OBJECT_NUMBER_THRESHOLD}) * @return the object number being read. * @throws IOException if an I/O error occurs */ protected long readObjectNumber() throws IOException { long retval = readLong(); if(retval < 0 || retval >= OBJECT_NUMBER_THRESHOLD) { throw new IOException("Object Number '" + retval + "' has more than 10 digits or is negative"); } return retval; } /** * This will read a integer from the Stream and throw an {@link IllegalArgumentException} if the integer value * has more than the maximum object revision (i.e. : bigger than {@link #GENERATION_NUMBER_THRESHOLD}) * @return the generation number being read. * @throws IOException if an I/O error occurs */ protected int readGenerationNumber() throws IOException { int retval = readInt(); if(retval < 0 || retval > GENERATION_NUMBER_THRESHOLD) { throw new IOException("Generation Number '" + retval + "' has more than 5 digits"); } return retval; } /** * This will read an integer from the stream. * * @return The integer that was read from the stream. * * @throws IOException If there is an error reading from the stream. */ protected int readInt() throws IOException { skipSpaces(); int retval = 0; StringBuilder intBuffer = readStringNumber(); try { retval = Integer.parseInt( intBuffer.toString() ); } catch( NumberFormatException e ) { pdfSource.unread(intBuffer.toString().getBytes("ISO-8859-1")); throw new IOException( "Error: Expected an integer type at offset "+pdfSource.getOffset()); } return retval; } /** * This will read an long from the stream. * * @return The long that was read from the stream. * * @throws IOException If there is an error reading from the stream. */ protected long readLong() throws IOException { skipSpaces(); long retval = 0; StringBuilder longBuffer = readStringNumber(); try { retval = Long.parseLong( longBuffer.toString() ); } catch( NumberFormatException e ) { pdfSource.unread(longBuffer.toString().getBytes("ISO-8859-1")); throw new IOException( "Error: Expected a long type at offset " + pdfSource.getOffset() + ", instead got '" + longBuffer + "'"); } return retval; } /** * This method is used to read a token by the {@linkplain #readInt()} method * and the {@linkplain #readLong()} method. * * @return the token to parse as integer or long by the calling method. * @throws IOException throws by the {@link #pdfSource} methods. */ protected final StringBuilder readStringNumber() throws IOException { int lastByte = 0; StringBuilder buffer = new StringBuilder(); while( (lastByte = pdfSource.read() ) != 32 && lastByte != 10 && lastByte != 13 && lastByte != 60 && //see sourceforge bug 1714707 lastByte != '[' && // PDFBOX-1845 lastByte != '(' && // PDFBOX-2579 lastByte != 0 && //See sourceforge bug 853328 lastByte != -1 ) { buffer.append( (char)lastByte ); if (buffer.length() > MAX_LENGTH_LONG) { throw new IOException("Number '" + buffer + "' is getting too long, stop reading at offset " + pdfSource.getOffset()); } } if( lastByte != -1 ) { pdfSource.unread( lastByte ); } return buffer; } /** * Release all used resources. */ public void clearResources() { document = null; if (pdfSource != null) { IOUtils.closeQuietly(pdfSource); pdfSource = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/package.html0000644000000000000000000000175412645757432025267 0ustar rootroot The pdfparser package contains classes to parse PDF documents and objects within the document. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java0000644000000000000000000011531712645757432025440 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.exceptions.WrappedIOException; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.fdf.FDFDocument; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * This class will handle the parsing of the PDF document. * * @author Ben Litchfield * @version $Revision: 1.53 $ */ public class PDFParser extends BaseParser { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFParser.class); private static final int SPACE_BYTE = 32; private static final String PDF_HEADER = "%PDF-"; private static final String FDF_HEADER = "%FDF-"; protected boolean isFDFDocment = false; private static final String PDF_DEFAULT_VERSION = "1.4"; private static final String FDF_DEFAULT_VERSION = "1.0"; /** * A list of duplicate objects found when Parsing the PDF * File. */ private List conflictList = new ArrayList(); /** * A list of COSStream objects to check for length correctness */ private final HashSet streamLengthCheckSet = new HashSet(); /** Collects all Xref/trailer objects and resolves them into single * object using startxref reference. */ protected XrefTrailerResolver xrefTrailerResolver = new XrefTrailerResolver(); /** * Temp file directory. */ private File tempDirectory = null; private RandomAccess raf = null; /** * Constructor. * * @param input The input stream that contains the PDF document. * * @throws IOException If there is an error initializing the stream. */ public PDFParser( InputStream input ) throws IOException { this(input, null, FORCE_PARSING); } /** * Constructor to allow control over RandomAccessFile. * @param input The input stream that contains the PDF document. * @param rafi The RandomAccessFile to be used in internal COSDocument * * @throws IOException If there is an error initializing the stream. */ public PDFParser(InputStream input, RandomAccess rafi) throws IOException { this(input, rafi, FORCE_PARSING); } /** * Constructor to allow control over RandomAccessFile. * Also enables parser to skip corrupt objects to try and force parsing * @param input The input stream that contains the PDF document. * @param rafi The RandomAccessFile to be used in internal COSDocument * @param force When true, the parser will skip corrupt pdf objects and * will continue parsing at the next object in the file * * @throws IOException If there is an error initializing the stream. */ public PDFParser(InputStream input, RandomAccess rafi, boolean force) throws IOException { super(input, force); this.raf = rafi; } /** * This is the directory where pdfbox will create a temporary file * for storing pdf document stream in. By default this directory will * be the value of the system property java.io.tmpdir. * * @param tmpDir The directory to create scratch files needed to store * pdf document streams. */ public void setTempDirectory( File tmpDir ) { tempDirectory = tmpDir; } /** * Returns true if parsing should be continued. By default, forceParsing is returned. * This can be overridden to add application specific handling (for example to stop * parsing when the number of exceptions thrown exceed a certain number). * * @param e The exception if vailable. Can be null if there is no exception available * @return true if parsing could be continued, otherwise false */ protected boolean isContinueOnError(Exception e) { return forceParsing; } /** * This will parse the stream and populate the COSDocument object. This will close * the stream when it is done parsing. * * @throws IOException If there is an error reading from the stream or corrupt data * is found. */ public void parse() throws IOException { try { if ( raf == null ) { if( tempDirectory != null ) { document = new COSDocument( tempDirectory ); } else { document = new COSDocument(); } } else { document = new COSDocument( raf ); } setDocument( document ); parseHeader(); //Some PDF files have garbage between the header and the //first object skipToNextObj(); boolean wasLastParsedObjectEOF = false; while(true) { if(pdfSource.isEOF()) { break; } try { // don't reset flag to false if it is already true wasLastParsedObjectEOF |= parseObject(); } catch(IOException e) { /* * PDF files may have random data after the EOF marker. Ignore errors if * last object processed is EOF. */ if( wasLastParsedObjectEOF ) { break; } if(isContinueOnError(e)) { /* * Warning is sent to the PDFBox.log and to the Console that * we skipped over an object */ LOG.warn("Parsing Error, Skipping Object", e); skipSpaces(); long lastOffset = pdfSource.getOffset(); skipToNextObj(); /* the nextObject is the one we want to skip * so read the 'Object Number' without interpret it * in order to force the skipObject */ if (lastOffset == pdfSource.getOffset()) { readStringNumber(); skipToNextObj(); } } else { throw e; } } skipSpaces(); } // set xref to start with xrefTrailerResolver.setStartxref( document.getStartXref() ); // get resolved xref table + trailer document.setTrailer( xrefTrailerResolver.getTrailer() ); document.addXRefTable( xrefTrailerResolver.getXrefTable() ); fixStreamsLength(); if( !document.isEncrypted() ) { document.dereferenceObjectStreams(); } else { LOG.info("Document is encrypted"); } ConflictObj.resolveConflicts(document, conflictList); } catch( Throwable t ) { //so if the PDF is corrupt then close the document and clear //all resources to it if( document != null ) { document.close(); document = null; } if( t instanceof IOException ) { throw (IOException)t; } else { throw new WrappedIOException( t ); } } finally { pdfSource.close(); } } /** * Check whether streams with previously unknown length have the correct * length and fix that length if needed. * * @throws IOException */ private void fixStreamsLength() throws IOException { for (COSObject obj : document.getObjects()) { if (obj.getObject() instanceof COSStream && streamLengthCheckSet.contains((COSStream) obj.getObject())) { COSStream stream = (COSStream) obj.getObject(); long filteredLength = stream.getFilteredLength(); long filteredLengthWritten = stream.getFilteredLengthWritten(); if (Math.abs(filteredLength - filteredLengthWritten) > 2) { // adjust the length, but only if the difference is > 2, // i.e. don't bother with CR LF differences LOG.warn("/Length of " + obj + " corrected from " + filteredLength + " to " + filteredLengthWritten); stream.setLong(COSName.LENGTH, filteredLengthWritten); stream.setFilteredLength(filteredLengthWritten); } } } } /** * Skip to the start of the next object. This is used to recover * from a corrupt object. This should handle all cases that parseObject * supports. This assumes that the next object will * start on its own line. * * @throws IOException */ private void skipToNextObj() throws IOException { byte[] b = new byte[16]; Pattern p = Pattern.compile("\\d+\\s+\\d+\\s+obj.*", Pattern.DOTALL); /* Read a buffer of data each time to see if it starts with a * known keyword. This is not the most efficient design, but we should * rarely be needing this function. We could update this to use the * circular buffer, like in readUntilEndStream(). */ while(!pdfSource.isEOF()) { int l = pdfSource.read(b); if(l < 1) { break; } String s = new String(b, "US-ASCII"); if(s.startsWith("trailer") || s.startsWith("xref") || s.startsWith("startxref") || s.startsWith("stream") || p.matcher(s).matches()) { pdfSource.unread(b); break; } else { pdfSource.unread(b, 1, l-1); } } } protected void parseHeader() throws IOException { // read first line String header = readLine(); // some pdf-documents are broken and the pdf-version is in one of the following lines if (!header.contains(PDF_HEADER) && !header.contains(FDF_HEADER)) { header = readLine(); while (!header.contains(PDF_HEADER) && !header.contains(FDF_HEADER)) { // if a line starts with a digit, it has to be the first one with data in it if ((header.length() > 0) && (Character.isDigit(header.charAt(0)))) { break; } header = readLine(); } } // nothing found if ((header.indexOf( PDF_HEADER ) == -1) && (header.indexOf( FDF_HEADER ) == -1)) { throw new IOException( "Error: Header doesn't contain versioninfo" ); } //sometimes there are some garbage bytes in the header before the header //actually starts, so lets try to find the header first. int headerStart = header.indexOf( PDF_HEADER ); if (headerStart == -1) { headerStart = header.indexOf(FDF_HEADER); } //greater than zero because if it is zero then //there is no point of trimming if ( headerStart > 0 ) { //trim off any leading characters header = header.substring( headerStart, header.length() ); } /* * This is used if there is garbage after the header on the same line */ if (header.startsWith(PDF_HEADER)) { if (!header.matches(PDF_HEADER + "\\d.\\d")) { if (header.length() < PDF_HEADER.length() + 3) { // No version number at all, set to 1.4 as default header = PDF_HEADER + PDF_DEFAULT_VERSION; LOG.debug("No pdf version found, set to " + PDF_DEFAULT_VERSION + " as default."); } else { String headerGarbage = header.substring(PDF_HEADER.length() + 3, header.length()) + "\n"; header = header.substring(0, PDF_HEADER.length() + 3); pdfSource.unread(headerGarbage.getBytes("ISO-8859-1")); } } } else { isFDFDocment = true; if (!header.matches(FDF_HEADER + "\\d.\\d")) { if (header.length() < FDF_HEADER.length() + 3) { // No version number at all, set to 1.0 as default header = FDF_HEADER + FDF_DEFAULT_VERSION; LOG.debug("No fdf version found, set to " + FDF_DEFAULT_VERSION + " as default."); } else { String headerGarbage = header.substring(FDF_HEADER.length() + 3, header.length()) + "\n"; header = header.substring(0, FDF_HEADER.length() + 3); pdfSource.unread(headerGarbage.getBytes("ISO-8859-1")); } } } document.setHeaderString(header); try { if (header.startsWith( PDF_HEADER )) { float pdfVersion = Float. parseFloat( header.substring( PDF_HEADER.length(), Math.min( header.length(), PDF_HEADER .length()+3) ) ); document.setVersion( pdfVersion ); } else { float pdfVersion = Float. parseFloat( header.substring( FDF_HEADER.length(), Math.min( header.length(), FDF_HEADER.length()+3) ) ); document.setVersion( pdfVersion ); } } catch ( NumberFormatException e ) { throw new IOException( "Error getting pdf version:" + e ); } } /** * This will get the document that was parsed. parse() must be called before this is called. * When you are done with this document you must call close() on it to release * resources. * * @return The document that was parsed. * * @throws IOException If there is an error getting the document. */ public COSDocument getDocument() throws IOException { if( document == null ) { throw new IOException( "You must call parse() before calling getDocument()" ); } return document; } /** * This will get the PD document that was parsed. When you are done with * this document you must call close() on it to release resources. * * @return The document at the PD layer. * * @throws IOException If there is an error getting the document. */ public PDDocument getPDDocument() throws IOException { return new PDDocument( getDocument(), this ); } /** * This will get the FDF document that was parsed. When you are done with * this document you must call close() on it to release resources. * * @return The document at the PD layer. * * @throws IOException If there is an error getting the document. */ public FDFDocument getFDFDocument() throws IOException { return new FDFDocument( getDocument() ); } /** * This will parse the next object from the stream and add it to * the local state. * * @return Returns true if the processed object had an endOfFile marker * * @throws IOException If an IO error occurs. */ private boolean parseObject() throws IOException { long currentObjByteOffset = pdfSource.getOffset(); boolean isEndOfFile = false; skipSpaces(); //peek at the next character to determine the type of object we are parsing char peekedChar = (char)pdfSource.peek(); //ignore endobj and endstream sections. while( peekedChar == 'e' ) { //there are times when there are multiple endobj, so lets //just read them and move on. readString(); skipSpaces(); currentObjByteOffset = pdfSource.getOffset(); peekedChar = (char)pdfSource.peek(); } if( pdfSource.isEOF()) { //"Skipping because of EOF" ); //end of file we will return a false and call it a day. } //xref table. Note: The contents of the Xref table are currently ignored else if( peekedChar == 'x') { parseXrefTable( currentObjByteOffset ); } // Note: startxref can occur in either a trailer section or by itself else if (peekedChar == 't' || peekedChar == 's') { if(peekedChar == 't') { parseTrailer(); peekedChar = (char)pdfSource.peek(); } if (peekedChar == 's') { parseStartXref(); // readString() calls skipSpaces() will skip comments... that's // bad for us b/c the %%EOF flag is a comment while(isWhitespace(pdfSource.peek()) && !pdfSource.isEOF()) { pdfSource.read(); // read (get rid of) all the whitespace } String eof = ""; if(!pdfSource.isEOF()) { eof = readLine(); // if there's more data to read, get the EOF flag } // verify that EOF exists (see PDFBOX-979 for documentation on special cases) if(!"%%EOF".equals(eof)) { if(eof.startsWith("%%EOF")) { // content after marker -> unread with first space byte for read newline pdfSource.unread(SPACE_BYTE); // we read a whole line; add space as newline replacement pdfSource.unread(eof.substring(5).getBytes("ISO-8859-1")); } else { // PDF does not conform to spec, we should warn someone LOG.warn("expected='%%EOF' actual='" + eof + "'"); // if we're not at the end of a file, just put it back and move on if(!pdfSource.isEOF()) { pdfSource.unread( SPACE_BYTE ); // we read a whole line; add space as newline replacement pdfSource.unread(eof.getBytes("ISO-8859-1")); } } } isEndOfFile = true; } } //we are going to parse an normal object else { long number = -1; int genNum; String objectKey; boolean missingObjectNumber = false; try { char peeked = (char)pdfSource.peek(); if( peeked == '<' ) { missingObjectNumber = true; } else { number = readObjectNumber(); } } catch( IOException e ) { //ok for some reason "GNU Ghostscript 5.10" puts two endobj //statements after an object, of course this is nonsense //but because we want to support as many PDFs as possible //we will simply try again number = readObjectNumber(); } if( !missingObjectNumber ) { skipSpaces(); genNum = readGenerationNumber(); objectKey = readString( 3 ); //System.out.println( "parseObject() num=" + number + //" genNumber=" + genNum + " key='" + objectKey + "'" ); if( !objectKey.equals( "obj" ) ) { if (!isContinueOnError(null) || !objectKey.equals("o")) { throw new IOException("expected='obj' actual='" + objectKey + "' " + pdfSource); } //assume that "o" was meant to be "obj" (this is a workaround for // PDFBOX-773 attached PDF Andersens_Fairy_Tales.pdf). } } else { number = -1; genNum = -1; } skipSpaces(); COSBase pb = parseDirObject(); String endObjectKey = readString(); if( endObjectKey.equals( "stream" ) ) { pdfSource.unread( endObjectKey.getBytes("ISO-8859-1") ); pdfSource.unread( ' ' ); if( pb instanceof COSDictionary ) { pb = parseCOSStream( (COSDictionary)pb, getDocument().getScratchFile() ); // test for XRef type final COSStream strmObj = (COSStream) pb; // remember streams without length to check them later COSBase streamLength = strmObj.getItem(COSName.LENGTH); int length = -1; if (streamLength instanceof COSNumber) { length = ((COSNumber) streamLength).intValue(); } if (length == -1) { streamLengthCheckSet.add(strmObj); } if (COSName.XREF.equals(strmObj.getItem(COSName.TYPE))) { // XRef stream parseXrefStream( strmObj, currentObjByteOffset ); } } else { // this is not legal // the combination of a dict and the stream/endstream forms a complete stream object throw new IOException("stream not preceded by dictionary"); } skipSpaces(); endObjectKey = readLine(); } COSObjectKey key = new COSObjectKey( number, genNum ); COSObject pdfObject = document.getObjectFromPool( key ); if(pdfObject.getObject() == null) { pdfObject.setObject(pb); } /* * If the object we returned already has a baseobject, then we have a conflict * which we will resolve using information after we parse the xref table. */ else { addObjectToConflicts(currentObjByteOffset, key, pb); } if( !endObjectKey.equals( "endobj" ) ) { if (endObjectKey.startsWith( "endobj" ) ) { /* * Some PDF files don't contain a new line after endobj so we * need to make sure that the next object number is getting read separately * and not part of the endobj keyword. Ex. Some files would have "endobj28" * instead of "endobj" */ pdfSource.unread( SPACE_BYTE ); // add a space first in place of the newline consumed by readline() pdfSource.unread( endObjectKey.substring( 6 ).getBytes("ISO-8859-1") ); } else if(endObjectKey.trim().endsWith("endobj")) { /* * Some PDF files contain junk (like ">> ", in the case of a PDF * I found which was created by Exstream Dialogue Version 5.0.039) * in which case we ignore the data before endobj and just move on */ LOG.warn("expected='endobj' actual='" + endObjectKey + "' "); } else if( !pdfSource.isEOF() ) { //It is possible that the endobj is missing, there //are several PDFs out there that do that so. Unread //and assume that endobj was missing pdfSource.unread( SPACE_BYTE ); // add a space first in place of the newline consumed by readline() pdfSource.unread( endObjectKey.getBytes("ISO-8859-1") ); } } skipSpaces(); } return isEndOfFile; } /** * Adds a new ConflictObj to the conflictList. * @param offset the offset of the ConflictObj * @param key The COSObjectKey of this object * @param pb The COSBase of this conflictObj * @throws IOException */ private void addObjectToConflicts(long offset, COSObjectKey key, COSBase pb) throws IOException { COSObject obj = new COSObject(null); obj.setObjectNumber( COSInteger.get( key.getNumber() ) ); obj.setGenerationNumber( COSInteger.get( key.getGeneration() ) ); obj.setObject(pb); ConflictObj conflictObj = new ConflictObj(offset, key, obj); conflictList.add(conflictObj); } /** * This will parse the startxref section from the stream. * The startxref value is ignored. * * @return false on parsing error * @throws IOException If an IO error occurs. */ protected boolean parseStartXref() throws IOException { if(pdfSource.peek() != 's') { return false; } String startXRef = readString(); if( !startXRef.trim().equals( "startxref" ) ) { return false; } skipSpaces(); /* This integer is the byte offset of the first object referenced by the xref or xref stream * Needed for the incremental update (PREV) */ getDocument().setStartXref(readLong()); return true; } /** * This will parse the xref table from the stream and add it to the state * The XrefTable contents are ignored. * @param startByteOffset the offset to start at * @return false on parsing error * @throws IOException If an IO error occurs. */ protected boolean parseXrefTable( long startByteOffset ) throws IOException { if(pdfSource.peek() != 'x') { return false; } String xref = readString(); if( !xref.trim().equals( "xref" ) ) { return false; } // check for trailer after xref String str = readString(); byte[] b = str.getBytes("ISO-8859-1"); pdfSource.unread(b, 0, b.length); // signal start of new XRef xrefTrailerResolver.nextXrefObj( startByteOffset ); if (str.startsWith("trailer")) { LOG.warn("skipping empty xref table"); return false; } /* * Xref tables can have multiple sections. * Each starts with a starting object id and a count. */ while(true) { long currObjID = readObjectNumber(); // first obj id long count = readLong(); // the number of objects in the xref table skipSpaces(); for(int i = 0; i < count; i++) { if(pdfSource.isEOF() || isEndOfName((char)pdfSource.peek())) { break; } if(pdfSource.peek() == 't') { break; } //Ignore table contents String currentLine = readLine(); String[] splitString = currentLine.split("\\s"); if (splitString.length < 3) { LOG.warn("invalid xref line: " + currentLine); break; } /* This supports the corrupt table as reported in * PDFBOX-474 (XXXX XXX XX n) */ if(splitString[splitString.length-1].equals("n")) { try { long currOffset = Long.parseLong(splitString[0]); int currGenID = Integer.parseInt(splitString[1]); COSObjectKey objKey = new COSObjectKey(currObjID, currGenID); xrefTrailerResolver.setXRef(objKey, currOffset); } catch(NumberFormatException e) { throw new IOException(e.getMessage()); } } else if(!splitString[2].equals("f")) { throw new IOException("Corrupt XRefTable Entry - ObjID:" + currObjID); } currObjID++; skipSpaces(); } skipSpaces(); char c = (char)pdfSource.peek(); if(c < '0' || c > '9') { break; } } return true; } /** * This will parse the trailer from the stream and add it to the state. * * @return false on parsing error * @throws IOException If an IO error occurs. */ protected boolean parseTrailer() throws IOException { if(pdfSource.peek() != 't') { return false; } //read "trailer" String nextLine = readLine(); if( !nextLine.trim().equals( "trailer" ) ) { // in some cases the EOL is missing and the trailer immediately // continues with "<<" or with a blank character // even if this does not comply with PDF reference we want to support as many PDFs as possible // Acrobat reader can also deal with this. if (nextLine.startsWith("trailer")) { byte[] b = nextLine.getBytes("ISO-8859-1"); int len = "trailer".length(); pdfSource.unread('\n'); pdfSource.unread(b, len, b.length-len); } else { return false; } } // in some cases the EOL is missing and the trailer continues with " <<" // even if this does not comply with PDF reference we want to support as many PDFs as possible // Acrobat reader can also deal with this. skipSpaces(); COSDictionary parsedTrailer = parseCOSDictionary(); xrefTrailerResolver.setTrailer( parsedTrailer ); // The version can also be specified within the document /Catalog readVersionInTrailer(parsedTrailer); skipSpaces(); return true; } /** * The document catalog can also have a /Version parameter which overrides the version specified * in the header if, and only if it is greater. * * @param parsedTrailer the parsed catalog in the trailer */ protected void readVersionInTrailer(COSDictionary parsedTrailer) { COSObject root = (COSObject) parsedTrailer.getItem(COSName.ROOT); if (root != null) { COSBase item = root.getItem(COSName.VERSION); if (item instanceof COSName) { COSName version = (COSName) item; float trailerVersion = Float.valueOf(version.getName()); if (trailerVersion > document.getVersion()) { document.setVersion(trailerVersion); } } else if (item != null) { LOG.warn("Incorrect /Version entry is ignored: " + item); } } } /** * Fills XRefTrailerResolver with data of given stream. * Stream must be of type XRef. * @param stream the stream to be read * @param objByteOffset the offset to start at * @throws IOException if there is an error parsing the stream */ public void parseXrefStream( COSStream stream, long objByteOffset ) throws IOException { parseXrefStream(stream, objByteOffset, true); } /** * Fills XRefTrailerResolver with data of given stream. * Stream must be of type XRef. * @param stream the stream to be read * @param objByteOffset the offset to start at * @param isStandalone should be set to true if the stream is not part of a hybrid xref table * @throws IOException if there is an error parsing the stream */ public void parseXrefStream( COSStream stream, long objByteOffset, boolean isStandalone ) throws IOException { // the cross reference stream of a hybrid xref table will be added to the existing one // and we must not override the offset and the trailer if (isStandalone) { xrefTrailerResolver.nextXrefObj( objByteOffset ); xrefTrailerResolver.setTrailer( stream ); } PDFXrefStreamParser parser = new PDFXrefStreamParser( stream, document, forceParsing, xrefTrailerResolver ); parser.parse(); } /** * Used to resolve conflicts when a PDF Document has multiple objects with * the same id number. Ideally, we could use the Xref table when parsing * the document to be able to determine which of the objects with the same ID * is correct, but we do not have access to the Xref Table during parsing. * Instead, we queue up the conflicts and resolve them after the Xref has * been parsed. The Objects listed in the Xref Table are kept and the * others are ignored. */ private static class ConflictObj { private final long offset; private final COSObjectKey objectKey; private final COSObject object; ConflictObj(long offsetValue, COSObjectKey key, COSObject pdfObject) { this.offset = offsetValue; this.objectKey = key; this.object = pdfObject; } @Override public String toString() { return "Object(" + offset + ", " + objectKey + ")"; } /** * Sometimes pdf files have objects with the same ID number yet are * not referenced by the Xref table and therefore should be excluded. * This method goes through the conflicts list and replaces the object stored * in the objects array with this one if it is referenced by the xref * table. * @throws IOException */ private static void resolveConflicts(COSDocument document, List conflictList) throws IOException { Iterator conflicts = conflictList.iterator(); if (conflicts.hasNext()) { Collection values = document.getXrefTable().values(); do { ConflictObj o = conflicts.next(); if (tolerantConflicResolver(values, o.offset, 4)) { COSObject pdfObject = document.getObjectFromPool(o.objectKey); if (pdfObject.getObjectNumber() != null && pdfObject.getObjectNumber().equals(o.object.getObjectNumber())) { pdfObject.setObject(o.object.getObject()); } else { LOG.debug("Conflict object [" + o.objectKey + "] at offset " + o.offset +" found in the xref table, but the object numbers differ. Ignoring this object." + " The document is maybe malformed."); } } } while (conflicts.hasNext()); } } } /** * Check if the given object offset can be find in the xref table. If not, we try to search the table * again with the given tolerance and check the given bytes before and after the xref table offset. * * @param values are the unsorted values from the xref table * @param offset is the offset that should be found in the xref table * @param tolerance is the allowed tolerance in bytes. * @return true if the offset was found inside the xref table */ private static boolean tolerantConflicResolver(Collection values, long offset, int tolerance) { if (values.contains(offset)) { return true; } else { for ( Long integer : values ) { if (Math.abs(integer - offset) <= tolerance) { return true; } } } return false; } /** * {@inheritDoc} */ @Override public void clearResources() { super.clearResources(); if (conflictList != null) { conflictList.clear(); conflictList = null; } if (xrefTrailerResolver != null) { xrefTrailerResolver.clearResources(); xrefTrailerResolver = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/ConformingPDFParser.java0000644000000000000000000006542512645757432027466 0ustar rootroot/* * Copyright 2010 adam. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * under the License. */ package org.apache.pdfbox.pdfparser; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.cos.COSUnread; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.io.RandomAccessFile; import org.apache.pdfbox.pdmodel.ConformingPDDocument; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.XrefEntry; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * * @author Adam Nichols */ public class ConformingPDFParser extends BaseParser { protected RandomAccess inputFile; List xrefEntries; private long currentOffset; private ConformingPDDocument doc = null; private boolean throwNonConformingException = true; private boolean recursivlyRead = true; /** * Constructor. * * @param inputFile The input stream that contains the PDF document. * * @throws IOException If there is an error initializing the stream. */ public ConformingPDFParser(File inputFile) throws IOException { this.inputFile = new RandomAccessFile(inputFile, "r"); } /** * This will parse the stream and populate the COSDocument object. This will close * the stream when it is done parsing. * * @throws IOException If there is an error reading from the stream or corrupt data * is found. */ public void parse() throws IOException { document = new COSDocument(); doc = new ConformingPDDocument(document); currentOffset = inputFile.length()-1; long xRefTableLocation = parseTrailerInformation(); currentOffset = xRefTableLocation; parseXrefTable(); // now that we read the xref table and put null references in the doc, // we can deference those objects now. boolean oldValue = recursivlyRead; recursivlyRead = false; List keys = doc.getObjectKeysFromPool(); for(COSObjectKey key : keys) { // getObject will put it into the document's object pool for us getObject(key.getNumber(), key.getGeneration()); } recursivlyRead = oldValue; } /** * This will get the document that was parsed. parse() must be called before this is called. * When you are done with this document you must call close() on it to release * resources. * * @return The document that was parsed. * * @throws IOException If there is an error getting the document. */ public COSDocument getDocument() throws IOException { if( document == null ) { throw new IOException( "You must call parse() before calling getDocument()" ); } return document; } /** * This will get the PD document that was parsed. When you are done with * this document you must call close() on it to release resources. * * @return The document at the PD layer. * * @throws IOException If there is an error getting the document. */ public PDDocument getPDDocument() throws IOException { return doc; } private boolean parseXrefTable() throws IOException { String currentLine = readLine(); if(throwNonConformingException) { if(!"xref".equals(currentLine)) throw new AssertionError("xref table not found.\nExpected: xref\nFound: "+currentLine); } int objectNumber = readInt(); int entries = readInt(); xrefEntries = new ArrayList(entries); for(int i=0; i")) { // string of hex codes return COSString.createFromHexString(string.replaceAll("^<", "").replaceAll(">$", "")); } return null; } protected COSBase readObjectBackwards() throws IOException { COSBase obj = null; consumeWhitespaceBackwards(); String lastSection = readBackwardUntilWhitespace(); if("R".equals(lastSection)) { // indirect reference long gen = readLongBackwards(); long number = readLongBackwards(); // We just put a placeholder in the pool for now, we'll read the data later doc.putObjectInPool(new COSUnread(), number, gen); obj = new COSUnread(number, gen, this); } else if(">>".equals(lastSection)) { // dictionary throw new RuntimeException("Not yet implemented"); } else if(lastSection != null && lastSection.endsWith("]")) { // array COSArray array = new COSArray(); lastSection = lastSection.replaceAll("]$", ""); while(!lastSection.startsWith("[")) { if(lastSection.matches("^\\s*<.*>\\s*$")) // it's a hex string array.add(COSString.createFromHexString(lastSection.replaceAll("^\\s*<", "").replaceAll(">\\s*$", ""))); lastSection = readBackwardUntilWhitespace(); } lastSection = lastSection.replaceAll("^\\[", ""); if(lastSection.matches("^\\s*<.*>\\s*$")) // it's a hex string array.add(COSString.createFromHexString(lastSection.replaceAll("^\\s*<", "").replaceAll(">\\s*$", ""))); obj = array; } else if(lastSection != null && lastSection.endsWith(">")) { // string of hex codes obj = processCosObject(lastSection); } else { // try a number, otherwise fall back on a string try { Long.parseLong(lastSection); obj = COSNumber.get(lastSection); } catch(NumberFormatException e) { throw new RuntimeException("Not yet implemented"); } } return obj; } protected COSName readNameBackwards() throws IOException { String name = readBackwardUntilWhitespace(); name = name.replaceAll("^/", ""); return COSName.getPDFName(name); } public COSBase getObject(long objectNumber, long generation) throws IOException { // we could optionally, check to see if parse() have been called & // throw an exception here, but I don't think that's really necessary XrefEntry entry = xrefEntries.get((int)objectNumber); currentOffset = entry.getByteOffset(); return readObject(objectNumber, generation); } /** * This will read an object from the inputFile at whatever our currentOffset * is. If the object and generation are not the expected values and this * object is set to throw an exception for non-conforming documents, then an * exception will be thrown. * @param objectNumber the object number you expect to read * @param generation the generation you expect this object to be * @return the object being read. */ public COSBase readObject(long objectNumber, long generation) throws IOException { // when recursivly reading, we always pull the object from the filesystem if(document != null && recursivlyRead) { // check to see if it is in the document cache before hitting the filesystem COSBase obj = doc.getObjectFromPool(objectNumber, generation); if(obj != null) return obj; } int actualObjectNumber = readInt(); if(objectNumber != actualObjectNumber) if(throwNonConformingException) throw new AssertionError("Object numer expected was " + objectNumber + " but actual was " + actualObjectNumber); consumeWhitespace(); int actualGeneration = readInt(); if(generation != actualGeneration) if(throwNonConformingException) throw new AssertionError("Generation expected was " + generation + " but actual was " + actualGeneration); consumeWhitespace(); String obj = readWord(); if(!"obj".equals(obj)) if(throwNonConformingException) throw new AssertionError("Expected keyword 'obj' but found " + obj); // put placeholder object in doc to prevent infinite recursion // e.g. read Root -> dereference object -> read object which has /Parent -> GOTO read Root doc.putObjectInPool(new COSObject(null), objectNumber, generation); COSBase object = readObject(); doc.putObjectInPool(object, objectNumber, generation); return object; } /** * This actually reads the object data. * @return the object which is read * @throws IOException */ protected COSBase readObject() throws IOException { consumeWhitespace(); String string = readWord(); if(string.startsWith("<<")) { // this is a dictionary COSDictionary dictionary = new COSDictionary(); boolean atEndOfDictionary = false; // remove the marker for the beginning of the dictionary string = string.replaceAll("^<<", ""); if("".equals(string) || string.matches("^\\w$")) string = readWord().trim(); while(!atEndOfDictionary) { COSName name = COSName.getPDFName(string); COSBase object = readObject(); dictionary.setItem(name, object); byte singleByte = consumeWhitespace(); if(singleByte == '>') { readByte(); // get rid of the second '>' atEndOfDictionary = true; } if(!atEndOfDictionary) string = readWord().trim(); } return dictionary; } else if(string.startsWith("/")) { // it's a dictionary label. i.e. /Type or /Pages or something similar COSBase name = COSName.getPDFName(string); return name; } else if(string.startsWith("-")) { // it's a negitive number return parseNumber(string); } else if(string.charAt(0) >= '0' && string.charAt(0) <= '9' ) { // it's a COSInt or COSFloat, or a weak reference (i.e. "3 0 R") // we'll have to peek ahead a little to see if it's a reference or not long tempOffset = this.currentOffset; consumeWhitespace(); String tempString = readWord(); if(tempString.matches("^[0-9]+$")) { // it is an int, might be a weak reference... tempString = readWord(); if(!"R".equals(tempString)) { // it's just a number, not a weak reference this.currentOffset = tempOffset; return parseNumber(string); } } else { // it's just a number, not a weak reference this.currentOffset = tempOffset; return parseNumber(string); } // it wasn't a number, so we need to parse the weak-reference this.currentOffset = tempOffset; int number = Integer.parseInt(string); int gen = readInt(); String r = readWord(); if(!"R".equals(r)) if(throwNonConformingException) throw new AssertionError("Expected keyword 'R' but found " + r); if(recursivlyRead) { // seek to the object, read it, seek back to current location long tempLocation = this.currentOffset; this.currentOffset = this.xrefEntries.get(number).getByteOffset(); COSBase returnValue = readObject(number, gen); this.currentOffset = tempLocation; return returnValue; } else { // Put a COSUnknown there as a placeholder COSObject obj = new COSObject(new COSUnread()); obj.setObjectNumber(COSInteger.get(number)); obj.setGenerationNumber(COSInteger.get(gen)); return obj; } } else if(string.startsWith("]")) { // end of an array, just return null if("]".equals(string)) return null; int oldLength = string.length(); this.currentOffset -= oldLength; return null; } else if(string.startsWith("[")) { // array of values // we'll just pay attention to the first part (this is in case there // is no whitespace between the "[" and the first element) int oldLength = string.length(); string = "["; this.currentOffset -= (oldLength - string.length() + 1); COSArray array = new COSArray(); COSBase object = readObject(); while(object != null) { array.add(object); object = readObject(); } return array; } else if(string.startsWith("(")) { // this is a string (not hex encoded), strip off the '(' and read until ')' StringBuilder sb = new StringBuilder(string.substring(1)); byte singleByte = readByte(); while(singleByte != ')') { sb.append((char)singleByte); singleByte = readByte(); } return new COSString(sb.toString()); } else { throw new RuntimeException("Not yet implemented: " + string + " loation=" + this.currentOffset); } } /** * This will read the next string from the stream. * @return The string that was read from the stream. * @throws IOException If there is an error reading from the stream. */ @Override protected String readString() throws IOException { consumeWhitespace(); StringBuilder buffer = new StringBuilder(); int c = pdfSource.read(); while(!isEndOfName((char)c) && !isClosing(c) && c != -1) { buffer.append( (char)c ); c = pdfSource.read(); } if (c != -1) { pdfSource.unread(c); } return buffer.toString(); } protected COSDictionary readDictionaryBackwards() throws IOException { COSDictionary dict = new COSDictionary(); // consume the last two '>' chars which signify the end of the dictionary consumeWhitespaceBackwards(); byte singleByte = readByteBackwards(); if(throwNonConformingException) { if(singleByte != '>') throw new AssertionError(""); } singleByte = readByteBackwards(); if(throwNonConformingException) { if(singleByte != '>') throw new AssertionError(""); } // check to see if we're at the end of the dictionary boolean atEndOfDictionary = false; singleByte = consumeWhitespaceBackwards(); if(singleByte == '<') { inputFile.seek(currentOffset-1); atEndOfDictionary = ((byte)inputFile.read()) == '<'; } COSDictionary backwardsDictionary = new COSDictionary(); // while we're not at the end of the dictionary, read in entries while(!atEndOfDictionary) { COSBase object = readObjectBackwards(); COSName name = readNameBackwards(); backwardsDictionary.setItem(name, object); singleByte = consumeWhitespaceBackwards(); if(singleByte == '<') { inputFile.seek(currentOffset-1); atEndOfDictionary = ((byte)inputFile.read()) == '<'; } } // the dictionaries preserve the order keys were added, as such we shall // add them in the proper order, not the reverse order Set backwardsKeys = backwardsDictionary.keySet(); for(int i = backwardsKeys.size()-1; i >=0; i--) dict.setItem((COSName)backwardsKeys.toArray()[i], backwardsDictionary.getItem((COSName)backwardsKeys.toArray()[i])); // consume the last two '<' chars readByteBackwards(); readByteBackwards(); return dict; } /** * This will read a line starting with the byte at offset and going * backwards until it finds a newline. This should only be used if we are * certain that the data will only be text, and not binary data. * * @return the string which was read * @throws IOException if there was an error reading data from the file */ protected String readLineBackwards() throws IOException { StringBuilder sb = new StringBuilder(); boolean endOfObject = false; do { // first we read the %%EOF marker byte singleByte = readByteBackwards(); if(singleByte == '\n') { // if ther's a preceeding \r, we'll eat that as well inputFile.seek(currentOffset); if((byte)inputFile.read() == '\r') currentOffset--; endOfObject = true; } else if(singleByte == '\r') { endOfObject = true; } else { sb.insert(0, (char)singleByte); } } while(!endOfObject); return sb.toString(); } /** * This will read a line starting with the byte at offset and going * forward until it finds a newline. This should only be used if we are * certain that the data will only be text, and not binary data. * @return the string which was read * @throws IOException if there was an error reading data from the file */ @Override protected String readLine() throws IOException { StringBuilder sb = new StringBuilder(); boolean endOfLine = false; do { // first we read the %%EOF marker byte singleByte = readByte(); if(singleByte == '\n') { // if ther's a preceeding \r, we'll eat that as well inputFile.seek(currentOffset); if((byte)inputFile.read() == '\r') currentOffset++; endOfLine = true; } else if(singleByte == '\r') { endOfLine = true; } else { sb.append((char)singleByte); } } while(!endOfLine); return sb.toString(); } protected String readWord() throws IOException { StringBuilder sb = new StringBuilder(); boolean stop = true; do { byte singleByte = readByte(); stop = this.isWhitespace(singleByte); // there are some additional characters which indicate the next element/word has begun // ignore the first char we read, b/c the first char is the beginnging of this object, not the next one if(!stop && sb.length() > 0) { stop = singleByte == '/' || singleByte == '[' || singleByte == ']' || (singleByte == '>' && !">".equals(sb.toString())); if(stop) // we're stopping on a non-whitespace char, decrement the this.currentOffset--; // counter so we don't miss this character } if(!stop) sb.append((char)singleByte); } while(!stop); return sb.toString(); } /** * @return the recursivlyRead */ public boolean isRecursivlyRead() { return recursivlyRead; } /** * @param recursivlyRead the recursivlyRead to set */ public void setRecursivlyRead(boolean recursivlyRead) { this.recursivlyRead = recursivlyRead; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefTrailerResolver.java0000644000000000000000000002530312645757432027616 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.SortedSet; import java.util.TreeSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * This class will collect all XRef/trailer objects and creates correct * xref/trailer information after all objects are read using startxref * and 'Prev' information (unused XRef/trailer objects are discarded). * * In case of missing startxref or wrong startxref pointer all * XRef/trailer objects are used to create xref table / trailer dictionary * in order they occur. * * For each new xref object/XRef stream method {@link #nextXrefObj(long)} * must be called with start byte position. All following calls to * {@link #setXRef(COSObjectKey, long)} or {@link #setTrailer(COSDictionary)} * will add the data for this byte position. * * After all objects are parsed the startxref position must be provided * using {@link #setStartxref(long)}. This is used to build the chain of * active xref/trailer objects used for creating document trailer and xref table. * * @author Timo Boehme (timo.boehme at ontochem.com) */ public class XrefTrailerResolver { /** * A class which represents a xref/trailer object. */ private class XrefTrailerObj { protected COSDictionary trailer = null; private final Map xrefTable = new HashMap(); /** * Default constructor. */ private XrefTrailerObj() { } /** * Release all used resources. */ public void clearResources() { if (trailer != null) { trailer.clear(); trailer = null; } if (xrefTable != null) { xrefTable.clear(); } } } private final Map bytePosToXrefMap = new HashMap(); private XrefTrailerObj curXrefTrailerObj = null; private XrefTrailerObj resolvedXrefTrailer = null; /** Log instance. */ private static final Log LOG = LogFactory.getLog( XrefTrailerResolver.class ); public final COSDictionary getFirstTrailer() { if (bytePosToXrefMap.isEmpty()) return null; Set offsets = bytePosToXrefMap.keySet(); SortedSet sortedOffset = new TreeSet(offsets); return bytePosToXrefMap.get(sortedOffset.first()).trailer; } public final COSDictionary getLastTrailer() { if (bytePosToXrefMap.isEmpty()) return null; Set offsets = bytePosToXrefMap.keySet(); SortedSet sortedOffset = new TreeSet(offsets); return bytePosToXrefMap.get(sortedOffset.last()).trailer; } /** * Signals that a new XRef object (table or stream) starts. * @param startBytePos the offset to start at * */ public void nextXrefObj( final long startBytePos ) { bytePosToXrefMap.put( startBytePos, curXrefTrailerObj = new XrefTrailerObj() ); } /** * Populate XRef HashMap of current XRef object. * Will add an Xreftable entry that maps ObjectKeys to byte offsets in the file. * @param objKey The objkey, with id and gen numbers * @param offset The byte offset in this file */ public void setXRef( COSObjectKey objKey, long offset ) { if ( curXrefTrailerObj == null ) { // should not happen... LOG.warn( "Cannot add XRef entry for '" + objKey.getNumber() + "' because XRef start was not signalled." ); return; } curXrefTrailerObj.xrefTable.put( objKey, offset ); } /** * Adds trailer information for current XRef object. * * @param trailer the current document trailer dictionary */ public void setTrailer( COSDictionary trailer ) { if ( curXrefTrailerObj == null ) { // should not happen... LOG.warn( "Cannot add trailer because XRef start was not signalled." ); return; } curXrefTrailerObj.trailer = trailer; } /** * Returns the trailer last set by {@link #setTrailer(COSDictionary)}. * * @return the current trailer. * */ public COSDictionary getCurrentTrailer() { return curXrefTrailerObj.trailer; } /** * Sets the byte position of the first XRef * (has to be called after very last startxref was read). * This is used to resolve chain of active XRef/trailer. * * In case startxref position is not found we output a * warning and use all XRef/trailer objects combined * in byte position order. * Thus for incomplete PDF documents with missing * startxref one could call this method with parameter value -1. * * @param startxrefBytePosValue starting position of the first XRef * */ public void setStartxref( long startxrefBytePosValue ) { if ( resolvedXrefTrailer != null ) { LOG.warn( "Method must be called only ones with last startxref value." ); return; } resolvedXrefTrailer = new XrefTrailerObj(); resolvedXrefTrailer.trailer = new COSDictionary(); XrefTrailerObj curObj = bytePosToXrefMap.get( startxrefBytePosValue ); List xrefSeqBytePos = new ArrayList(); if ( curObj == null ) { // no XRef at given position LOG.warn( "Did not found XRef object at specified startxref position " + startxrefBytePosValue ); // use all objects in byte position order (last entries overwrite previous ones) xrefSeqBytePos.addAll( bytePosToXrefMap.keySet() ); Collections.sort( xrefSeqBytePos ); } else { // found starting Xref object // add this and follow chain defined by 'Prev' keys xrefSeqBytePos.add( startxrefBytePosValue ); while ( curObj.trailer != null ) { long prevBytePos = curObj.trailer.getLong( COSName.PREV, -1L ); if ( prevBytePos == -1 ) { break; } curObj = bytePosToXrefMap.get( prevBytePos ); if ( curObj == null ) { LOG.warn( "Did not found XRef object pointed to by 'Prev' key at position " + prevBytePos ); break; } xrefSeqBytePos.add( prevBytePos ); // sanity check to prevent infinite loops if ( xrefSeqBytePos.size() >= bytePosToXrefMap.size() ) { break; } } // have to reverse order so that later XRefs will overwrite previous ones Collections.reverse( xrefSeqBytePos ); } // merge used and sorted XRef/trailer for ( Long bPos : xrefSeqBytePos ) { curObj = bytePosToXrefMap.get( bPos ); if ( curObj.trailer != null ) { resolvedXrefTrailer.trailer.addAll( curObj.trailer ); } resolvedXrefTrailer.xrefTable.putAll( curObj.xrefTable ); } } /** * Gets the resolved trailer. Might return null in case * {@link #setStartxref(long)} was not called before. * * @return the trailer if available */ public COSDictionary getTrailer() { return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.trailer; } /** * Gets the resolved xref table. Might return null in case * {@link #setStartxref(long)} was not called before. * * @return the xrefTable if available */ public Map getXrefTable() { return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.xrefTable; } /** Returns object numbers which are referenced as contained * in object stream with specified object number. * * This will scan resolved xref table for all entries having negated * stream object number as value. * * @param objstmObjNr object number of object stream for which contained object numbers * should be returned * * @return set of object numbers referenced for given object stream * or null if {@link #setStartxref(long)} was not * called before so that no resolved xref table exists */ public Set getContainedObjectNumbers( final int objstmObjNr ) { if ( resolvedXrefTrailer == null ) { return null; } final Set refObjNrs = new HashSet(); final int cmpVal = - objstmObjNr; for ( Entry xrefEntry : resolvedXrefTrailer.xrefTable.entrySet() ) { if ( xrefEntry.getValue() == cmpVal ) { refObjNrs.add( xrefEntry.getKey().getNumber() ); } } return refObjNrs; } /** * Release all used resources. */ public void clearResources() { if (curXrefTrailerObj != null) { curXrefTrailerObj.clearResources(); curXrefTrailerObj = null; } if (resolvedXrefTrailer != null) { resolvedXrefTrailer.clearResources(); resolvedXrefTrailer = null; } if (bytePosToXrefMap != null) { bytePosToXrefMap.clear(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFStreamParser.java0000644000000000000000000004440412645757432026612 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNull; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.util.ImageParameters; import org.apache.pdfbox.util.PDFOperator; /** * This will parse a PDF byte stream and extract operands and such. * * @author Ben Litchfield * @version $Revision$ */ public class PDFStreamParser extends BaseParser { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFStreamParser.class); private List streamObjects = new ArrayList( 100 ); private final RandomAccess file; private final int maxBinCharTestLength = 10; private final byte[] binCharTestArr = new byte[maxBinCharTestLength]; /** * Constructor that takes a stream to parse. * * @since Apache PDFBox 1.3.0 * @param stream The stream to read data from. * @param raf The random access file. * @param forceParsing flag to skip malformed or otherwise unparseable * input where possible * @throws IOException If there is an error reading from the stream. */ public PDFStreamParser( InputStream stream, RandomAccess raf, boolean forceParsing) throws IOException { super(stream, forceParsing); file = raf; } /** * Constructor that takes a stream to parse. * * @param stream The stream to read data from. * @param raf The random access file. * * @throws IOException If there is an error reading from the stream. */ public PDFStreamParser(InputStream stream, RandomAccess raf) throws IOException { this(stream, raf, FORCE_PARSING); } /** * Constructor. * * @param stream The stream to parse. * * @throws IOException If there is an error initializing the stream. */ public PDFStreamParser( PDStream stream ) throws IOException { this( stream.createInputStream(), stream.getStream().getScratchFile() ); } /** * Constructor. * * @since Apache PDFBox 1.3.0 * @param stream The stream to parse. * @param forceParsing flag to skip malformed or otherwise unparseable * input where possible * @throws IOException If there is an error initializing the stream. */ public PDFStreamParser(COSStream stream, boolean forceParsing) throws IOException { this(stream.getUnfilteredStream(), stream.getScratchFile(), forceParsing); } /** * Constructor. * * @param stream The stream to parse. * * @throws IOException If there is an error initializing the stream. */ public PDFStreamParser( COSStream stream ) throws IOException { this( stream.getUnfilteredStream(), stream.getScratchFile() ); } /** * This will parse the tokens in the stream. This will close the * stream when it is finished parsing. * * @throws IOException If there is an error while parsing the stream. */ public void parse() throws IOException { try { Object token; while( (token = parseNextToken()) != null ) { streamObjects.add( token ); //logger().fine( "parsed=" + token ); } } finally { pdfSource.close(); } } /** * This will get the tokens that were parsed from the stream. * * @return All of the tokens in the stream. */ public List getTokens() { return streamObjects; } /** * This will close the underlying pdfSource object. * * @throws IOException If there is an error releasing resources. */ public void close() throws IOException { pdfSource.close(); } /** * This will get an iterator which can be used to parse the stream * one token after the other. * * @return an iterator to get one token after the other */ public Iterator getTokenIterator() { return new Iterator() { private Object token; private void tryNext() { try { if (token == null) { token = parseNextToken(); } } catch (IOException e) { throw new RuntimeException(e); } } /** {@inheritDoc} */ public boolean hasNext() { tryNext(); return token != null; } /** {@inheritDoc} */ public Object next() { tryNext(); Object tmp = token; if (tmp == null) { throw new NoSuchElementException(); } token = null; return tmp; } /** {@inheritDoc} */ public void remove() { throw new UnsupportedOperationException(); } }; } /** * This will parse the next token in the stream. * * @return The next token in the stream or null if there are no more tokens in the stream. * * @throws IOException If an io error occurs while parsing the stream. */ private Object parseNextToken() throws IOException { Object retval; skipSpaces(); int nextByte = pdfSource.peek(); if( ((byte)nextByte) == -1 ) { return null; } char c = (char)nextByte; switch(c) { case '<': { int leftBracket = pdfSource.read();//pull off first left bracket c = (char)pdfSource.peek(); //check for second left bracket pdfSource.unread( leftBracket ); //put back first bracket if(c == '<') { COSDictionary pod = parseCOSDictionary(); skipSpaces(); if((char)pdfSource.peek() == 's') { retval = parseCOSStream( pod, file ); } else { retval = pod; } } else { retval = parseCOSString(); } break; } case '[': // array { retval = parseCOSArray(); break; } case '(': // string retval = parseCOSString(); break; case '/': // name retval = parseCOSName(); break; case 'n': // null { String nullString = readString(); if( nullString.equals( "null") ) { retval = COSNull.NULL; } else { retval = PDFOperator.getOperator( nullString ); } break; } case 't': case 'f': { String next = readString(); if( next.equals( "true" ) ) { retval = COSBoolean.TRUE; break; } else if( next.equals( "false" ) ) { retval = COSBoolean.FALSE; } else { retval = PDFOperator.getOperator( next ); } break; } case 'R': { String line = readString(); if( line.equals( "R" ) ) { retval = new COSObject( null ); } else { retval = PDFOperator.getOperator( line ); } break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': case '+': case '.': { /* We will be filling buf with the rest of the number. Only * allow 1 "." and "-" and "+" at start of number. */ StringBuffer buf = new StringBuffer(); buf.append( c ); pdfSource.read(); boolean dotNotRead = (c != '.'); while( Character.isDigit(( c = (char)pdfSource.peek()) ) || (dotNotRead && (c == '.')) ) { buf.append( c ); pdfSource.read(); if (dotNotRead && (c == '.')) { dotNotRead = false; } } retval = COSNumber.get( buf.toString() ); break; } case 'B': { String next = readString(); retval = PDFOperator.getOperator( next ); if( next.equals( "BI" ) ) { PDFOperator beginImageOP = (PDFOperator)retval; COSDictionary imageParams = new COSDictionary(); beginImageOP.setImageParameters( new ImageParameters( imageParams ) ); Object nextToken = null; while( (nextToken = parseNextToken()) instanceof COSName ) { Object value = parseNextToken(); imageParams.setItem( (COSName)nextToken, (COSBase)value ); } //final token will be the image data, maybe?? PDFOperator imageData = (PDFOperator)nextToken; beginImageOP.setImageData( imageData.getImageData() ); } break; } case 'I': { //Special case for ID operator String id = "" + (char)pdfSource.read() + (char)pdfSource.read(); if( !id.equals( "ID" ) ) { throw new IOException( "Error: Expected operator 'ID' actual='" + id + "'" ); } ByteArrayOutputStream imageData = new ByteArrayOutputStream(); if( isWhitespace() ) { //pull off the whitespace character pdfSource.read(); } int lastByte = pdfSource.read(); int currentByte = pdfSource.read(); // PDF spec is kinda unclear about this. Should a whitespace // always appear before EI? Not sure, so that we just read // until EI. // Be aware not all kind of whitespaces are allowed here. see PDFBOX-1561 while( !(lastByte == 'E' && currentByte == 'I' && hasNextSpaceOrReturn() && hasNoFollowingBinData( pdfSource )) && !pdfSource.isEOF() ) { imageData.write( lastByte ); lastByte = currentByte; currentByte = pdfSource.read(); } // the EI operator isn't unread, as it won't be processed anyway retval = PDFOperator.getOperator( "ID" ); // save the image data to the operator, so that it can be accessed later ((PDFOperator)retval).setImageData( imageData.toByteArray() ); break; } case ']': { // some ']' around without its previous '[' // this means a PDF is somewhat corrupt but we will continue to parse. pdfSource.read(); retval = COSNull.NULL; // must be a better solution than null... break; } default: { //we must be an operator String operator = readOperator(); if( operator.trim().length() == 0 ) { //we have a corrupt stream, stop reading here retval = null; } else { retval = PDFOperator.getOperator( operator ); } } } return retval; } /** * Looks up an amount of bytes if they contain only ASCII characters (no * control sequences etc.), and that these ASCII characters begin with a * sequence of 1-3 non-blank characters between blanks * * @return true if next bytes are probably printable ASCII * characters starting with a PDF operator, otherwise false */ private boolean hasNoFollowingBinData(final PushbackInputStream pdfSource) throws IOException { // as suggested in PDFBOX-1164 final int readBytes = pdfSource.read(binCharTestArr, 0, maxBinCharTestLength); boolean noBinData = true; int startOpIdx = -1; int endOpIdx = -1; if (readBytes > 0) { for (int bIdx = 0; bIdx < readBytes; bIdx++) { final byte b = binCharTestArr[bIdx]; if (b < 0x09 || b > 0x0a && b < 0x20 && b != 0x0d) { // control character or > 0x7f -> we have binary data noBinData = false; break; } // find the start of a PDF operator if (startOpIdx == -1 && !(b == 9 || b == 0x20 || b == 0x0a || b == 0x0d)) { startOpIdx = bIdx; } else if (startOpIdx != -1 && endOpIdx == -1 && (b == 9 || b == 0x20 || b == 0x0a || b == 0x0d)) { endOpIdx = bIdx; } } if (readBytes == maxBinCharTestLength) // only if not close to eof { // a PDF operator is 1-3 bytes long if (startOpIdx != -1 && endOpIdx == -1) { endOpIdx = maxBinCharTestLength; } if (endOpIdx != -1 && startOpIdx != -1 && endOpIdx - startOpIdx > 3) { noBinData = false; } } pdfSource.unread(binCharTestArr, 0, readBytes); } if (!noBinData) { LOG.warn("ignoring 'EI' assumed to be in the middle of inline image"); } return noBinData; } /** * This will read an operator from the stream. * * @return The operator that was read from the stream. * * @throws IOException If there is an error reading from the stream. */ protected String readOperator() throws IOException { skipSpaces(); //average string size is around 2 and the normal string buffer size is //about 16 so lets save some space. StringBuffer buffer = new StringBuffer(4); int nextChar = pdfSource.peek(); while( nextChar != -1 && // EOF !isWhitespace(nextChar) && !isClosing(nextChar) && nextChar != '[' && nextChar != '<' && nextChar != '(' && nextChar != '/' && (nextChar < '0' || nextChar > '9' ) ) { char currentChar = (char)pdfSource.read(); nextChar = pdfSource.peek(); buffer.append( currentChar ); // Type3 Glyph description has operators with a number in the name if (currentChar == 'd' && (nextChar == '0' || nextChar == '1') ) { buffer.append( (char)pdfSource.read() ); nextChar = pdfSource.peek(); } } return buffer.toString(); } private boolean isSpaceOrReturn( int c ) { return c == 10 || c == 13 || c == 32; } /** * Checks if the next char is a space or a return. * * @return true if the next char is a space or a return * @throws IOException if something went wrong */ private boolean hasNextSpaceOrReturn() throws IOException { return isSpaceOrReturn( pdfSource.peek() ); } /** * {@inheritDoc} */ @Override public void clearResources() { super.clearResources(); if (streamObjects != null) { streamObjects.clear(); streamObjects = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRef.java0000644000000000000000000000231412645757432025040 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import org.apache.pdfbox.cos.COSObject; /** * @author Alexander Funk * @version $Revision: $ */ public interface PDFXRef { /** * Returns the object referenced by the given object number. * * @param objectNumber the object to be returned * @return the object corresponding to the given object number */ COSObject getObject(int objectNumber); } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/EndstreamOutputStream.java0000644000000000000000000001055412645757432030166 0ustar rootroot/* * Copyright 2014 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; /** * This class is only for the readUntilEndStream methods, to prevent a * final CR LF or LF (but not a final CR!) from being written to the output, * unless the beginning of the stream is assumed to be ASCII. * Only the 3-param write() method is implemented. This solves * PDFBOX-2079 and PDFBOX-2120 and avoids making readUntilEndStream() * even more complex than it already is. * * @author Tilman Hausherr */ class EndstreamOutputStream extends BufferedOutputStream { //TODO: replace this class with a PullBackOutputStream class if there ever is one private boolean hasCR = false; private boolean hasLF = false; private int pos = 0; private boolean mustFilter = true; public EndstreamOutputStream(OutputStream out) { super(out); } /** * Write CR and/or LF that were kept, then writes len bytes from the * specified byte array starting at offset off to this output stream, * except trailing CR, CR LF, or LF. No filtering will be done for the * entire stream if the beginning is assumed to be ASCII. * @param b byte array. * @param off offset. * @param len length of segment to write. * @throws IOException */ @Override public void write(byte[] b, int off, int len) throws IOException { if (pos == 0 && len > 10) { // PDFBOX-2120 Don't filter if ASCII, i.e. keep a final CR LF or LF mustFilter = false; for (int i = 0; i < 10; ++i) { // Heuristic approach, taken from PDFStreamParser, PDFBOX-1164 if ((b[i] < 0x09) || ((b[i] > 0x0a) && (b[i] < 0x20) && (b[i] != 0x0d))) { // control character or > 0x7f -> we have binary data mustFilter = true; break; } } } if (mustFilter) { // first write what we kept last time if (hasCR) { if (!hasLF && len == 1 && b[off] == '\n') { // previous buffer ended with CR // actual buffer contains only LF so it will be the last one // => we're done hasCR = false; // to avoid this getting written in the flush return; } super.write('\r'); hasCR = false; } if (hasLF) { super.write('\n'); hasLF = false; } // don't write CR, LF, or CR LF if at the end of the buffer if (len > 0) { if (b[off + len - 1] == '\r') { hasCR = true; --len; } else if (b[off + len - 1] == '\n') { hasLF = true; --len; if (len > 0 && b[off + len - 1] == '\r') { hasCR = true; --len; } } } } super.write(b, off, len); pos += len; } /** * write out a single CR if one was kept. Don't write kept CR LF or LF, * and then call the base method to flush. * * @throws IOException */ @Override public void flush() throws IOException { // if there is only a CR and no LF, write it if (hasCR && !hasLF) { super.write('\r'); ++pos; } hasCR = false; hasLF = false; super.flush(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java0000644000000000000000000002545212645757432026224 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.io.RandomAccessBuffer; import org.apache.pdfbox.pdfwriter.COSWriterXRefEntry; /** * @author Alexander Funk * @version $Revision: $ */ public class PDFXRefStream implements PDFXRef { private static final int ENTRY_OBJSTREAM = 2; private static final int ENTRY_NORMAL = 1; private static final int ENTRY_FREE = 0; private Map streamData; private Set objectNumbers; private COSStream stream; private long size = -1; /** * Create a fresh XRef stream like for a fresh file or an incremental update. */ public PDFXRefStream() { this.stream = new COSStream(new COSDictionary(), new RandomAccessBuffer()); streamData = new TreeMap(); objectNumbers = new TreeSet(); } /** * Returns the stream of the XRef. * @return the XRef stream * @throws IOException if something went wrong */ public COSStream getStream() throws IOException { stream.setItem(COSName.TYPE, COSName.XREF); if (size == -1) { throw new IllegalArgumentException("size is not set in xrefstream"); } stream.setLong(COSName.SIZE, getSizeEntry()); stream.setFilters(COSName.FLATE_DECODE); { List indexEntry = getIndexEntry(); COSArray indexAsArray = new COSArray(); for ( Integer i : indexEntry ) { indexAsArray.add(COSInteger.get(i)); } stream.setItem(COSName.INDEX, indexAsArray); } { int[] wEntry = getWEntry(); COSArray wAsArray = new COSArray(); for ( int i = 0; i < wEntry.length; i++ ) { int j = wEntry[i]; wAsArray.add(COSInteger.get(j)); } stream.setItem(COSName.W, wAsArray); OutputStream unfilteredStream = stream.createUnfilteredStream(); writeStreamData(unfilteredStream, wEntry); } Set keySet = stream.keySet(); for ( COSName cosName : keySet ) { // "Other cross-reference stream entries not listed in Table 17 may be indirect; // in fact, some (such as Root in Table 15) shall be indirect." if (COSName.ROOT.equals(cosName) || COSName.INFO.equals(cosName) || COSName.PREV.equals(cosName)) { continue; } COSBase dictionaryObject = stream.getDictionaryObject(cosName); dictionaryObject.setDirect(true); } return stream; } /** * Copy all Trailer Information to this file. * * @param trailerDict dictionary to be added as trailer info */ public void addTrailerInfo(COSDictionary trailerDict) { Set> entrySet = trailerDict.entrySet(); for ( Entry entry : entrySet ) { COSName key = entry.getKey(); if (COSName.INFO.equals(key) || COSName.ROOT.equals(key) || COSName.ENCRYPT.equals(key) || COSName.ID.equals(key) || COSName.PREV.equals(key)) { stream.setItem(key, entry.getValue()); } } } /** * Add an new entry to the XRef stream. * * @param entry new entry to be added */ public void addEntry(COSWriterXRefEntry entry) { objectNumbers.add((int)entry.getKey().getNumber()); if (entry.isFree()) { // what would be a f-Entry in the xref table FreeReference value = new FreeReference(); value.nextGenNumber = entry.getKey().getGeneration(); value.nextFree = entry.getKey().getNumber(); streamData.put((int)value.nextFree, value); } else { // we don't care for ObjectStreamReferences for now and only handle // normal references that would be f-Entrys in the xref table. NormalReference value = new NormalReference(); value.genNumber = entry.getKey().getGeneration(); value.offset = entry.getOffset(); streamData.put((int)entry.getKey().getNumber(), value); } } /** * determines the minimal length required for all the lengths. * * @return the length information */ private int[] getWEntry() { long[] wMax = new long[3]; for ( Object entry : streamData.values() ) { if (entry instanceof FreeReference) { FreeReference free = (FreeReference)entry; wMax[0] = Math.max(wMax[0], ENTRY_FREE); // the type field for a free reference wMax[1] = Math.max(wMax[1], free.nextFree); wMax[2] = Math.max(wMax[2], free.nextGenNumber); } else if (entry instanceof NormalReference) { NormalReference ref = (NormalReference)entry; wMax[0] = Math.max(wMax[0], ENTRY_NORMAL); // the type field for a normal reference wMax[1] = Math.max(wMax[1], ref.offset); wMax[2] = Math.max(wMax[2], ref.genNumber); } else if (entry instanceof ObjectStreamReference) { ObjectStreamReference objStream = (ObjectStreamReference)entry; wMax[0] = Math.max(wMax[0], ENTRY_OBJSTREAM); // the type field for a objstm reference wMax[1] = Math.max(wMax[1], objStream.offset); wMax[2] = Math.max(wMax[2], objStream.objectNumberOfObjectStream); } // TODO add here if new standard versions define new types else { throw new RuntimeException("unexpected reference type"); } } // find the max bytes needed to display that column int[] w = new int[3]; for ( int i = 0; i < w.length; i++ ) { while (wMax[i] > 0) { w[i]++; wMax[i] >>= 8; } } return w; } private long getSizeEntry() { return size; } /** * Set the size of the XRef stream. * * @param streamSize size to bet set as stream size */ public void setSize(long streamSize) { this.size = streamSize; } private List getIndexEntry() { LinkedList linkedList = new LinkedList(); Integer first = null; Integer length = null; for ( Integer objNumber : objectNumbers ) { if (first == null) { first = objNumber; length = 1; } if (first + length == objNumber) { length += 1; } if (first + length < objNumber) { linkedList.add(first); linkedList.add(length); first = objNumber; length = 1; } } linkedList.add(first); linkedList.add(length); return linkedList; } private void writeNumber(OutputStream os, long number, int bytes) throws IOException { byte[] buffer = new byte[bytes]; for ( int i = 0; i < bytes; i++ ) { buffer[i] = (byte)(number & 0xff); number >>= 8; } for ( int i = 0; i < bytes; i++ ) { os.write(buffer[bytes-i-1]); } } private void writeStreamData(OutputStream os, int[] w) throws IOException { // iterate over all streamData and write it in the required format for ( Object entry : streamData.values() ) { if (entry instanceof FreeReference) { FreeReference free = (FreeReference)entry; writeNumber(os, ENTRY_FREE, w[0]); writeNumber(os, free.nextFree, w[1]); writeNumber(os, free.nextGenNumber, w[2]); } else if (entry instanceof NormalReference) { NormalReference ref = (NormalReference)entry; writeNumber(os, ENTRY_NORMAL, w[0]); writeNumber(os, ref.offset, w[1]); writeNumber(os, ref.genNumber, w[2]); } else if (entry instanceof ObjectStreamReference) { ObjectStreamReference objStream = (ObjectStreamReference)entry; writeNumber(os, ENTRY_OBJSTREAM, w[0]); writeNumber(os, objStream.offset, w[1]); writeNumber(os, objStream.objectNumberOfObjectStream, w[2]); } // TODO add here if new standard versions define new types else { throw new RuntimeException("unexpected reference type"); } } os.flush(); os.close(); } /** * A class representing an object stream reference. * */ class ObjectStreamReference { long objectNumberOfObjectStream; long offset; } /** * A class representing a normal reference. * */ class NormalReference { long genNumber; long offset; } /** * A class representing a free reference. * */ class FreeReference { long nextGenNumber; long nextFree; } /** * {@inheritDoc} */ public COSObject getObject(int objectNumber) { return null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXrefStreamParser.java0000644000000000000000000001652112645757432027436 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdfparser; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * This will parse a PDF 1.5 (or better) Xref stream and * extract the xref information from the stream. * * @author Justin LeFebvre * @version $Revision: 1.0 $ */ public class PDFXrefStreamParser extends BaseParser { private COSStream stream; private XrefTrailerResolver xrefTrailerResolver; /** * Constructor. * * @since 1.3.0 * @param strm The stream to parse. * @param doc The document for the current parsing. * @param forceParsing flag to skip malformed or otherwise unparseable * input where possible * @param resolver resolver to read the xref/trailer information * * @throws IOException If there is an error initializing the stream. */ public PDFXrefStreamParser( COSStream strm, COSDocument doc, boolean forceParsing, XrefTrailerResolver resolver ) throws IOException { super(strm.getUnfilteredStream(), forceParsing); setDocument(doc); stream = strm; this.xrefTrailerResolver = resolver; } /** * Parses through the unfiltered stream and populates the xrefTable HashMap. * @throws IOException If there is an error while parsing the stream. */ public void parse() throws IOException { try { COSArray xrefFormat = (COSArray)stream.getDictionaryObject(COSName.W); COSArray indexArray = (COSArray)stream.getDictionaryObject(COSName.INDEX); /* * If Index doesn't exist, we will use the default values. */ if(indexArray == null) { indexArray = new COSArray(); indexArray.add(COSInteger.ZERO); indexArray.add(stream.getDictionaryObject(COSName.SIZE)); } ArrayList objNums = new ArrayList(); /* * Populates objNums with all object numbers available */ Iterator indexIter = indexArray.iterator(); while(indexIter.hasNext()) { int objID = ((COSInteger)indexIter.next()).intValue(); int size = ((COSInteger)indexIter.next()).intValue(); for(int i = 0; i < size; i++) { objNums.add(new Integer(objID + i)); } } Iterator objIter = objNums.iterator(); /* * Calculating the size of the line in bytes */ int w0 = xrefFormat.getInt(0); int w1 = xrefFormat.getInt(1); int w2 = xrefFormat.getInt(2); int lineSize = w0 + w1 + w2; while(pdfSource.available() > 0 && objIter.hasNext()) { byte[] currLine = new byte[lineSize]; pdfSource.read(currLine); int type; if (w0 == 0) { // "If the first element is zero, // the type field shall not be present, and shall default to type 1" type = 1; } else { type = 0; /* * Grabs the number of bytes specified for the first column in * the W array and stores it. */ for (int i = 0; i < w0; i++) { type += (currLine[i] & 0x00ff) << ((w0 - i - 1) * 8); } } //Need to remember the current objID Integer objID = objIter.next(); /* * 3 different types of entries. */ switch(type) { case 0: /* * Skipping free objects */ break; case 1: int offset = 0; for(int i = 0; i < w1; i++) { offset += (currLine[i + w0] & 0x00ff) << ((w1 - i - 1) * 8); } int genNum = 0; for(int i = 0; i < w2; i++) { genNum += (currLine[i + w0 + w1] & 0x00ff) << ((w2 - i - 1) * 8); } COSObjectKey objKey = new COSObjectKey(objID.intValue(), genNum); xrefTrailerResolver.setXRef(objKey, offset); break; case 2: /* * object stored in object stream; 2nd argument is object number of object stream; * 3rd argument index of object within object stream * * For sequential PDFParser we do not need this information * because * These objects are handled by the dereferenceObjects() method * since they're only pointing to object numbers * * However for XRef aware parsers we have to know which objects contain * object streams. We will store this information in normal xref mapping * table but add object stream number with minus sign in order to * distinguish from file offsets */ int objstmObjNr = 0; for(int i = 0; i < w1; i++) { objstmObjNr += (currLine[i + w0] & 0x00ff) << ((w1 - i - 1) * 8); } objKey = new COSObjectKey( objID.intValue(), 0 ); xrefTrailerResolver.setXRef( objKey, -objstmObjNr ); break; default: break; } } } finally { pdfSource.close(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/0000755000000000000000000000000012645757432021420 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessBuffer.java0000644000000000000000000002402212645757432025757 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; /** * An implementation of the RandomAccess interface to store a pdf in memory. * The data will be stored in 16kb chunks organized in an ArrayList. * */ public class RandomAccessBuffer implements RandomAccess, Closeable { // chunk size is 16kb private static final int BUFFER_SIZE = 16384; // list containing all chunks private ArrayList bufferList = null; // current chunk private byte[] currentBuffer; // current pointer to the whole buffer private long pointer; // current pointer for the current chunk private long currentBufferPointer; // size of the whole buffer private long size; // current chunk list index private int bufferListIndex; // maximum chunk list index private int bufferListMaxIndex; /** * Default constructor. */ public RandomAccessBuffer() { // starting with one chunk bufferList = new ArrayList(); currentBuffer = new byte[BUFFER_SIZE]; bufferList.add(currentBuffer); pointer = 0; currentBufferPointer = 0; size = 0; bufferListIndex = 0; bufferListMaxIndex = 0; } @Override public RandomAccessBuffer clone() { RandomAccessBuffer copy = new RandomAccessBuffer(); copy.bufferList = new ArrayList(bufferList.size()); for (byte [] buffer : bufferList) { byte [] newBuffer = new byte [buffer.length]; System.arraycopy(buffer,0,newBuffer,0,buffer.length); copy.bufferList.add(newBuffer); } if (currentBuffer!=null) { copy.currentBuffer = copy.bufferList.get(copy.bufferList.size()-1); } else { copy.currentBuffer = null; } copy.pointer = pointer; copy.currentBufferPointer = currentBufferPointer; copy.size = size; copy.bufferListIndex = bufferListIndex; copy.bufferListMaxIndex = bufferListMaxIndex; return copy; } /** * {@inheritDoc} */ public void close() throws IOException { currentBuffer = null; bufferList.clear(); pointer = 0; currentBufferPointer = 0; size = 0; bufferListIndex = 0; } /** * {@inheritDoc} */ public void seek(long position) throws IOException { checkClosed(); pointer = position; // calculate the chunk list index bufferListIndex = (int)(position / BUFFER_SIZE); currentBufferPointer = position % BUFFER_SIZE; currentBuffer = bufferList.get(bufferListIndex); } /** * {@inheritDoc} */ public long getPosition() throws IOException { checkClosed(); return pointer; } /** * {@inheritDoc} */ public int read() throws IOException { checkClosed(); if (pointer >= this.size) { return -1; } if (currentBufferPointer >= BUFFER_SIZE) { if (bufferListIndex >= bufferListMaxIndex) { return -1; } else { currentBuffer = bufferList.get(++bufferListIndex); currentBufferPointer = 0; } } pointer++; return currentBuffer[(int)currentBufferPointer++] & 0xff; } /** * {@inheritDoc} */ public int read(byte[] b, int offset, int length) throws IOException { checkClosed(); if (pointer >= this.size) { return 0; } int maxLength = (int) Math.min(length, this.size-pointer); long remainingBytes = BUFFER_SIZE - currentBufferPointer; if (remainingBytes == 0) { nextBuffer(); remainingBytes = BUFFER_SIZE; } if (maxLength >= remainingBytes) { // copy the first bytes from the current buffer System.arraycopy(currentBuffer, (int)currentBufferPointer, b, offset, (int)remainingBytes); currentBufferPointer += remainingBytes; int newOffset = offset + (int)remainingBytes; long remainingBytes2Read = length - remainingBytes; // determine how many buffers are needed to get the remaining amount bytes int numberOfArrays = (int)remainingBytes2Read / BUFFER_SIZE; for (int i=0;i 0) { nextBuffer(); System.arraycopy(currentBuffer, 0, b, newOffset, (int)remainingBytes2Read); currentBufferPointer += remainingBytes2Read; } } else { System.arraycopy(currentBuffer, (int)currentBufferPointer, b, offset, maxLength); currentBufferPointer += maxLength; } pointer += maxLength; return maxLength; } /** * {@inheritDoc} */ public long length() throws IOException { checkClosed(); return size; } /** * {@inheritDoc} */ public void write(int b) throws IOException { checkClosed(); // end of buffer reached? if (currentBufferPointer >= BUFFER_SIZE) { if (pointer + BUFFER_SIZE >= Integer.MAX_VALUE) { throw new IOException("RandomAccessBuffer overflow"); } expandBuffer(); } currentBuffer[(int)currentBufferPointer++] = (byte)b; pointer++; if (pointer > this.size) { this.size = pointer; } // end of buffer reached now? if (currentBufferPointer >= BUFFER_SIZE) { if (pointer + BUFFER_SIZE >= Integer.MAX_VALUE) { throw new IOException("RandomAccessBuffer overflow"); } expandBuffer(); } } /** * {@inheritDoc} */ public void write(byte[] b, int offset, int length) throws IOException { checkClosed(); long newSize = pointer + length; long remainingBytes = BUFFER_SIZE - currentBufferPointer; if (length >= remainingBytes) { if (newSize > Integer.MAX_VALUE) { throw new IOException("RandomAccessBuffer overflow"); } // copy the first bytes to the current buffer System.arraycopy(b, offset, currentBuffer, (int)currentBufferPointer, (int)remainingBytes); int newOffset = offset + (int)remainingBytes; long remainingBytes2Write = length - remainingBytes; // determine how many buffers are needed for the remaining bytes int numberOfNewArrays = (int)remainingBytes2Write / BUFFER_SIZE; for (int i=0;i= 0) { expandBuffer(); if (remainingBytes2Write > 0) { System.arraycopy(b, newOffset, currentBuffer, (int)currentBufferPointer, (int)remainingBytes2Write); } currentBufferPointer = remainingBytes2Write; } } else { System.arraycopy(b, offset, currentBuffer, (int)currentBufferPointer, length); currentBufferPointer += length; } pointer += length; if (pointer > this.size) { this.size = pointer; } } /** * create a new buffer chunk and adjust all pointers and indices. */ private void expandBuffer() { if (bufferListMaxIndex > bufferListIndex) { // there is already an existing chunk nextBuffer(); } else { // create a new chunk and add it to the buffer currentBuffer = new byte[BUFFER_SIZE]; bufferList.add(currentBuffer); currentBufferPointer = 0; bufferListMaxIndex++; bufferListIndex++; } } /** * switch to the next buffer chunk and reset the buffer pointer. */ private void nextBuffer() { currentBufferPointer = 0; currentBuffer = bufferList.get(++bufferListIndex); } /** * Ensure that the RandomAccessBuffer is not closed * @throws IOException */ private void checkClosed () throws IOException { if (currentBuffer==null) { // consider that the rab is closed if there is no current buffer throw new IOException("RandomAccessBuffer already closed"); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/IOUtils.java0000644000000000000000000001246212645757432023620 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: IOUtils.java 1328603 2012-04-21 07:44:35Z gbailleul $ */ package org.apache.pdfbox.io; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; /** * This class contains various I/O-related methods. * @version $Revision$ */ public class IOUtils { //TODO PDFBox should really use Apache Commons IO. private IOUtils() { //Utility class. Don't instantiate. } /** * Reads the input stream and returns its contents as a byte array. * @param in the input stream to read from. * @return the byte array * @throws IOException if an I/O error occurs */ public static byte[] toByteArray(InputStream in) throws IOException { ByteArrayOutputStream baout = new ByteArrayOutputStream(); copy(in, baout); return baout.toByteArray(); } /** * Copies all the contents from the given input stream to the given output stream. * @param input the input stream * @param output the output stream * @return the number of bytes that have been copied * @throws IOException if an I/O error occurs */ public static long copy(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[4096]; long count = 0; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; } /** * Populates the given buffer with data read from the input stream. If the data doesn't * fit the buffer, only the data that fits in the buffer is read. If the data is less than * fits in the buffer, the buffer is not completely filled. * @param in the input stream to read from * @param buffer the buffer to fill * @return the number of bytes written to the buffer * @throws IOException if an I/O error occurs */ public static long populateBuffer(InputStream in, byte[] buffer) throws IOException { int remaining = buffer.length; while (remaining > 0) { int bufferWritePos = buffer.length - remaining; int bytesRead = in.read(buffer, bufferWritePos, remaining); if (bytesRead < 0) { break; //EOD } remaining -= bytesRead; } return buffer.length - remaining; } /** * Unconditionally close an InputStream. *

* Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. * This is typically used in finally blocks. * * @param input the InputStream to close, may be null or already closed */ public static void closeQuietly(InputStream input) { try { if (input != null) { input.close(); } } catch (IOException ioe) { // ignore } } /** * Unconditionally close an Reader. *

* Equivalent to {@link Reader#close()}, except any exceptions will be ignored. * This is typically used in finally blocks. * * @param input the Reader to close, may be null or already closed */ public static void closeQuietly(Reader input) { try { if (input != null) { input.close(); } } catch (IOException ioe) { // ignore } } /** * Unconditionally close a Writer. *

* Equivalent to {@link Writer#close()}, except any exceptions will be ignored. * This is typically used in finally blocks. * * @param output the Writer to close, may be null or already closed */ public static void closeQuietly(Writer output) { try { if (output != null) { output.close(); } } catch (IOException ioe) { // ignore } } /** * Unconditionally close an OutputStream. *

* Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. * This is typically used in finally blocks. * * @param output the OutputStream to close, may be null or already closed */ public static void closeQuietly(OutputStream output) { try { if (output != null) { output.close(); } } catch (IOException ioe) { // ignore } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ASCII85OutputStream.java0000644000000000000000000001357112645757432025674 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; /** * This class represents an ASCII85 output stream. * * @author Ben Litchfield * */ public class ASCII85OutputStream extends FilterOutputStream { private int lineBreak; private int count; private byte[] indata; private byte[] outdata; /** * Function produces five ASCII printing characters from * four bytes of binary data. */ private int maxline; private boolean flushed; private char terminator; private static final char OFFSET = '!'; private static final char NEWLINE = '\n'; private static final char Z = 'z'; /** * Constructor. * * @param out The output stream to write to. */ public ASCII85OutputStream(OutputStream out) { super(out); lineBreak = 36 * 2; maxline = 36 * 2; count = 0; indata = new byte[4]; outdata = new byte[5]; flushed = true; terminator = '~'; } /** * This will set the terminating character. * * @param term The terminating character. */ public void setTerminator(char term) { if (term < 118 || term > 126 || term == Z) { throw new IllegalArgumentException("Terminator must be 118-126 excluding z"); } terminator = term; } /** * This will get the terminating character. * * @return The terminating character. */ public char getTerminator() { return terminator; } /** * This will set the line length that will be used. * * @param l The length of the line to use. */ public void setLineLength(int l) { if (lineBreak > l) { lineBreak = l; } maxline = l; } /** * This will get the length of the line. * * @return The line length attribute. */ public int getLineLength() { return maxline; } /** * This will transform the next four ascii bytes. */ private final void transformASCII85() { long word = ((((indata[0] << 8) | (indata[1] & 0xFF)) << 16) | ((indata[2] & 0xFF) << 8) | (indata[3] & 0xFF)) & 0xFFFFFFFFL; if (word == 0) { outdata[0] = (byte) Z; outdata[1] = 0; return; } long x; x = word / (85L * 85L * 85L * 85L); outdata[0] = (byte) (x + OFFSET); word -= x * 85L * 85L * 85L * 85L; x = word / (85L * 85L * 85L); outdata[1] = (byte) (x + OFFSET); word -= x * 85L * 85L * 85L; x = word / (85L * 85L); outdata[2] = (byte) (x + OFFSET); word -= x * 85L * 85L; x = word / 85L; outdata[3] = (byte) (x + OFFSET); outdata[4] = (byte) ((word % 85L) + OFFSET); } /** * This will write a single byte. * * @param b The byte to write. * * @throws IOException If there is an error writing to the stream. */ public final void write(int b) throws IOException { flushed = false; indata[count++] = (byte) b; if (count < 4) { return; } transformASCII85(); for (int i = 0; i < 5; i++) { if (outdata[i] == 0) { break; } out.write(outdata[i]); if (--lineBreak == 0) { out.write(NEWLINE); lineBreak = maxline; } } count = 0; } /** * This will flush the data to the stream. * * @throws IOException If there is an error writing the data to the stream. */ public final void flush() throws IOException { if (flushed) { return; } if (count > 0) { for (int i = count; i < 4; i++) { indata[i] = 0; } transformASCII85(); if (outdata[0] == Z) { for (int i = 0; i < 5; i++) // expand 'z', { outdata[i] = (byte) OFFSET; } } for (int i = 0; i < count + 1; i++) { out.write(outdata[i]); if (--lineBreak == 0) { out.write(NEWLINE); lineBreak = maxline; } } } if (--lineBreak == 0) { out.write(NEWLINE); } out.write(terminator); out.write(NEWLINE); count = 0; lineBreak = maxline; flushed = true; super.flush(); } /** * This will close the stream. * * @throws IOException If there is an error closing the wrapped stream. */ public void close() throws IOException { try { flush(); super.close(); } finally { indata = outdata = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccess.java0000644000000000000000000000331012645757432024622 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.IOException; /** * An interface to allow PDF files to be stored completely in memory or * to use a scratch file on the disk. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public interface RandomAccess extends RandomAccessRead { /** * Write a byte to the stream. * * @param b The byte to write. * @throws IOException If there is an IO error while writing. */ public void write(int b) throws IOException; /** * Write a buffer of data to the stream. * * @param b The buffer to get the data from. * @param offset An offset into the buffer to get the data from. * @param length The length of data to write. * @throws IOException If there is an error while writing the data. */ public void write(byte[] b, int offset, int length) throws IOException; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/SequentialRead.java0000644000000000000000000000342212645757432025172 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.IOException; /** * An interface allowing sequential read operations. */ public interface SequentialRead { /** * Release resources that are being held. * * @throws IOException If there is an error closing this resource. */ public void close() throws IOException; /** * Read a single byte of data. * * @return The byte of data that is being read. * * @throws IOException If there is an error while reading the data. */ public int read() throws IOException; /** * Read a buffer of data. * * @param b The buffer to write the data to. * @param offset Offset into the buffer to start writing. * @param length The amount of data to attempt to read. * @return The number of bytes that were actually read. * @throws IOException If there was an error while reading the data. */ public int read(byte[] b, int offset, int length) throws IOException; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessFileOutputStream.java0000644000000000000000000001005112645757432030017 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.IOException; import java.io.OutputStream; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSNumber; /** * This will write to a RandomAccessFile in the filesystem and keep track * of the position it is writing to and the length of the stream. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class RandomAccessFileOutputStream extends OutputStream { private RandomAccess file; private long position; private long lengthWritten = 0; private COSBase expectedLength = null; /** * Constructor to create an output stream that will write to the end of a * random access file. * * @param raf The file to write to. * * @throws IOException If there is a problem accessing the raf. */ public RandomAccessFileOutputStream( RandomAccess raf ) throws IOException { file = raf; //first get the position that we will be writing to position = raf.length(); } /** * This will get the position in the RAF that the stream was written * to. * * @return The position in the raf where the file can be obtained. */ public long getPosition() { return position; } /** * Get the amount of data that was actually written to the stream, in theory this * should be the same as the length specified but in some cases it doesn't match. * * @return The number of bytes actually written to this stream. */ public long getLengthWritten() { return lengthWritten; } /** * The number of bytes written or expected in the stream. * * @return The number of bytes written or expected in the stream. */ public long getLength() { long length = -1; if( expectedLength instanceof COSNumber ) { length = ((COSNumber)expectedLength).intValue(); } else if( expectedLength instanceof COSObject && ((COSObject)expectedLength).getObject() instanceof COSNumber ) { length = ((COSNumber)((COSObject)expectedLength).getObject()).intValue(); } if( length == -1 ) { length = lengthWritten; } return length; } /** * {@inheritDoc} */ public void write( byte[] b, int offset, int length ) throws IOException { file.seek( position+lengthWritten ); lengthWritten += length; file.write( b, offset, length ); } /** * {@inheritDoc} */ public void write( int b ) throws IOException { file.seek( position+lengthWritten ); lengthWritten++; file.write( b ); } /** * This will get the length that the PDF document specified this stream * should be. This may not match the number of bytes read. * * @return The expected length. */ public COSBase getExpectedLength() { return expectedLength; } /** * This will set the expected length of this stream. * * @param value The expected value. */ public void setExpectedLength(COSBase value) { expectedLength = value; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessFileInputStream.java0000644000000000000000000000647212645757432027632 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.InputStream; import java.io.IOException; /** * This class allows a section of a RandomAccessFile to be accessed as an * input stream. * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class RandomAccessFileInputStream extends InputStream { private RandomAccess file; private long currentPosition; private long endPosition; /** * Constructor. * * @param raFile The file to read the data from. * @param startPosition The position in the file that this stream starts. * @param length The length of the input stream. */ public RandomAccessFileInputStream( RandomAccess raFile, long startPosition, long length ) { file = raFile; currentPosition = startPosition; endPosition = currentPosition+length; } /** * {@inheritDoc} */ public int available() { return (int)(endPosition - currentPosition); } /** * {@inheritDoc} */ public void close() { //do nothing because we want to leave the random access file open. } /** * {@inheritDoc} */ public int read() throws IOException { synchronized(file) { int retval = -1; if( currentPosition < endPosition ) { file.seek( currentPosition ); currentPosition++; retval = file.read(); } return retval; } } /** * {@inheritDoc} */ public int read( byte[] b, int offset, int length ) throws IOException { //only allow a read of the amount available. if( length > available() ) { length = available(); } int amountRead = -1; //only read if there are bytes actually available, otherwise //return -1 if the EOF has been reached. if( available() > 0 ) { synchronized(file) { file.seek( currentPosition ); amountRead = file.read( b, offset, length ); } } //update the current cursor position. if( amountRead > 0 ) { currentPosition += amountRead; } return amountRead; } /** * {@inheritDoc} */ public long skip( long amountToSkip ) { long amountSkipped = Math.min( amountToSkip, available() ); currentPosition+= amountSkipped; return amountSkipped; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/package.html0000644000000000000000000000165712645757432023712 0ustar rootroot This package contains IO streams. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ByteArrayPushBackInputStream.java0000644000000000000000000003010012645757432027774 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * PushBackInputStream for byte arrays. * * The inheritance from PushBackInputStream is only to avoid the * introduction of an interface with all PushBackInputStream * methods. The parent PushBackInputStream is not used in any way and * all methods are overridden. (Thus when adding new methods to PushBackInputStream * override them in this class as well!) * unread() is limited to the number of bytes already read from this stream (i.e. * the current position in the array). This limitation usually poses no problem * to a parser, but allows for some optimization since only one array has to * be dealt with. * * Note: This class is not thread safe. Clients must provide synchronization * if needed. * * Note: Calling unread() after mark() will cause (part of) the unread data to be * read again after reset(). Thus do not call unread() between mark() and reset(). * * @author Andreas Weiss (andreas.weiss@switzerland.org) * @version $Revision: 1.2 $ */ public class ByteArrayPushBackInputStream extends PushBackInputStream { private byte[] data; private int datapos; private int datalen; private int save; // dummy for base class constructor private static final InputStream DUMMY = new ByteArrayInputStream("".getBytes()); /** * Constructor. * @param input Data to read from. Note that calls to unread() will * modify this array! If this is not desired, pass a copy. * * @throws IOException If there is an IO error. */ public ByteArrayPushBackInputStream(byte[] input) throws IOException { super(DUMMY, 1); data = input; datapos = 0; save = datapos; datalen = input != null ? input.length : 0; } /** * This will peek at the next byte. * * @return The next byte on the stream, leaving it as available to read. */ public int peek() { try { // convert negative values to 128..255 return (data[datapos] + 0x100) & 0xff; } catch (ArrayIndexOutOfBoundsException ex) { // could check this before, but this is a rare case // and this method is called sufficiently often to justify this // optimization return -1; } } /** * A simple test to see if we are at the end of the stream. * * @return true if we are at the end of the stream. */ public boolean isEOF() { return datapos >= datalen; } /** * Save the state of this stream. * @param readlimit Has no effect. * @see InputStream#mark(int) */ public void mark(int readlimit) { if (false) { ++readlimit; // avoid unused param warning } save = datapos; } /** * Check if mark is supported. * @return Always true. * @see InputStream#markSupported() */ public boolean markSupported() { return true; } /** * Restore the state of this stream to the last saveState call. * @see InputStream#reset() */ public void reset() { datapos = save; } /** Available bytes. * @see InputStream#available() * @return Available bytes. */ public int available() { int av = datalen - datapos; return av > 0 ? av : 0; } /** Totally available bytes in the underlying array. * @return Available bytes. */ public int size() { return datalen; } /** * Pushes back a byte. * After this method returns, the next byte to be read will have the value (byte)by. * @param by the int value whose low-order byte is to be pushed back. * @throws IOException - If there is not enough room in the buffer for the byte. * @see java.io.PushbackInputStream#unread(int) */ public void unread(int by) throws IOException { if (datapos == 0) { throw new IOException("ByteArrayParserInputStream.unread(int): " + "cannot unread 1 byte at buffer position " + datapos); } --datapos; data[datapos] = (byte)by; } /** * Pushes back a portion of an array of bytes by copying it to the * front of the pushback buffer. After this method returns, the next byte * to be read will have the value b[off], the byte after that will have * the value b[off+1], and so forth. * @param buffer the byte array to push back. * @param off the start offset of the data. * @param len the number of bytes to push back. * @throws IOException If there is not enough room in the pushback buffer * for the specified number of bytes. * @see java.io.PushbackInputStream#unread(byte[], int, int) */ public void unread(byte[] buffer, int off, int len) throws IOException { if (len <= 0 || off >= buffer.length) { return; } if (off < 0) { off = 0; } if (len > buffer.length) { len = buffer.length; } localUnread(buffer, off, len); } /** * Pushes back a portion of an array of bytes by copying it to the * front of the pushback buffer. After this method returns, the next byte * to be read will have the value buffer[0], the byte after that will have * the value buffer[1], and so forth. * @param buffer the byte array to push back. * @throws IOException If there is not enough room in the pushback buffer * for the specified number of bytes. * @see java.io.PushbackInputStream#unread(byte[]) */ public void unread(byte[] buffer) throws IOException { localUnread(buffer, 0, buffer.length); } /** * Pushes back a portion of an array of bytes by copying it to the * front of the pushback buffer. After this method returns, the next byte * to be read will have the value buffer[off], the byte after that will have * the value buffer[off+1], and so forth. * Internal method that assumes off and len to be valid. * @param buffer the byte array to push back. * @param off the start offset of the data. * @param len the number of bytes to push back. * @throws IOException If there is not enough room in the pushback buffer * for the specified number of bytes. * @see java.io.PushbackInputStream#unread(byte[], int, int) */ private void localUnread(byte[] buffer, int off, int len) throws IOException { if (datapos < len) { throw new IOException("ByteArrayParserInputStream.unread(int): " + "cannot unread " + len + " bytes at buffer position " + datapos); } datapos -= len; System.arraycopy(buffer, off, data, datapos, len); } /** * Read a byte. * @see InputStream#read() * @return Byte read or -1 if no more bytes are available. */ public int read() { try { // convert negative values to 128..255 return (data[datapos++] + 0x100) & 0xff; } catch (ArrayIndexOutOfBoundsException ex) { // could check this before, but this is a rare case // and this method is called sufficiently often to justify this // optimization datapos = datalen; return -1; } } /** * Read a number of bytes. * @see InputStream#read(byte[]) * @param buffer the buffer into which the data is read. * @return the total number of bytes read into the buffer, or -1 if there * is no more data because the end of the stream has been reached. */ public int read(byte[] buffer) { return localRead(buffer, 0, buffer.length); } /** * Read a number of bytes. * @see InputStream#read(byte[], int, int) * @param buffer the buffer into which the data is read. * @param off the start offset in array buffer at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or -1 if there * is no more data because the end of the stream has been reached. */ public int read(byte[] buffer, int off, int len) { if (len <= 0 || off >= buffer.length) { return 0; } if (off < 0) { off = 0; } if (len > buffer.length) { len = buffer.length; } return localRead(buffer, off, len); } /** * Read a number of bytes. Internal method that assumes off and len to be * valid. * @see InputStream#read(byte[], int, int) * @param buffer the buffer into which the data is read. * @param off the start offset in array buffer at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or -1 if there * is no more data because the end of the stream has been reached. */ public int localRead(byte[] buffer, int off, int len) { if (len == 0) { return 0; // must return 0 even if at end! } else if (datapos >= datalen) { return -1; } else { int newpos = datapos + len; if (newpos > datalen) { newpos = datalen; len = newpos - datapos; } System.arraycopy(data, datapos, buffer, off, len); datapos = newpos; return len; } } /** * Skips over and discards n bytes of data from this input stream. * The skip method may, for a variety of reasons, end up skipping over some * smaller number of bytes, possibly 0. This may result from any of a number * of conditions; reaching end of file before n bytes have been skipped is * only one possibility. The actual number of bytes skipped is returned. * If n is negative, no bytes are skipped. * @param num the number of bytes to be skipped. * @return the actual number of bytes skipped. * @see InputStream#skip(long) */ public long skip(long num) { if (num <= 0) { return 0; } else { long newpos = datapos + num; if (newpos >= datalen) { num = datalen - datapos; datapos = datalen; } else { datapos = (int)newpos; } return num; } } /** Position the stream at a given index. Positioning the stream * at position size() will cause the next call to read() to return -1. * * @param newpos Position in the underlying array. A negative value will be * interpreted as 0, a value greater than size() as size(). * @return old position. */ public int seek(int newpos) { if (newpos < 0) { newpos = 0; } else if (newpos > datalen) { newpos = datalen; } int oldpos = pos; pos = newpos; return oldpos; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessRead.java0000644000000000000000000000350512645757432025424 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.IOException; /** * An interface allowing random access read operations. */ public interface RandomAccessRead extends SequentialRead { /** * Returns offset of next byte to be returned by a read method. * * @return offset of next byte which will be returned with next {@link #read()} * (if no more bytes are left it returns a value >= length of source) * * @throws IOException */ public long getPosition() throws IOException; /** * Seek to a position in the data. * * @param position The position to seek to. * @throws IOException If there is an error while seeking. */ public void seek(long position) throws IOException; /** * The total number of bytes that are available. * * @return The number of bytes available. * * @throws IOException If there is an IO error while determining the * length of the data stream. */ public long length() throws IOException; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ASCII85InputStream.java0000644000000000000000000001551012645757432025466 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * This class represents an ASCII85 stream. * * @author Ben Litchfield * */ public class ASCII85InputStream extends FilterInputStream { private int index; private int n; private boolean eof; private byte[] ascii; private byte[] b; private static final char TERMINATOR = '~'; private static final char OFFSET = '!'; private static final char NEWLINE = '\n'; private static final char RETURN = '\r'; private static final char SPACE = ' '; private static final char PADDING_U = 'u'; private static final char Z = 'z'; /** * Constructor. * * @param is The input stream to actually read from. */ public ASCII85InputStream(InputStream is) { super(is); index = 0; n = 0; eof = false; ascii = new byte[5]; b = new byte[4]; } /** * This will read the next byte from the stream. * * @return The next byte read from the stream. * * @throws IOException If there is an error reading from the wrapped stream. */ public final int read() throws IOException { if (index >= n) { if (eof) { return -1; } index = 0; int k; byte z; do { int zz = (byte) in.read(); if (zz == -1) { eof = true; return -1; } z = (byte) zz; } while (z == NEWLINE || z == RETURN || z == SPACE); if (z == TERMINATOR) { eof = true; ascii = b = null; n = 0; return -1; } else if (z == Z) { b[0] = b[1] = b[2] = b[3] = 0; n = 4; } else { ascii[0] = z; // may be EOF here.... for (k = 1; k < 5; ++k) { do { int zz = (byte) in.read(); if (zz == -1) { eof = true; return -1; } z = (byte) zz; } while (z == NEWLINE || z == RETURN || z == SPACE); ascii[k] = z; if (z == TERMINATOR) { // don't include ~ as padding byte ascii[k] = (byte) PADDING_U; break; } } n = k - 1; if (n == 0) { eof = true; ascii = null; b = null; return -1; } if (k < 5) { for (++k; k < 5; ++k) { // use 'u' for padding ascii[k] = (byte) PADDING_U; } eof = true; } // decode stream long t = 0; for (k = 0; k < 5; ++k) { z = (byte) (ascii[k] - OFFSET); if (z < 0 || z > 93) { n = 0; eof = true; ascii = null; b = null; throw new IOException("Invalid data in Ascii85 stream"); } t = (t * 85L) + z; } for (k = 3; k >= 0; --k) { b[k] = (byte) (t & 0xFFL); t >>>= 8; } } } return b[index++] & 0xFF; } /** * This will read a chunk of data. * * @param data The buffer to write data to. * @param offset The offset into the data stream. * @param len The number of byte to attempt to read. * * @return The number of bytes actually read. * * @throws IOException If there is an error reading data from the underlying stream. */ public final int read(byte[] data, int offset, int len) throws IOException { if (eof && index >= n) { return -1; } for (int i = 0; i < len; i++) { if (index < n) { data[i + offset] = b[index++]; } else { int t = read(); if (t == -1) { return i; } data[i + offset] = (byte) t; } } return len; } /** * This will close the underlying stream and release any resources. * * @throws IOException If there is an error closing the underlying stream. */ public void close() throws IOException { ascii = null; eof = true; b = null; super.close(); } /** * non supported interface methods. * * @return False always. */ public boolean markSupported() { return false; } /** * Unsupported. * * @param nValue ignored. * * @return Always zero. */ public long skip(long nValue) { return 0; } /** * Unsupported. * * @return Always zero. */ public int available() { return 0; } /** * Unsupported. * * @param readlimit ignored. */ public void mark(int readlimit) { } /** * Unsupported. * * @throws IOException telling that this is an unsupported action. */ public void reset() throws IOException { throw new IOException("Reset is not supported"); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/FastByteArrayOutputStream.java0000644000000000000000000000274612645757432027411 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.ByteArrayOutputStream; /** * An byte array output stream that allows direct access to the byte array. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class FastByteArrayOutputStream extends ByteArrayOutputStream { /** * Constructor. * * @param size An initial size of the stream. */ public FastByteArrayOutputStream( int size ) { super( size ); } /** * This will get the underlying byte array. * * @return The underlying byte array at this moment in time. */ public byte[] getByteArray() { return buf; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessBufferedFileInputStream.java0000644000000000000000000001703212645757432031267 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.util.LinkedHashMap; import java.util.Map; /** * Provides {@link InputStream} access to portions of a file combined with * buffered reading of content. Start of next bytes to read can be set via seek * method. * * File is accessed via {@link RandomAccessFile} and is read in byte chunks * which are cached. * * @author Timo Boehme (timo.boehme at ontochem com) */ public class RandomAccessBufferedFileInputStream extends InputStream implements RandomAccessRead { private int pageSizeShift = 12; private int pageSize = 1 << pageSizeShift; private long pageOffsetMask = -1L << pageSizeShift; private int maxCachedPages = 1000; private byte[] lastRemovedCachePage = null; /** Create a LRU page cache. */ private final LinkedHashMap pageCache = new LinkedHashMap( maxCachedPages, 0.75f, true ) { private static final long serialVersionUID = -6302488539257741101L; @Override protected boolean removeEldestEntry( Map.Entry _eldest ) { final boolean doRemove = size() > maxCachedPages; if (doRemove) { lastRemovedCachePage = _eldest.getValue(); } return doRemove; } }; private long curPageOffset = -1; private byte[] curPage = new byte[pageSize]; private int offsetWithinPage = 0; private final RandomAccessFile raFile; private final long fileLength; private long fileOffset = 0; // ------------------------------------------------------------------------ /** Create input stream instance for given file. */ public RandomAccessBufferedFileInputStream( File _file ) throws FileNotFoundException, IOException { raFile = new RandomAccessFile(_file, "r"); fileLength = _file.length(); seek(0); } // ------------------------------------------------------------------------ /** * Returns offset in file at which next byte would be read. * * @deprecated use {@link #getPosition()} instead */ public long getFilePointer() { return fileOffset; } // ------------------------------------------------------------------------ /** Returns offset in file at which next byte would be read. */ public long getPosition() { return fileOffset; } // ------------------------------------------------------------------------ /** * Seeks to new position. If new position is outside of current page the new * page is either taken from cache or read from file and added to cache. */ public void seek( final long newOffset ) throws IOException { final long newPageOffset = newOffset & pageOffsetMask; if ( newPageOffset != curPageOffset ) { byte[] newPage = pageCache.get( newPageOffset ); if ( newPage == null ) { raFile.seek( newPageOffset ); newPage = readPage(); pageCache.put( newPageOffset, newPage ); } curPageOffset = newPageOffset; curPage = newPage; } offsetWithinPage = (int) ( newOffset - curPageOffset ); fileOffset = newOffset; } // ------------------------------------------------------------------------ /** * Reads a page with data from current file position. If we have a * previously removed page from cache the buffer of this page is reused. * Otherwise a new byte buffer is created. */ private final byte[] readPage() throws IOException { byte[] page; if ( lastRemovedCachePage != null ) { page = lastRemovedCachePage; lastRemovedCachePage = null; } else { page = new byte[pageSize]; } int readBytes = 0; while ( readBytes < pageSize ) { int curBytesRead = raFile.read( page, readBytes, pageSize - readBytes); if (curBytesRead < 0) { // EOF break; } readBytes += curBytesRead; } return page; } // ------------------------------------------------------------------------ @Override public int read() throws IOException { if ( fileOffset >= fileLength ) { return -1; } if ( offsetWithinPage == pageSize ) { seek( fileOffset ); } fileOffset++; return curPage[offsetWithinPage++] & 0xff; } // ------------------------------------------------------------------------ @Override public int read( byte[] b, int off, int len ) throws IOException { if ( fileOffset >= fileLength ) { return -1; } if ( offsetWithinPage == pageSize ) { seek( fileOffset ); } int commonLen = Math.min( pageSize - offsetWithinPage, len ); if ( ( fileLength - fileOffset ) < pageSize ) commonLen = Math.min( commonLen, (int) ( fileLength - fileOffset ) ); System.arraycopy( curPage, offsetWithinPage, b, off, commonLen ); offsetWithinPage += commonLen; fileOffset += commonLen; return commonLen; } // ------------------------------------------------------------------------ @Override public int available() throws IOException { return (int) Math.min( fileLength - fileOffset, Integer.MAX_VALUE ); } // ------------------------------------------------------------------------ @Override public long skip( long n ) throws IOException { // test if we have to reduce skip count because of EOF long toSkip = n; if ( fileLength - fileOffset < toSkip ) { toSkip = fileLength - fileOffset; } if ( ( toSkip < pageSize ) && ( ( offsetWithinPage + toSkip ) <= pageSize ) ) { // we can skip within current page offsetWithinPage += toSkip; fileOffset += toSkip; } else { // seek to the page we will get after skipping seek( fileOffset + toSkip ); } return toSkip; } // ------------------------------------------------------------------------ public long length() throws IOException { return fileLength; } // ------------------------------------------------------------------------ @Override public void close() throws IOException { raFile.close(); pageCache.clear(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessFile.java0000644000000000000000000000522112645757432025425 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; /** * An interface to allow temp PDF data to be stored in a scratch * file on the disk to reduce memory consumption. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class RandomAccessFile implements RandomAccess, Closeable { private java.io.RandomAccessFile ras; /** * Constructor. * * @param file The file to write the data to. * @param mode The writing mode. * @throws FileNotFoundException If the file cannot be created. */ public RandomAccessFile(File file, String mode) throws FileNotFoundException { ras = new java.io.RandomAccessFile(file, mode); } /** * {@inheritDoc} */ public void close() throws IOException { ras.close(); } /** * {@inheritDoc} */ public void seek(long position) throws IOException { ras.seek(position); } /** * {@inheritDoc} */ public long getPosition() throws IOException { return ras.getFilePointer(); } /** * {@inheritDoc} */ public int read() throws IOException { return ras.read(); } /** * {@inheritDoc} */ public int read(byte[] b, int offset, int length) throws IOException { return ras.read(b, offset, length); } /** * {@inheritDoc} */ public long length() throws IOException { return ras.length(); } /** * {@inheritDoc} */ public void write(byte[] b, int offset, int length) throws IOException { ras.write(b, offset, length); } /** * {@inheritDoc} */ public void write(int b) throws IOException { ras.write(b); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/PushBackInputStream.java0000644000000000000000000001524312645757432026164 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.io; import java.io.InputStream; import java.io.IOException; import java.io.EOFException; /** * A simple subclass that adds a few convience methods. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class PushBackInputStream extends java.io.PushbackInputStream { /* * The current position in the file. */ private long offset = 0; /** In case provided input stream implements {@link RandomAccessRead} we hold * a typed reference to it in order to support seek operations. */ private final RandomAccessRead raInput; /** * Constructor. * * @param input The input stream. * @param size The size of the push back buffer. * * @throws IOException If there is an error with the stream. */ public PushBackInputStream( InputStream input, int size ) throws IOException { super( input, size ); if( input == null ) { throw new IOException( "Error: input was null" ); } raInput = (input instanceof RandomAccessRead) ? (RandomAccessRead) input : null; } /** * This will peek at the next byte. * * @return The next byte on the stream, leaving it as available to read. * * @throws IOException If there is an error reading the next byte. */ public int peek() throws IOException { int result = read(); if( result != -1 ) { unread( result ); } return result; } /** * Returns the current byte offset in the file. * @return the int byte offset */ public long getOffset() { return offset; } /** * {@inheritDoc} */ public int read() throws IOException { int retval = super.read(); if (retval != -1) { offset++; } return retval; } /** * {@inheritDoc} */ public int read(byte[] b) throws IOException { return this.read(b, 0, b.length); } /** * {@inheritDoc} */ public int read(byte[] b, int off, int len) throws IOException { int retval = super.read(b, off, len); if (retval != -1) { offset += retval; } return retval; } /** * {@inheritDoc} */ public void unread(int b) throws IOException { offset--; super.unread(b); } /** * {@inheritDoc} */ public void unread(byte[] b) throws IOException { this.unread(b, 0, b.length); } /** * {@inheritDoc} */ public void unread(byte[] b, int off, int len) throws IOException { if (len > 0) { offset -= len; super.unread(b, off, len); } } /** * A simple test to see if we are at the end of the stream. * * @return true if we are at the end of the stream. * * @throws IOException If there is an error reading the next byte. */ public boolean isEOF() throws IOException { int peek = peek(); return peek == -1; } /** * This is a method used to fix PDFBox issue 974661, the PDF parsing code needs * to know if there is at least x amount of data left in the stream, but the available() * method returns how much data will be available without blocking. PDFBox is willing to * block to read the data, so we will first fill the internal buffer. * * @throws IOException If there is an error filling the buffer. */ public void fillBuffer() throws IOException { int bufferLength = buf.length; byte[] tmpBuffer = new byte[bufferLength]; int amountRead = 0; int totalAmountRead = 0; while( amountRead != -1 && totalAmountRead < bufferLength ) { amountRead = this.read( tmpBuffer, totalAmountRead, bufferLength - totalAmountRead ); if( amountRead != -1 ) { totalAmountRead += amountRead; } } this.unread( tmpBuffer, 0, totalAmountRead ); } /** * Reads a given number of bytes from the underlying stream. * @param length the number of bytes to be read * @return a byte array containing the bytes just read * @throws IOException if an I/O error occurs while reading data */ public byte[] readFully(int length) throws IOException { byte[] data = new byte[length]; int pos = 0; while (pos < length) { int amountRead = read( data, pos, length - pos ); if (amountRead < 0) { throw new EOFException("Premature end of file"); } pos += amountRead; } return data; } /** Allows to seek to another position within stream in case the underlying * stream implements {@link RandomAccessRead}. Otherwise an {@link IOException} * is thrown. * * Pushback buffer is cleared before seek operation by skipping over all bytes * of buffer. * * @param newOffset new position within stream from which to read next * * @throws IOException if underlying stream does not implement {@link RandomAccessRead} * or seek operation on underlying stream was not successful */ public void seek( long newOffset ) throws IOException { if (raInput == null) { throw new IOException("Provided stream of type " + in.getClass().getSimpleName() + " is not seekable."); } // clear unread buffer by skipping over all bytes of buffer int unreadLength = buf.length - pos; if (unreadLength > 0) { skip(unreadLength); } raInput.seek(newOffset); offset = newOffset; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ccitt/0000755000000000000000000000000012645757432022526 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ccitt/FillOrderChangeInputStream.java0000644000000000000000000000764012645757432030564 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: FillOrderChangeInputStream.java 1156213 2011-08-10 15:06:20Z jeremias $ */ package org.apache.pdfbox.io.ccitt; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * This filtering input stream does a fill order change required for certain TIFF images. * @version $Revision$ */ public class FillOrderChangeInputStream extends FilterInputStream { /** * Main constructor. * @param in the underlying input stream */ public FillOrderChangeInputStream(InputStream in) { super(in); } /** {@inheritDoc} */ public int read(byte[] b, int off, int len) throws IOException { int result = super.read(b, off, len); if (result > 0) { int endpos = off + result; for (int i = off; i < endpos; i++) { b[i] = FLIP_TABLE[b[i] & 0xff]; } } return result; } /** {@inheritDoc} */ public int read() throws IOException { int b = super.read(); if (b < 0) { return b; } else { return FLIP_TABLE[b] & 0xff; } } // Table to be used when fillOrder = 2, for flipping bytes. // Copied from the TIFFFaxDecoder class private static final byte[] FLIP_TABLE = { 0, -128, 64, -64, 32, -96, 96, -32, 16, -112, 80, -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, 24, -104, 88, -40, 56, -72, 120, -8, 4, -124, 68, -60, 36, -92, 100, -28, 20, -108, 84, -44, 52, -76, 116, -12, 12, -116, 76, -52, 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, -126, 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, 10, -118, 74, -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, 122, -6, 6, -122, 70, -58, 38, -90, 102, -26, 22, -106, 86, -42, 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, 30, -98, 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, -111, 81, -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, -23, 25, -103, 89, -39, 57, -71, 121, -7, 5, -123, 69, -59, 37, -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, -11, 13, -115, 77, -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, -125, 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, -13, 11, -117, 75, -53, 43, -85, 107, -21, 27, -101, 91, -37, 59, -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, -25, 23, -105, 87, -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, -97, 95, -33, 63, -65, 127, -1, }; // end }pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ccitt/CCITTFaxG31DDecodeInputStream.java0000644000000000000000000003353212645757432030563 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: CCITTFaxG31DDecodeInputStream.java 1581946 2014-03-26 17:13:01Z tilman $ */ package org.apache.pdfbox.io.ccitt; import java.io.IOException; import java.io.InputStream; /** * This is a CCITT Group 3 1D decoder (ITU T.4). * @version $Revision$ */ public class CCITTFaxG31DDecodeInputStream extends InputStream implements CCITTFaxConstants { private static final int CODE_WORD = 0; private static final int SIGNAL_EOD = -1; private static final int SIGNAL_EOL = -2; private InputStream source; private int columns; private int rows; private boolean encodedByteAlign; //for reading compressed bits private int bits; private int bitPos = 8; //a single decoded line (one line decoded at a time, then read byte by byte) private PackedBitArray decodedLine; private int decodedWritePos; //write position in bits (used by the decoder algorithm) private int decodedReadPos; //read position in bytes (used by the actual InputStream reading) //state private int y = -1; //Current row/line private int accumulatedRunLength; //Used for make-up codes private static final NonLeafLookupTreeNode WHITE_LOOKUP_TREE_ROOT; private static final NonLeafLookupTreeNode BLACK_LOOKUP_TREE_ROOT; static { WHITE_LOOKUP_TREE_ROOT = new NonLeafLookupTreeNode(); BLACK_LOOKUP_TREE_ROOT = new NonLeafLookupTreeNode(); buildLookupTree(); } /** * Creates a new decoder. * @param source the input stream containing the compressed data. * @param columns the number of columns * @param rows the number of rows (0 if undefined) * @param encodedByteAlign true if each encoded scan line is filled * to a byte boundary, false if not */ public CCITTFaxG31DDecodeInputStream(InputStream source, int columns, int rows, boolean encodedByteAlign) { this.source = source; this.columns = columns; this.rows = rows; this.decodedLine = new PackedBitArray(columns); this.decodedReadPos = this.decodedLine.getByteCount(); this.encodedByteAlign = encodedByteAlign; } /** * Creates a new decoder. * @param source the input stream containing the compressed data. * @param columns the number of columns * @param encodedByteAlign true if each encoded scan line is filled * to a byte boundary, false if not */ public CCITTFaxG31DDecodeInputStream(InputStream source, int columns, boolean encodedByteAlign) { this(source, columns, 0, encodedByteAlign); } /** {@inheritDoc} */ public boolean markSupported() { return false; } /** {@inheritDoc} */ public int read() throws IOException { if (this.decodedReadPos >= this.decodedLine.getByteCount()) { boolean hasLine = decodeLine(); if (!hasLine) { return -1; } } byte data = this.decodedLine.getData()[this.decodedReadPos++]; //System.out.println("Returning " + PackedBitArray.visualizeByte(data)); return data & 0xFF; } //TODO Implement the other two read methods private boolean decodeLine() throws IOException { if (encodedByteAlign && this.bitPos != 0) { readByte(); } if (this.bits < 0) { return false; //Shortcut after EOD } this.y++; //System.out.println("decodeLine " + this.y); int x = 0; if (this.rows > 0 && this.y >= this.rows) { return false; //All rows decoded, ignore further bits } this.decodedLine.clear(); this.decodedWritePos = 0; int expectRTC = 6; boolean white = true; while (x < this.columns || this.accumulatedRunLength > 0) { CodeWord code; LookupTreeNode root = white ? WHITE_LOOKUP_TREE_ROOT : BLACK_LOOKUP_TREE_ROOT; code = root.getNextCodeWord(this); if (code == null) { //no more code words (EOD) if (x > 0) { //Have last line this.decodedReadPos = 0; return true; } else { return false; } } else if (code.getType() == SIGNAL_EOL) { expectRTC--; if (expectRTC == 0) { //System.out.println("Return to Control"); return false; //Return to Control = End Of Data } if (x == 0) { //System.out.println("Ignoring leading EOL"); continue; //Ignore leading EOL } } else { expectRTC = -1; x += code.execute(this); if (this.accumulatedRunLength == 0) { //Only switch if not using make-up codes white = !white; } } } this.decodedReadPos = 0; return true; } private void writeRun(int bit, int length) { this.accumulatedRunLength += length; //System.out.println(" Run " + bit + " for " + this.accumulatedRunLength + " at " + decodedWritePos); if (bit != 0) { this.decodedLine.setBits(this.decodedWritePos, this.accumulatedRunLength); } this.decodedWritePos += this.accumulatedRunLength; this.accumulatedRunLength = 0; } private void writeNonTerminating(int length) { //System.out.println(" Make up code for " + length + " bits"); this.accumulatedRunLength += length; } private static final int[] BIT_POS_MASKS = new int[] {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; private int readBit() throws IOException { if (this.bitPos >= 8) { readByte(); if (this.bits < 0) { return SIGNAL_EOD; } } final int bit = (this.bits & BIT_POS_MASKS[this.bitPos++]) == 0 ? 0 : 1; //System.out.print(bit); return bit; } private void readByte() throws IOException { this.bits = this.source.read(); this.bitPos = 0; } private static final short EOL_STARTER = 0x0B00; private static void buildLookupTree() { buildUpTerminating(WHITE_TERMINATING, WHITE_LOOKUP_TREE_ROOT, true); buildUpTerminating(BLACK_TERMINATING, BLACK_LOOKUP_TREE_ROOT, false); buildUpMakeUp(WHITE_MAKE_UP, WHITE_LOOKUP_TREE_ROOT); buildUpMakeUp(BLACK_MAKE_UP, BLACK_LOOKUP_TREE_ROOT); buildUpMakeUpLong(LONG_MAKE_UP, WHITE_LOOKUP_TREE_ROOT); buildUpMakeUpLong(LONG_MAKE_UP, BLACK_LOOKUP_TREE_ROOT); LookupTreeNode eolNode = new EndOfLineTreeNode(); addLookupTreeNode(EOL_STARTER, WHITE_LOOKUP_TREE_ROOT, eolNode); addLookupTreeNode(EOL_STARTER, BLACK_LOOKUP_TREE_ROOT, eolNode); } private static void buildUpTerminating(short[] codes, NonLeafLookupTreeNode root, boolean white) { for (int len = 0, c = codes.length; len < c; len++) { LookupTreeNode leaf = new RunLengthTreeNode(white ? 0 : 1, len); addLookupTreeNode(codes[len], root, leaf); } } private static void buildUpMakeUp(short[] codes, NonLeafLookupTreeNode root) { for (int len = 0, c = codes.length; len < c; len++) { LookupTreeNode leaf = new MakeUpTreeNode((len + 1) * 64); addLookupTreeNode(codes[len], root, leaf); } } private static void buildUpMakeUpLong(short[] codes, NonLeafLookupTreeNode root) { for (int len = 0, c = codes.length; len < c; len++) { LookupTreeNode leaf = new MakeUpTreeNode((len + 28) * 64); addLookupTreeNode(codes[len], root, leaf); } } private static void addLookupTreeNode(short code, NonLeafLookupTreeNode root, LookupTreeNode leaf) { int codeLength = code >> 8; int pattern = code & 0xFF; NonLeafLookupTreeNode node = root; for (int p = codeLength - 1; p > 0; p--) { int bit = (pattern >> p) & 0x01; LookupTreeNode child = node.get(bit); if (child == null) { child = new NonLeafLookupTreeNode(); node.set(bit, child); } if (child instanceof NonLeafLookupTreeNode) { node = (NonLeafLookupTreeNode)child; } else { throw new IllegalStateException("NonLeafLookupTreeNode expected, was " + child.getClass().getName()); } } int bit = pattern & 0x01; if (node.get(bit) != null) { throw new IllegalStateException("Two codes conflicting in lookup tree"); } node.set(bit, leaf); } /** Base class for all nodes in the lookup tree for code words. */ private abstract static class LookupTreeNode { public abstract CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException; } /** Interface for code words. */ private interface CodeWord { public abstract int getType(); public abstract int execute(CCITTFaxG31DDecodeInputStream decoder) throws IOException; } /** Non-leaf nodes that hold a child node for both the 0 and 1 cases for the lookup tree. */ private static class NonLeafLookupTreeNode extends LookupTreeNode { private LookupTreeNode zero; private LookupTreeNode one; public void set(int bit, LookupTreeNode node) { if (bit == 0) { this.zero = node; } else { this.one = node; } } public LookupTreeNode get(int bit) { return (bit == 0) ? this.zero : this.one; } public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException { int bit = decoder.readBit(); if (bit < 0) { return null; } LookupTreeNode node = get(bit); if (node != null) { return node.getNextCodeWord(decoder); } throw new IOException("Invalid code word encountered"); } } /** This node represents a run length of either 0 or 1. */ private static class RunLengthTreeNode extends LookupTreeNode implements CodeWord { private final int bit; private final int length; public RunLengthTreeNode(int bit, int length) { this.bit = bit; this.length = length; } public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException { return this; } public int execute(CCITTFaxG31DDecodeInputStream decoder) { decoder.writeRun(this.bit, this.length); return length; } public int getType() { return CODE_WORD; } public String toString() { return "Run Length for " + length + " bits of " + (bit == 0 ? "white" : "black"); } } /** Represents a make-up code word. */ private static class MakeUpTreeNode extends LookupTreeNode implements CodeWord { private final int length; public MakeUpTreeNode(int length) { this.length = length; } public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException { return this; } public int execute(CCITTFaxG31DDecodeInputStream decoder) throws IOException { decoder.writeNonTerminating(length); return length; } public int getType() { return CODE_WORD; } public String toString() { return "Make up code for length " + length; } } /** Represents an EOL code word. */ private static class EndOfLineTreeNode extends LookupTreeNode implements CodeWord { public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException { int bit; do { bit = decoder.readBit(); } while (bit == 0); //bit 1 finishes the EOL, any number of bit 0 allowed as fillers if (bit < 0) { return null; } return this; } public int execute(CCITTFaxG31DDecodeInputStream decoder) throws IOException { //nop return 0; } public int getType() { return SIGNAL_EOL; } public String toString() { return "EOL"; } } }pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ccitt/package.html0000644000000000000000000000201712645757432025007 0ustar rootroot This package contains CCITT encoders and decoders. This refers to the ITU T.4 (Group 3 Fax) and T.6 (Group 4 Fax) specifications. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ccitt/CCITTFaxConstants.java0000644000000000000000000000742512645757432026603 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: CCITTFaxConstants.java 1156213 2011-08-10 15:06:20Z jeremias $ */ package org.apache.pdfbox.io.ccitt; /** * Constants for CCITT Fax Filter. * @version $Revision$ */ public interface CCITTFaxConstants { /** A constant for group 3 1D encoding (ITU T.4). */ int COMPRESSION_GROUP3_1D = 0; /** A constant for group 3 2D encoding (ITU T.4). */ int COMPRESSION_GROUP3_2D = 1; /** A constant for group 4 2D encoding (ITU T.6). */ int COMPRESSION_GROUP4_2D = 2; //Format: First 8 bits: length of pattern, Second 8 bits: pattern /** The white terminating code words. */ public static final short[] WHITE_TERMINATING = new short[] { 0x0835, 0x0607, 0x0407, 0x0408, 0x040B, 0x040C, 0x040E, 0x040F, 0x0513, 0x0514, 0x0507, 0x0508, 0x0608, 0x0603, 0x0634, 0x0635, 0x062A, 0x062B, 0x0727, 0x070C, 0x0708, 0x0717, 0x0703, 0x0704, 0x0728, 0x072B, 0x0713, 0x0724, 0x0718, 0x0802, 0x0803, 0x081A, 0x081B, 0x0812, 0x0813, 0x0814, 0x0815, 0x0816, 0x0817, 0x0828, 0x0829, 0x082A, 0x082B, 0x082C, 0x082D, 0x0804, 0x0805, 0x080A, 0x080B, 0x0852, 0x0853, 0x0854, 0x0855, 0x0824, 0x0825, 0x0858, 0x0859, 0x085A, 0x085B, 0x084A, 0x084B, 0x0832, 0x0833, 0x0834}; /** The black terminating code words. */ public static final short[] BLACK_TERMINATING = new short[] { 0x0A37, 0x0302, 0x0203, 0x0202, 0x0303, 0x0403, 0x0402, 0x0503, 0x0605, 0x0604, 0x0704, 0x0705, 0x0707, 0x0804, 0x0807, 0x0918, 0x0A17, 0x0A18, 0x0A08, 0x0B67, 0x0B68, 0x0B6C, 0x0B37, 0x0B28, 0x0B17, 0x0B18, 0x0CCA, 0x0CCB, 0x0CCC, 0x0CCD, 0x0C68, 0x0C69, 0x0C6A, 0x0C6B, 0x0CD2, 0x0CD3, 0x0CD4, 0x0CD5, 0x0CD6, 0x0CD7, 0x0C6C, 0x0C6D, 0x0CDA, 0x0CDB, 0x0C54, 0x0C55, 0x0C56, 0x0C57, 0x0C64, 0x0C65, 0x0C52, 0x0C53, 0x0C24, 0x0C37, 0x0C38, 0x0C27, 0x0C28, 0x0C58, 0x0C59, 0x0C2B, 0x0C2C, 0x0C5A, 0x0C66, 0x0C67}; /** The white make-up code words. */ public static final short[] WHITE_MAKE_UP = new short[] { 0x051B, 0x0512, 0x0617, 0x0737, 0x0836, 0x0837, 0x0864, 0x0865, 0x0868, 0x0867, 0x09CC, 0x09CD, 0x09D2, 0x09D3, 0x09D4, 0x09D5, 0x09D6, 0x09D7, 0x09D8, 0x09D9, 0x09DA, 0x09DB, 0x0998, 0x0999, 0x099A, 0x0618, 0x099B}; /** The black make-up code words. */ public static final short[] BLACK_MAKE_UP = new short[] { 0x0A0F, 0x0CC8, 0x0CC9, 0x0C5B, 0x0C33, 0x0C34, 0x0C35, 0x0D6C, 0x0D6D, 0x0D4A, 0x0D4B, 0x0D4C, 0x0D4D, 0x0D72, 0x0D73, 0x0D74, 0x0D75, 0x0D76, 0x0D77, 0x0D52, 0x0D53, 0x0D54, 0x0D55, 0x0D5A, 0x0D5B, 0x0D64, 0x0D65}; /** The long make-up code words. */ public static final short[] LONG_MAKE_UP = new short[] { 0x0B08, 0x0B0C, 0x0B0D, 0x0C12, 0x0C13, 0x0C14, 0x0C15, 0x0C16, 0x0C17, 0x0C1C, 0x0C1D, 0x0C1E, 0x0C1F}; /** The EOL code word. */ public static final short EOL_CODE = 0x0C01; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/io/ccitt/PackedBitArray.java0000644000000000000000000001547412645757432026231 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: PackedBitArray.java 1156213 2011-08-10 15:06:20Z jeremias $ */ package org.apache.pdfbox.io.ccitt; /** * Represents an array of bits packed in a byte array of fixed size. * @version $Revision$ */ public class PackedBitArray { private int bitCount; private byte[] data; /** * Constructs a new bit array. * @param bitCount the number of bits to maintain */ public PackedBitArray(int bitCount) { this.bitCount = bitCount; int byteCount = (bitCount + 7) / 8; this.data = new byte[byteCount]; } private int byteOffset(int offset) { return offset / 8; } private int bitOffset(int offset) { return offset % 8; } /** * Sets a bit at the given offset. * @param offset the offset */ public void set(int offset) { int byteOffset = byteOffset(offset); this.data[byteOffset] |= 1 << bitOffset(offset); } /** * Clears a bit at the given offset. * @param offset the offset */ public void clear(int offset) { int byteOffset = byteOffset(offset); int bitOffset = bitOffset(offset); this.data[byteOffset] &= ~(1 << bitOffset); } /** * Sets a run of bits at the given offset to either 1 or 0. * @param offset the offset * @param length the number of bits to set * @param bit 1 to set the bit, 0 to clear it */ public void setBits(int offset, int length, int bit) { if (bit == 0) { clearBits(offset, length); } else { setBits(offset, length); } } /** * Sets a run of bits at the given offset to either 1. * @param offset the offset * @param length the number of bits to set */ public void setBits(int offset, int length) { if (length == 0) { return; } int startBitOffset = bitOffset(offset); int firstByte = byteOffset(offset); int lastBitOffset = offset + length; if (lastBitOffset > getBitCount()) { throw new IndexOutOfBoundsException("offset + length > bit count"); } int lastByte = byteOffset(lastBitOffset); int endBitOffset = bitOffset(lastBitOffset); if (firstByte == lastByte) { //Only one byte affected int mask = (1 << endBitOffset) - (1 << startBitOffset); this.data[firstByte] |= mask; } else { //Bits spanning multiple bytes this.data[firstByte] |= 0xFF << startBitOffset; for (int i = firstByte + 1; i < lastByte; i++) { this.data[i] = (byte)0xFF; } if (endBitOffset > 0) { this.data[lastByte] |= 0xFF >> (8 - endBitOffset); } } } /** * Clears a run of bits at the given offset. * @param offset the offset * @param length the number of bits to clear */ public void clearBits(int offset, int length) { if (length == 0) { return; } int startBitOffset = offset % 8; int firstByte = byteOffset(offset); int lastBitOffset = offset + length; int lastByte = byteOffset(lastBitOffset); int endBitOffset = lastBitOffset % 8; if (firstByte == lastByte) { //Only one byte affected int mask = (1 << endBitOffset) - (1 << startBitOffset); this.data[firstByte] &= ~mask; } else { //Bits spanning multiple bytes this.data[firstByte] &= ~(0xFF << startBitOffset); for (int i = firstByte + 1; i < lastByte; i++) { this.data[i] = (byte)0x00; } if (endBitOffset > 0) { this.data[lastByte] &= ~(0xFF >> (8 - endBitOffset)); } } } /** * Clear all bits in the array. */ public void clear() { clearBits(0, getBitCount()); } /** * Returns the number of bits maintained by this array. * @return the number of bits */ public int getBitCount() { return this.bitCount; } /** * Returns the size of the byte buffer for this array. * @return the size of the byte buffer */ public int getByteCount() { return this.data.length; } /** * Returns the underlying byte buffer. *

* Note: the actual buffer is returned. If it's manipulated * the content of the bit array changes. * @return the underlying data buffer */ public byte[] getData() { return this.data; } /** {@inheritDoc} */ public String toString() { return toBitString(this.data).substring(0, this.bitCount); } /** * Converts a byte to a "binary" String of 0s and 1s. * @param data the value to convert * @return the binary string */ public static String toBitString(byte data) { byte[] buf = new byte[] {data}; return toBitString(buf); } /** * Converts a series of bytes to a "binary" String of 0s and 1s. * @param data the data * @return the binary string */ public static String toBitString(byte[] data) { return toBitString(data, 0, data.length); } /** * Converts a series of bytes to a "binary" String of 0s and 1s. * @param data the data * @param start the start offset * @param len the number of bytes to convert * @return the binary string */ public static String toBitString(byte[] data, int start, int len) { StringBuffer sb = new StringBuffer(); for (int x = start, end = start + len; x < end; x++) { for (int i = 0; i < 8; i++) { int mask = 1 << i; int value = data[x] & mask; sb.append(value != 0 ? '1' : '0'); } } return sb.toString(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/PDFBox.java0000644000000000000000000001221112645757432022733 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox; /** * Simple wrapper around all the command line utilities included in PDFBox. * Used as the main class in the runnable standalone PDFBox jar. * * @see PDFBOX-687 */ public class PDFBox { /** * Main method. * * @param args command line arguments */ public static void main(String[] args) { if (args.length > 0) { String command = args[0]; String[] arguments = new String[args.length - 1]; System.arraycopy(args, 1, arguments, 0, arguments.length); boolean exitAfterCallingMain = true; try { if (command.equals("ConvertColorspace")) { ConvertColorspace.main(arguments); } else if (command.equals("Decrypt")) { Decrypt.main(arguments); } else if (command.equals("Encrypt")) { Encrypt.main(arguments); } else if (command.equals("ExtractText")) { ExtractText.main(arguments); } else if (command.equals("ExtractImages")) { ExtractImages.main(arguments); } else if (command.equals("Overlay")) { Overlay.main(arguments); } else if (command.equals("OverlayPDF")) { OverlayPDF.main(arguments); } else if (command.equals("PrintPDF")) { PrintPDF.main(arguments); } else if (command.equals("PDFDebugger")) { PDFDebugger.main(arguments); exitAfterCallingMain = false; } else if (command.equals("PDFMerger")) { PDFMerger.main(arguments); } else if (command.equals("PDFReader")) { PDFReader.main(arguments); exitAfterCallingMain = false; } else if (command.equals("PDFSplit")) { PDFSplit.main(arguments); } else if (command.equals("PDFToImage")) { PDFToImage.main(arguments); } else if (command.equals("TextToPDF")) { TextToPDF.main(arguments); } else if (command.equals("WriteDecodedDoc")) { WriteDecodedDoc.main(arguments); } else { showMessageAndExit(); } if (exitAfterCallingMain) { System.exit(0); } } catch (Exception e) { System.err.println( command + " failed with the following exception:"); e.printStackTrace(); System.exit(1); } } else { showMessageAndExit(); } } private static void showMessageAndExit() { System.err.println("PDFBox version: \""+Version.getVersion()+ "\""); System.err.println("\nUsage: java pdfbox-app-x.y.z.jar "); System.err.println("\nPossible commands are:\n"); System.err.println(" ConvertColorspace"); System.err.println(" Decrypt"); System.err.println(" Encrypt"); System.err.println(" ExtractText"); System.err.println(" ExtractImages"); System.err.println(" Overlay"); System.err.println(" OverlayPDF"); System.err.println(" PrintPDF"); System.err.println(" PDFDebugger"); System.err.println(" PDFMerger"); System.err.println(" PDFReader"); System.err.println(" PDFSplit"); System.err.println(" PDFToImage"); System.err.println(" TextToPDF"); System.err.println(" WriteDecodedDoc"); System.exit(1); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/0000755000000000000000000000000012645757432021766 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/XMLUtil.java0000644000000000000000000000516612645757432024137 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.InputStream; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; /** * This class with handle some simple XML operations. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class XMLUtil { /** * Utility class, should not be instantiated. * */ private XMLUtil() { } /** * This will parse an XML stream and create a DOM document. * * @param is The stream to get the XML from. * @return The DOM document. * @throws IOException It there is an error creating the dom. */ public static Document parse( InputStream is ) throws IOException { try { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); return builder.parse( is ); } catch( Exception e ) { IOException thrown = new IOException( e.getMessage() ); throw thrown; } } /** * This will get the text value of an element. * * @param node The node to get the text value for. * @return The text of the node. */ public static String getNodeValue( Element node ) { String retval = ""; NodeList children = node.getChildNodes(); for( int i=0; i specificPageOverlay = new HashMap(); private Map specificPageOverlayPage = new HashMap(); private Position position = Position.BACKGROUND; private String inputFileName = null; private PDDocument inputPDFDocument = null; private String outputFilename = null; private String defaultOverlayFilename = null; private PDDocument defaultOverlay = null; private String firstPageOverlayFilename = null; private PDDocument firstPageOverlay = null; private String lastPageOverlayFilename = null; private PDDocument lastPageOverlay = null; private String allPagesOverlayFilename = null; private PDDocument allPagesOverlay = null; private String oddPageOverlayFilename = null; private PDDocument oddPageOverlay = null; private String evenPageOverlayFilename = null; private PDDocument evenPageOverlay = null; private int numberOfOverlayPages = 0; private boolean useAllOverlayPages = false; /** * This will add overlays to a documents. * * @param specificPageOverlayFile map of overlay files for specific pages * @param useNonSeqParser indicates whether the non-sequential parser is used * @throws IOException if something went wrong * @throws COSVisitorException if something went wrong when savin the pdf */ public void overlay(Map specificPageOverlayFile, boolean useNonSeqParser) throws IOException, COSVisitorException { try { loadPDFs(useNonSeqParser); for (Map.Entry e : specificPageOverlayFile.entrySet()) { PDDocument doc = loadPDF(e.getValue(), useNonSeqParser); specificPageOverlay.put(e.getKey(), doc); specificPageOverlayPage.put(e.getKey(), getLayoutPage(doc)); } PDDocumentCatalog pdfCatalog = inputPDFDocument.getDocumentCatalog(); processPages(pdfCatalog.getAllPages()); inputPDFDocument.save(outputFilename); } finally { if (inputPDFDocument != null) { inputPDFDocument.close(); } if (defaultOverlay != null) { defaultOverlay.close(); } if (firstPageOverlay != null) { firstPageOverlay.close(); } if (lastPageOverlay != null) { lastPageOverlay.close(); } if (allPagesOverlay != null) { allPagesOverlay.close(); } if (oddPageOverlay != null) { oddPageOverlay.close(); } if (evenPageOverlay != null) { evenPageOverlay.close(); } for (Map.Entry e : specificPageOverlay.entrySet()) { e.getValue().close(); } specificPageOverlay.clear(); specificPageOverlayPage.clear(); } } private void loadPDFs(boolean useNonSeqParser) throws IOException { // input PDF if (inputFileName != null) { inputPDFDocument = loadPDF(inputFileName, useNonSeqParser); } // default overlay PDF if (defaultOverlayFilename != null) { defaultOverlay = loadPDF(defaultOverlayFilename, useNonSeqParser); } if (defaultOverlay != null) { defaultOverlayPage = getLayoutPage(defaultOverlay); } // first page overlay PDF if (firstPageOverlayFilename != null) { firstPageOverlay = loadPDF(firstPageOverlayFilename, useNonSeqParser); } if (firstPageOverlay != null) { firstPageOverlayPage = getLayoutPage(firstPageOverlay); } // last page overlay PDF if (lastPageOverlayFilename != null) { lastPageOverlay = loadPDF(lastPageOverlayFilename, useNonSeqParser); } if (lastPageOverlay != null) { lastPageOverlayPage = getLayoutPage(lastPageOverlay); } // odd pages overlay PDF if (oddPageOverlayFilename != null) { oddPageOverlay = loadPDF(oddPageOverlayFilename, useNonSeqParser); } if (oddPageOverlay != null) { oddPageOverlayPage = getLayoutPage(oddPageOverlay); } // even pages overlay PDF if (evenPageOverlayFilename != null) { evenPageOverlay = loadPDF(evenPageOverlayFilename, useNonSeqParser); } if (evenPageOverlay != null) { evenPageOverlayPage = getLayoutPage(evenPageOverlay); } // all pages overlay PDF if (allPagesOverlayFilename != null) { allPagesOverlay = loadPDF(allPagesOverlayFilename, useNonSeqParser); } if (allPagesOverlay != null) { specificPageOverlayPage = getLayoutPages(allPagesOverlay); useAllOverlayPages = true; numberOfOverlayPages = specificPageOverlayPage.size(); } } private PDDocument loadPDF(String pdfName, boolean useNonSeqParser) throws IOException { PDDocument pdf = null; if (useNonSeqParser) { pdf = PDDocument.loadNonSeq(new File(pdfName), null); } else { pdf = PDDocument.load(pdfName); } return pdf; } /** * Stores the overlay page information. */ private static class LayoutPage { private final PDRectangle overlayMediaBox; private final COSStream overlayContentStream; private final COSDictionary overlayResources; private LayoutPage(PDRectangle mediaBox, COSStream contentStream, COSDictionary resources) { overlayMediaBox = mediaBox; overlayContentStream = contentStream; overlayResources = resources; } } private LayoutPage getLayoutPage(PDDocument doc) throws IOException { PDDocumentCatalog catalog = doc.getDocumentCatalog(); PDPage page = (PDPage) catalog.getAllPages().get(0); COSBase contents = page.getCOSDictionary().getDictionaryObject(COSName.CONTENTS); PDResources resources = page.findResources(); if (resources == null) { resources = new PDResources(); } return new LayoutPage(page.getMediaBox(), createContentStream(contents), resources.getCOSDictionary()); } private HashMap getLayoutPages(PDDocument doc) throws IOException { PDDocumentCatalog catalog = doc.getDocumentCatalog(); int numberOfPages = doc.getNumberOfPages(); HashMap layoutPages = new HashMap(numberOfPages); for (int i=0;i contentStreams = createContentStreamList(contents); // concatenate streams COSStream concatStream = new COSStream(new RandomAccessBuffer()); OutputStream out = concatStream.createUnfilteredStream(); for (COSStream contentStream : contentStreams) { InputStream in = contentStream.getUnfilteredStream(); byte[] buf = new byte[2048]; int n; while ((n = in.read(buf)) > 0) { out.write(buf, 0, n); } out.flush(); } out.close(); concatStream.setFilters(COSName.FLATE_DECODE); return concatStream; } private List createContentStreamList(COSBase contents) throws IOException { List contentStreams = new ArrayList(); if (contents instanceof COSStream) { contentStreams.add((COSStream) contents); } else if (contents instanceof COSArray) { for (COSBase item : (COSArray) contents) { contentStreams.addAll(createContentStreamList(item)); } } else if (contents instanceof COSObject) { contentStreams.addAll(createContentStreamList(((COSObject) contents).getObject())); } else { throw new IOException("Contents are unknown type:" + contents.getClass().getName()); } return contentStreams; } private void processPages(List pages) throws IOException { int pageCount = 0; for (PDPage page : pages) { COSDictionary pageDictionary = page.getCOSDictionary(); COSBase contents = pageDictionary.getDictionaryObject(COSName.CONTENTS); COSArray contentArray = new COSArray(); switch (position) { case FOREGROUND: // save state contentArray.add(createStream("q\n")); // original content if (contents instanceof COSStream) { contentArray.add(contents); } else if (contents instanceof COSArray) { contentArray.addAll((COSArray) contents); } else { throw new IOException("Unknown content type:" + contents.getClass().getName()); } // restore state contentArray.add(createStream("Q\n")); // overlay content overlayPage(contentArray, page, pageCount + 1, pages.size()); break; case BACKGROUND: // overlay content overlayPage(contentArray, page, pageCount + 1, pages.size()); // original content if (contents instanceof COSStream) { contentArray.add(contents); } else if (contents instanceof COSArray) { contentArray.addAll((COSArray) contents); } else { throw new IOException("Unknown content type:" + contents.getClass().getName()); } break; default: throw new IOException("Unknown type of position:" + position); } pageDictionary.setItem(COSName.CONTENTS, contentArray); pageCount++; } } private void overlayPage(COSArray array, PDPage page, int pageNumber, int numberOfPages) throws IOException { LayoutPage layoutPage = null; if (!useAllOverlayPages && specificPageOverlayPage.containsKey(pageNumber)) { layoutPage = specificPageOverlayPage.get(pageNumber); } else if ((pageNumber == 1) && (firstPageOverlayPage != null)) { layoutPage = firstPageOverlayPage; } else if ((pageNumber == numberOfPages) && (lastPageOverlayPage != null)) { layoutPage = lastPageOverlayPage; } else if ((pageNumber % 2 == 1) && (oddPageOverlayPage != null)) { layoutPage = oddPageOverlayPage; } else if ((pageNumber % 2 == 0) && (evenPageOverlayPage != null)) { layoutPage = evenPageOverlayPage; } else if (defaultOverlayPage != null) { layoutPage = defaultOverlayPage; } else if (useAllOverlayPages) { int usePageNum = (pageNumber - 1) % numberOfOverlayPages; layoutPage = specificPageOverlayPage.get(usePageNum); } if (layoutPage != null) { PDResources resources = page.findResources(); if (resources == null) { resources = new PDResources(); page.setResources(resources); } String xObjectId = createOverlayXObject(page, layoutPage, layoutPage.overlayContentStream); array.add(createOverlayStream(page, layoutPage, xObjectId)); } } private String createOverlayXObject(PDPage page, LayoutPage layoutPage, COSStream contentStream) { PDXObjectForm xobjForm = new PDXObjectForm(contentStream); xobjForm.setResources(new PDResources(layoutPage.overlayResources)); xobjForm.setFormType(1); xobjForm.setBBox(layoutPage.overlayMediaBox.createRetranslatedRectangle()); xobjForm.setMatrix(new AffineTransform()); PDResources resources = page.findResources(); return resources.addXObject(xobjForm, XOBJECT_PREFIX); } private COSStream createOverlayStream(PDPage page, LayoutPage layoutPage, String xObjectId) throws IOException { // create a new content stream that executes the XObject content PDRectangle pageMediaBox = page.getMediaBox(); float hShift = (pageMediaBox.getWidth() - layoutPage.overlayMediaBox.getWidth()) / 2.0f; float vShift = (pageMediaBox.getHeight() - layoutPage.overlayMediaBox.getHeight()) / 2.0f; StringBuilder overlayStream = new StringBuilder(); overlayStream.append("q\nq 1 0 0 1 "); overlayStream.append(float2String(hShift)); overlayStream.append(" "); overlayStream.append(float2String(vShift) ); overlayStream.append(" cm /"); overlayStream.append(xObjectId); overlayStream.append(" Do Q\nQ\n"); return createStream(overlayStream.toString()); } private String float2String(float floatValue) { // use a BigDecimal as intermediate state to avoid // a floating point string representation of the float value BigDecimal value = new BigDecimal(String.valueOf(floatValue)); String stringValue = value.toPlainString(); // remove fraction digit "0" only if (stringValue.indexOf('.') > -1 && !stringValue.endsWith(".0")) { while (stringValue.endsWith("0") && !stringValue.endsWith(".0")) { stringValue = stringValue.substring(0,stringValue.length()-1); } } return stringValue; } private COSStream createStream(String content) throws IOException { COSStream stream = new COSStream(new RandomAccessBuffer()); OutputStream out = stream.createUnfilteredStream(); out.write(content.getBytes("ISO-8859-1")); out.close(); stream.setFilters(COSName.FLATE_DECODE); return stream; } /** * Sets the overlay position. * * @param overlayPosition the overlay position */ public void setOverlayPosition(Position overlayPosition) { position = overlayPosition; } /** * Sets the file to be overlayed. * * @param inputFile the file to be overlayed */ public void setInputFile(String inputFile) { inputFileName = inputFile; } /** * Sets the PDF to be overlayed. * * @param inputPDF the PDF to be overlayed */ public void setInputPDF(PDDocument inputPDF) { inputPDFDocument = inputPDF; } /** * Returns the input file. * * @return the input file */ public String getInputFile() { return inputFileName; } /** * Sets the output file. * * @param outputFile the output file */ public void setOutputFile(String outputFile) { outputFilename = outputFile; } /** * Returns the output file. * * @return the output file */ public String getOutputFile() { return outputFilename; } /** * Sets the default overlay file. * * @param defaultOverlayFile the default overlay file */ public void setDefaultOverlayFile(String defaultOverlayFile) { defaultOverlayFilename = defaultOverlayFile; } /** * Sets the default overlay PDF. * * @param defaultOverlayPDF the default overlay PDF */ public void setDefaultOverlayPDF(PDDocument defaultOverlayPDF) { defaultOverlay = defaultOverlayPDF; } /** * Returns the default overlay file. * * @return the default overlay file */ public String getDefaultOverlayFile() { return defaultOverlayFilename; } /** * Sets the first page overlay file. * * @param firstPageOverlayFile the first page overlay file */ public void setFirstPageOverlayFile(String firstPageOverlayFile) { firstPageOverlayFilename = firstPageOverlayFile; } /** * Sets the first page overlay PDF. * * @param firstPageOverlayPDF the first page overlay PDF */ public void setFirstPageOverlayPDF(PDDocument firstPageOverlayPDF) { firstPageOverlay = firstPageOverlayPDF; } /** * Sets the last page overlay file. * * @param lastPageOverlayFile the last page overlay file */ public void setLastPageOverlayFile(String lastPageOverlayFile) { lastPageOverlayFilename = lastPageOverlayFile; } /** * Sets the last page overlay PDF. * * @param lastPageOverlayPDF the last page overlay PDF */ public void setLastPageOverlayPDF(PDDocument lastPageOverlayPDF) { lastPageOverlay = lastPageOverlayPDF; } /** * Sets the all pages overlay file. * * @param allPagesOverlayFile the all pages overlay file */ public void setAllPagesOverlayFile(String allPagesOverlayFile) { allPagesOverlayFilename = allPagesOverlayFile; } /** * Sets the all pages overlay PDF. * * @param allPagesOverlayPDF the all pages overlay PDF */ public void setAllPagesOverlayPDF(PDDocument allPagesOverlayPDF) { allPagesOverlay = allPagesOverlayPDF; } /** * Sets the odd page overlay file. * * @param oddPageOverlayFile the odd page overlay file */ public void setOddPageOverlayFile(String oddPageOverlayFile) { oddPageOverlayFilename = oddPageOverlayFile; } /** * Sets the odd page overlay PDF. * * @param oddPageOverlayPDF the odd page overlay PDF */ public void setOddPageOverlayPDF(PDDocument oddPageOverlayPDF) { oddPageOverlay = oddPageOverlayPDF; } /** * Sets the even page overlay file. * * @param evenPageOverlayFile the even page overlay file */ public void setEvenPageOverlayFile(String evenPageOverlayFile) { evenPageOverlayFilename = evenPageOverlayFile; } /** * Sets the even page overlay PDF. * * @param evenPageOverlayPDF the even page overlay PDF */ public void setEvenPageOverlayPDF(PDDocument evenPageOverlayPDF) { evenPageOverlay = evenPageOverlayPDF; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/ImageParameters.java0000644000000000000000000001566612645757432025715 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; import java.io.IOException; import java.util.List; import java.util.Map; /** * This contains all of the image parameters for in inlined image. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class ImageParameters { private COSDictionary dictionary; /** * Constructor. */ public ImageParameters() { dictionary = new COSDictionary(); } /** * Constructor. * * @param params The image parameters. */ public ImageParameters( COSDictionary params ) { dictionary = params; } /** * This will get the dictionary that stores the image parameters. * * @return The COS dictionary that stores the image parameters. */ public COSDictionary getDictionary() { return dictionary; } private COSBase getCOSObject( COSName abbreviatedName, COSName name ) { COSBase retval = dictionary.getDictionaryObject( abbreviatedName ); if( retval == null ) { retval = dictionary.getDictionaryObject( name ); } return retval; } private int getNumberOrNegativeOne( COSName abbreviatedName, COSName name ) { int retval = -1; COSNumber number = (COSNumber)getCOSObject( abbreviatedName, name ); if( number != null ) { retval = number.intValue(); } return retval; } /** * The bits per component of this image. This will return -1 if one has not * been set. * * @return The number of bits per component. */ public int getBitsPerComponent() { return getNumberOrNegativeOne( COSName.BPC, COSName.BITS_PER_COMPONENT ); } /** * Set the number of bits per component. * * @param bpc The number of bits per component. */ public void setBitsPerComponent( int bpc ) { dictionary.setInt( COSName.BPC, bpc ); } /** * This will get the color space or null if none exists. * * @return The color space for this image. * * @throws IOException If there is an error getting the colorspace. */ public PDColorSpace getColorSpace() throws IOException { return getColorSpace( null ); } /** * This will get the color space or null if none exists. * * @param colorSpaces The ColorSpace dictionary from the current resources, if any. * * @return The color space for this image. * * @throws IOException If there is an error getting the colorspace. */ public PDColorSpace getColorSpace( Map colorSpaces ) throws IOException { COSBase cs = getCOSObject( COSName.CS, COSName.COLORSPACE ); PDColorSpace retval = null; if( cs != null ) { retval = PDColorSpaceFactory.createColorSpace( cs, colorSpaces ); } return retval; } /** * This will set the color space for this image. * * @param cs The color space for this image. */ public void setColorSpace( PDColorSpace cs ) { COSBase base = null; if( cs != null ) { base = cs.getCOSObject(); } dictionary.setItem( COSName.CS, base ); } /** * The height of this image. This will return -1 if one has not * been set. * * @return The height. */ public int getHeight() { return getNumberOrNegativeOne( COSName.H, COSName.HEIGHT ); } /** * Set the height of the image. * * @param h The height of the image. */ public void setHeight( int h ) { dictionary.setInt( COSName.H, h ); } /** * The width of this image. This will return -1 if one has not * been set. * * @return The width. */ public int getWidth() { return getNumberOrNegativeOne( COSName.W, COSName.WIDTH ); } /** * Set the width of the image. * * @param w The width of the image. */ public void setWidth( int w ) { dictionary.setInt( COSName.W, w ); } /** * This will get the list of filters that are associated with this stream. Or * null if there are none. * @return A list of all encoding filters to apply to this stream. */ public List getFilters() { List retval = null; COSBase filters = dictionary.getDictionaryObject( new String[] {"Filter", "F"} ); if( filters instanceof COSName ) { COSName name = (COSName)filters; retval = new COSArrayList( name.getName(), name, dictionary, COSName.FILTER ); } else if( filters instanceof COSArray ) { retval = COSArrayList.convertCOSNameCOSArrayToList( (COSArray)filters ); } return retval; } /** * This will set the filters that are part of this stream. * * @param filters The filters that are part of this stream. */ public void setFilters( List filters ) { COSBase obj = COSArrayList.convertStringListToCOSNameCOSArray( filters ); dictionary.setItem( "Filter", obj ); } /** * Returns true if the image is a stencil mask. * * @return true if the image is a stencil mask. */ public boolean isStencil() { return dictionary.getBoolean(COSName.IM, COSName.IMAGE_MASK, false); } /** * Sets whether or not the image is a stencil. * This corresponds to the {@code ImageMask} entry in the image stream's dictionary. * @param isStencil True to make the image a stencil. */ public void setStencil(boolean isStencil) { dictionary.setBoolean(COSName.IM, isStencil); } }pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/MetaUtil.java0000644000000000000000000000527612645757432024367 0ustar rootroot/* * Copyright 2014 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.StringWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * * @author Tilman Hausherr */ public class MetaUtil { private static final Log LOG = LogFactory.getLog(TIFFUtil.class); static final String SUN_TIFF_FORMAT = "com_sun_media_imageio_plugins_tiff_image_1.0"; static final String JPEG_NATIVE_FORMAT = "javax_imageio_jpeg_image_1.0"; static final String STANDARD_METADATA_FORMAT = "javax_imageio_1.0"; // logs metadata as an XML tree if debug is enabled static void debugLogMetadata(IIOMetadata metadata, String format) { if (!LOG.isDebugEnabled()) { return; } // see http://docs.oracle.com/javase/7/docs/api/javax/imageio/ // metadata/doc-files/standard_metadata.html IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(format); try { StringWriter xmlStringWriter = new StringWriter(); StreamResult streamResult = new StreamResult(xmlStringWriter); Transformer transformer = TransformerFactory.newInstance().newTransformer(); // see http://stackoverflow.com/a/1264872/535646 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); DOMSource domSource = new DOMSource(root); transformer.transform(domSource, streamResult); LOG.debug("\n" + xmlStringWriter); } catch (IllegalArgumentException ex) { LOG.error(ex, ex); } catch (TransformerException ex) { LOG.error(ex, ex); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java0000644000000000000000000002765712645757432025312 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.awt.geom.AffineTransform; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.Map; import java.util.Set; import org.apache.fontbox.util.BoundingBox; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup; import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentProperties; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.pdmodel.markedcontent.PDPropertyList; /** * This class allows to import pages as Form XObjects into a PDF file and use them to create * layers (optional content groups). * * @version $Revision$ */ public class LayerUtility { private static final boolean DEBUG = true; private PDDocument targetDoc; private PDFCloneUtility cloner; /** * Creates a new instance. * @param document the PDF document to modify */ public LayerUtility(PDDocument document) { this.targetDoc = document; this.cloner = new PDFCloneUtility(document); } /** * Returns the PDF document we work on. * @return the PDF document */ public PDDocument getDocument() { return this.targetDoc; } /** * Some applications may not wrap their page content in a save/restore (q/Q) pair which can * lead to problems with coordinate system transformations when content is appended. This * method lets you add a q/Q pair around the existing page's content. * @param page the page * @throws IOException if an I/O error occurs */ public void wrapInSaveRestore(PDPage page) throws IOException { COSDictionary saveGraphicsStateDic = new COSDictionary(); COSStream saveGraphicsStateStream = getDocument().getDocument().createCOSStream(saveGraphicsStateDic); OutputStream saveStream = saveGraphicsStateStream.createUnfilteredStream(); saveStream.write("q\n".getBytes("ISO-8859-1")); saveStream.flush(); COSStream restoreGraphicsStateStream = getDocument().getDocument().createCOSStream(saveGraphicsStateDic); OutputStream restoreStream = restoreGraphicsStateStream.createUnfilteredStream(); restoreStream.write("Q\n".getBytes("ISO-8859-1")); restoreStream.flush(); //Wrap the existing page's content in a save/restore pair (q/Q) to have a controlled //environment to add additional content. COSDictionary pageDictionary = page.getCOSDictionary(); COSBase contents = pageDictionary.getDictionaryObject(COSName.CONTENTS); if (contents instanceof COSStream) { COSStream contentsStream = (COSStream)contents; COSArray array = new COSArray(); array.add(saveGraphicsStateStream); array.add(contentsStream); array.add(restoreGraphicsStateStream); pageDictionary.setItem(COSName.CONTENTS, array); } else if( contents instanceof COSArray ) { COSArray contentsArray = (COSArray)contents; contentsArray.add(0, saveGraphicsStateStream); contentsArray.add(restoreGraphicsStateStream); } else { throw new IOException("Contents are unknown type: " + contents.getClass().getName()); } } /** * Imports a page from some PDF file as a Form XObject so it can be placed on another page * in the target document. * @param sourceDoc the source PDF document that contains the page to be copied * @param pageNumber the page number of the page to be copied * @return a Form XObject containing the original page's content * @throws IOException if an I/O error occurs */ public PDXObjectForm importPageAsForm(PDDocument sourceDoc, int pageNumber) throws IOException { PDPage page = (PDPage)sourceDoc.getDocumentCatalog().getAllPages().get(pageNumber); return importPageAsForm(sourceDoc, page); } private static final Set PAGE_TO_FORM_FILTER = new java.util.HashSet( Arrays.asList(new String[] {"Group", "LastModified", "Metadata"})); /** * Imports a page from some PDF file as a Form XObject so it can be placed on another page * in the target document. * @param sourceDoc the source PDF document that contains the page to be copied * @param page the page in the source PDF document to be copied * @return a Form XObject containing the original page's content * @throws IOException if an I/O error occurs */ public PDXObjectForm importPageAsForm(PDDocument sourceDoc, PDPage page) throws IOException { COSStream pageStream = (COSStream)page.getContents().getCOSObject(); PDStream newStream = new PDStream(targetDoc, pageStream.getUnfilteredStream(), false); PDXObjectForm form = new PDXObjectForm(newStream); //Copy resources PDResources pageRes = page.findResources(); PDResources formRes = new PDResources(); cloner.cloneMerge(pageRes, formRes); form.setResources(formRes); //Transfer some values from page to form transferDict(page.getCOSDictionary(), form.getCOSStream(), PAGE_TO_FORM_FILTER, true); Matrix matrix = form.getMatrix(); AffineTransform at = matrix != null ? matrix.createAffineTransform() : new AffineTransform(); PDRectangle mediaBox = page.findMediaBox(); PDRectangle cropBox = page.findCropBox(); PDRectangle viewBox = (cropBox != null ? cropBox : mediaBox); //Handle the /Rotation entry on the page dict int rotation = getNormalizedRotation(page); //Transform to FOP's user space //at.scale(1 / viewBox.getWidth(), 1 / viewBox.getHeight()); at.translate(mediaBox.getLowerLeftX() - viewBox.getLowerLeftX(), mediaBox.getLowerLeftY() - viewBox.getLowerLeftY()); switch (rotation) { case 90: at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth()); at.translate(0, viewBox.getWidth()); at.rotate(-Math.PI / 2.0); break; case 180: at.translate(viewBox.getWidth(), viewBox.getHeight()); at.rotate(-Math.PI); break; case 270: at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth()); at.translate(viewBox.getHeight(), 0); at.rotate(-Math.PI * 1.5); default: //no additional transformations necessary } //Compensate for Crop Boxes not starting at 0,0 at.translate(-viewBox.getLowerLeftX(), -viewBox.getLowerLeftY()); if (!at.isIdentity()) { form.setMatrix(at); } BoundingBox bbox = new BoundingBox(); bbox.setLowerLeftX(viewBox.getLowerLeftX()); bbox.setLowerLeftY(viewBox.getLowerLeftY()); bbox.setUpperRightX(viewBox.getUpperRightX()); bbox.setUpperRightY(viewBox.getUpperRightY()); form.setBBox(new PDRectangle(bbox)); return form; } /** * Places the given form over the existing content of the indicated page (like an overlay). * The form is enveloped in a marked content section to indicate that it's part of an * optional content group (OCG), here used as a layer. This optional group is returned and * can be enabled and disabled through methods on {@link PDOptionalContentProperties}. * @param targetPage the target page * @param form the form to place * @param transform the transformation matrix that controls the placement * @param layerName the name for the layer/OCG to produce * @return the optional content group that was generated for the form usage * @throws IOException if an I/O error occurs */ public PDOptionalContentGroup appendFormAsLayer(PDPage targetPage, PDXObjectForm form, AffineTransform transform, String layerName) throws IOException { PDDocumentCatalog catalog = targetDoc.getDocumentCatalog(); PDOptionalContentProperties ocprops = catalog.getOCProperties(); if (ocprops == null) { ocprops = new PDOptionalContentProperties(); catalog.setOCProperties(ocprops); } if (ocprops.hasGroup(layerName)) { throw new IllegalArgumentException("Optional group (layer) already exists: " + layerName); } PDOptionalContentGroup layer = new PDOptionalContentGroup(layerName); ocprops.addGroup(layer); PDResources resources = targetPage.findResources(); PDPropertyList props = resources.getProperties(); if (props == null) { props = new PDPropertyList(); resources.setProperties(props); } //Find first free resource name with the pattern "MC" int index = 0; PDOptionalContentGroup ocg; COSName resourceName; do { resourceName = COSName.getPDFName("MC" + index); ocg = props.getOptionalContentGroup(resourceName); index++; } while (ocg != null); //Put mapping for our new layer/OCG props.putMapping(resourceName, layer); PDPageContentStream contentStream = new PDPageContentStream( targetDoc, targetPage, true, !DEBUG); contentStream.beginMarkedContentSequence(COSName.OC, resourceName); contentStream.drawXObject(form, transform); contentStream.endMarkedContentSequence(); contentStream.close(); return layer; } private void transferDict(COSDictionary orgDict, COSDictionary targetDict, Set filter, boolean inclusive) throws IOException { for (Map.Entry entry : orgDict.entrySet()) { COSName key = entry.getKey(); if (inclusive && !filter.contains(key.getName())) { continue; } else if (!inclusive && filter.contains(key.getName())) { continue; } targetDict.setItem(key, cloner.cloneForNewDocument(entry.getValue())); } } private static int getNormalizedRotation(PDPage page) { //Handle the /Rotation entry on the page dict int rotationAngle = page.findRotation(); // normalize the rotation angle while (rotationAngle < 0) { rotationAngle += 360; } while (rotationAngle >= 360) { rotationAngle -= 360; } return rotationAngle; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/TIFFUtil.java0000644000000000000000000001600412645757432024220 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.imageio.ImageWriteParam; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import java.awt.image.BufferedImage; import static org.apache.pdfbox.util.MetaUtil.SUN_TIFF_FORMAT; import static org.apache.pdfbox.util.MetaUtil.debugLogMetadata; /** * Used by ImageIOUtil to write TIFF files. * @author Tilman Hausherr */ class TIFFUtil { private static final Log LOG = LogFactory.getLog(TIFFUtil.class); /** * Sets the ImageIO parameter compression type based on the given image. * @param image buffered image used to decide compression type * @param param ImageIO write parameter to update */ public static void setCompressionType(ImageWriteParam param, BufferedImage image) { // avoid error: first compression type is RLE, not optimal and incorrect for color images // TODO expose this choice to the user? if (image.getType() == BufferedImage.TYPE_BYTE_BINARY && image.getColorModel().getPixelSize() == 1) { param.setCompressionType("CCITT T.6"); } else { param.setCompressionType("LZW"); } } /** * Updates the given ImageIO metadata with Sun's custom TIFF tags. * {@see https://svn.apache.org/repos/asf/xmlgraphics/commons/tags/commons-1_3_1/src/java/org/ * apache/xmlgraphics/image/writer/imageio/ImageIOTIFFImageWriter.java} * {@see http://download.java.net/media/jai-imageio/javadoc/1.0_01/com/sun/media/imageio/ * plugins/tiff/package-summary.html} * {@see http://partners.adobe.com/public/developer/tiff/index.html} * @param image buffered image which will be written * @param metadata ImageIO metadata * @param dpi image dots per inch */ public static void updateMetadata(IIOMetadata metadata, BufferedImage image, int dpi) { debugLogMetadata(metadata, SUN_TIFF_FORMAT); if (!SUN_TIFF_FORMAT.equals(metadata.getNativeMetadataFormatName())) { LOG.debug("Using unknown TIFF image writer: " + metadata.getNativeMetadataFormatName()); return; } IIOMetadataNode root = new IIOMetadataNode(SUN_TIFF_FORMAT); IIOMetadataNode ifd; if (root.getElementsByTagName("TIFFIFD").getLength() == 0) { ifd = new IIOMetadataNode("TIFFIFD"); ifd.setAttribute("tagSets", "com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet"); root.appendChild(ifd); } else { ifd = (IIOMetadataNode)root.getElementsByTagName("TIFFIFD").item(0); } // standard metadata does not work, so we set the DPI manually ifd.appendChild(createRationalField(282, "XResolution", dpi, 1)); ifd.appendChild(createRationalField(283, "YResolution", dpi, 1)); ifd.appendChild(createShortField(296, "ResolutionUnit", 2)); // Inch ifd.appendChild(createLongField(278, "RowsPerStrip", image.getHeight())); ifd.appendChild(createAsciiField(305, "Software", "PDFBOX")); if (image.getType() == BufferedImage.TYPE_BYTE_BINARY && image.getColorModel().getPixelSize() == 1) { // set PhotometricInterpretation WhiteIsZero // because of bug in Windows XP preview ifd.appendChild(createShortField(262, "PhotometricInterpretation", 0)); } try { metadata.mergeTree(SUN_TIFF_FORMAT, root); } catch (IIOInvalidTreeException e) { // should never happen throw new RuntimeException(e); } debugLogMetadata(metadata, SUN_TIFF_FORMAT); } private static IIOMetadataNode createShortField(int tiffTagNumber, String name, int val) { IIOMetadataNode field, arrayNode, valueNode; field = new IIOMetadataNode("TIFFField"); field.setAttribute("number", Integer.toString(tiffTagNumber)); field.setAttribute("name", name); arrayNode = new IIOMetadataNode("TIFFShorts"); field.appendChild(arrayNode); valueNode = new IIOMetadataNode("TIFFShort"); arrayNode.appendChild(valueNode); valueNode.setAttribute("value", Integer.toString(val)); return field; } private static IIOMetadataNode createAsciiField(int number, String name, String val) { IIOMetadataNode field, arrayNode, valueNode; field = new IIOMetadataNode("TIFFField"); field.setAttribute("number", Integer.toString(number)); field.setAttribute("name", name); arrayNode = new IIOMetadataNode("TIFFAsciis"); field.appendChild(arrayNode); valueNode = new IIOMetadataNode("TIFFAscii"); arrayNode.appendChild(valueNode); valueNode.setAttribute("value", val); return field; } private static IIOMetadataNode createLongField(int number, String name, long val) { IIOMetadataNode field, arrayNode, valueNode; field = new IIOMetadataNode("TIFFField"); field.setAttribute("number", Integer.toString(number)); field.setAttribute("name", name); arrayNode = new IIOMetadataNode("TIFFLongs"); field.appendChild(arrayNode); valueNode = new IIOMetadataNode("TIFFLong"); arrayNode.appendChild(valueNode); valueNode.setAttribute("value", Long.toString(val)); return field; } private static IIOMetadataNode createRationalField(int number, String name, int numerator, int denominator) { IIOMetadataNode field, arrayNode, valueNode; field = new IIOMetadataNode("TIFFField"); field.setAttribute("number", Integer.toString(number)); field.setAttribute("name", name); arrayNode = new IIOMetadataNode("TIFFRationals"); field.appendChild(arrayNode); valueNode = new IIOMetadataNode("TIFFRational"); arrayNode.appendChild(valueNode); valueNode.setAttribute("value", numerator + "/" + denominator); return field; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PositionWrapper.java0000644000000000000000000000607512645757432026006 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; /** * wrapper of TextPosition that adds flags to track * status as linestart and paragraph start positions. *

* This is implemented as a wrapper since the TextPosition * class doesn't provide complete access to its * state fields to subclasses. Also, conceptually TextPosition is * immutable while these flags need to be set post-creation so * it makes sense to put these flags in this separate class. *

* @author m.martinez@ll.mit.edu * */ public class PositionWrapper { private boolean isLineStart = false; private boolean isParagraphStart = false; private boolean isPageBreak = false; private boolean isHangingIndent = false; private boolean isArticleStart = false; private TextPosition position = null; /** * Returns the underlying TextPosition object. * @return the text position */ public TextPosition getTextPosition() { return position; } public boolean isLineStart() { return isLineStart; } /** * Sets the isLineStart() flag to true. */ public void setLineStart() { this.isLineStart = true; } public boolean isParagraphStart() { return isParagraphStart; } /** * sets the isParagraphStart() flag to true. */ public void setParagraphStart() { this.isParagraphStart = true; } public boolean isArticleStart() { return isArticleStart; } /** * Sets the isArticleStart() flag to true. */ public void setArticleStart() { this.isArticleStart = true; } public boolean isPageBreak() { return isPageBreak; } /** * Sets the isPageBreak() flag to true. */ public void setPageBreak() { this.isPageBreak = true; } public boolean isHangingIndent() { return isHangingIndent; } /** * Sets the isHangingIndent() flag to true. */ public void setHangingIndent() { this.isHangingIndent = true; } /** * Constructs a PositionWrapper around the specified TextPosition object. * @param position the text position */ public PositionWrapper(TextPosition position) { this.position = position; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/package.html0000644000000000000000000000173012645757432024250 0ustar rootroot This package contains utility classes that are used by the PDFBox project. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PageExtractor.java0000644000000000000000000001056412645757432025407 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.util.List; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; /** * This class will extract one or more sequential pages and create a new document. * @author Adam Nichols (adam@apache.org) */ public class PageExtractor { protected PDDocument sourceDocument; protected int startPage = 1; // first page to extract is page 1 (by default) protected int endPage = 0; /** * Creates a new instance of PageExtractor * @param sourceDocument The document to split. */ public PageExtractor(PDDocument sourceDocument) { this.sourceDocument = sourceDocument; endPage = sourceDocument.getNumberOfPages(); } /** * Creates a new instance of PageExtractor * @param sourceDocument The document to split. * @param startPage The first page you want extracted (inclusive) * @param endPage The last page you want extracted (inclusive) */ public PageExtractor(PDDocument sourceDocument, int startPage, int endPage) { this(sourceDocument); this.startPage = startPage; this.endPage = endPage; } /** * This will take a document and extract the desired pages into a new * document. Both startPage and endPage are included in the extracted * document. If the endPage is greater than the number of pages in the * source document, it will go to the end of the document. If startPage is * less than 1, it'll start with page 1. If startPage is greater than * endPage or greater than the number of pages in the source document, a * blank document will be returned. * * @return The extracted document * @throws IOException If there is an IOError */ public PDDocument extract() throws IOException { PDDocument extractedDocument = new PDDocument(); extractedDocument.setDocumentInformation(sourceDocument.getDocumentInformation()); extractedDocument.getDocumentCatalog().setViewerPreferences( sourceDocument.getDocumentCatalog().getViewerPreferences()); List pages = (List)sourceDocument.getDocumentCatalog().getAllPages(); int pageCounter = 1; for(PDPage page : pages) { if(pageCounter >= startPage && pageCounter <= endPage) { PDPage imported = extractedDocument.importPage(page); imported.setCropBox(page.findCropBox()); imported.setMediaBox(page.findMediaBox()); imported.setResources(page.findResources()); imported.setRotation(page.findRotation()); } pageCounter++; } return extractedDocument; } /** * Gets the first page number to be extracted. * @return the first page number which should be extracted */ public int getStartPage() { return startPage; } /** * Sets the first page number to be extracted. * @param startPage the first page number which should be extracted */ public void setStartPage(int startPage) { this.startPage = startPage; } /** * Gets the last page number (inclusive) to be extracted. * @return the last page number which should be extracted */ public int getEndPage() { return endPage; } /** * Sets the last page number to be extracted. * @param endPage the last page number which should be extracted */ public void setEndPage(int endPage) { this.endPage = endPage; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java0000644000000000000000000002273612645757432025621 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.COSStreamArray; import org.apache.pdfbox.pdmodel.common.PDStream; /** * Utility class used to clone PDF objects. It keeps track of objects it has already cloned. * * @version $Revision$ */ public class PDFCloneUtility { private PDDocument destination; private Map clonedVersion = new HashMap(); /** * Creates a new instance for the given target document. * @param dest the destination PDF document that will receive the clones */ public PDFCloneUtility(PDDocument dest) { this.destination = dest; } /** * Returns the destination PDF document this cloner instance is set up for. * @return the destination PDF document */ public PDDocument getDestination() { return this.destination; } /** * Deep-clones the given object for inclusion into a different PDF document identified by * the destination parameter. * @param base the initial object as the root of the deep-clone operation * @return the cloned instance of the base object * @throws IOException if an I/O error occurs */ public COSBase cloneForNewDocument( Object base ) throws IOException { if( base == null ) { return null; } COSBase retval = (COSBase)clonedVersion.get( base ); if( retval != null ) { //we are done, it has already been converted. } else if( base instanceof List ) { COSArray array = new COSArray(); List list = (List)base; for( int i=0; i 0) { throw new IllegalStateException("Cannot close stream array with items next to the streams."); } COSArray array = new COSArray(); for (int i = 0; i < originalStream.getStreamCount(); i++) { COSBase base2 = originalStream.get(i); COSBase cloneForNewDocument = cloneForNewDocument(base2); array.add(cloneForNewDocument); } retval = new COSStreamArray(array); clonedVersion.put(base, retval); } else if( base instanceof COSStream ) { COSStream originalStream = (COSStream)base; PDStream stream = new PDStream( destination, originalStream.getFilteredStream(), true ); clonedVersion.put( base, stream.getStream() ); for( Map.Entry entry : originalStream.entrySet() ) { stream.getStream().setItem( entry.getKey(), cloneForNewDocument(entry.getValue())); } retval = stream.getStream(); } else if( base instanceof COSDictionary ) { COSDictionary dic = (COSDictionary)base; retval = new COSDictionary(); clonedVersion.put( base, retval ); for( Map.Entry entry : dic.entrySet() ) { ((COSDictionary)retval).setItem( entry.getKey(), cloneForNewDocument(entry.getValue())); } } else { retval = (COSBase)base; } clonedVersion.put( base, retval ); return retval; } /** * Merges two objects of the same type by deep-cloning its members. *
* Base and target must be instances of the same class. * @param base the base object to be cloned * @param target the merge target * @throws IOException if an I/O error occurs */ public void cloneMerge( COSObjectable base, COSObjectable target) throws IOException { if( base == null ) { return; } COSBase retval = (COSBase)clonedVersion.get( base ); if( retval != null ) { return; //we are done, it has already been converted. // ### Is that correct for cloneMerge??? } else if( base instanceof List ) { COSArray array = new COSArray(); List list = (List)base; for( int i = 0; i < list.size(); i++ ) { array.add( cloneForNewDocument( list.get( i ) ) ); } ((List)target).add(array); } else if( base instanceof COSObjectable && !(base instanceof COSBase) ) { cloneMerge(((COSObjectable)base).getCOSObject(), ((COSObjectable)target).getCOSObject() ); clonedVersion.put( base, retval ); } else if( base instanceof COSObject ) { if(target instanceof COSObject) { cloneMerge(((COSObject) base).getObject(),((COSObject) target).getObject() ); } else if(target instanceof COSDictionary) { cloneMerge(((COSObject)base).getObject(), ((COSDictionary)target)); } clonedVersion.put( base, retval ); } else if( base instanceof COSArray ) { COSArray array = (COSArray)base; for( int i=0; i entry : originalStream.entrySet() ) { stream.getStream().setItem( entry.getKey(), cloneForNewDocument(entry.getValue())); } retval = stream.getStream(); target = retval; } else if( base instanceof COSDictionary ) { COSDictionary dic = (COSDictionary)base; clonedVersion.put( base, retval ); for( Map.Entry entry : dic.entrySet() ) { COSName key = entry.getKey(); COSBase value = entry.getValue(); if (((COSDictionary)target).getItem(key) != null) { cloneMerge(value, ((COSDictionary)target).getItem(key)); } else { ((COSDictionary)target).setItem( key, cloneForNewDocument(value)); } } } else { retval = (COSBase)base; } clonedVersion.put( base, retval ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/ResourceLoader.java0000644000000000000000000001151112645757432025546 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.util.Properties; /** * This class will handle loading resource files(AFM/CMAP). * * @author Ben Litchfield * @version $Revision: 1.9 $ */ public class ResourceLoader { /** * private constructor for utility class. */ private ResourceLoader() { //private utility class } /** * This will attempt to load the resource given the resource name. * * @param resourceName The resource to try and load. * * @return The resource as a stream or null if it could not be found. * * @throws IOException If there is an error while attempting to load the resource. */ public static InputStream loadResource( String resourceName ) throws IOException { ClassLoader loader = null; try { loader = ResourceLoader.class.getClassLoader(); } catch (SecurityException ex) { // PDFBOX-1946 ignore and try other alternatives } InputStream is = null; if( loader != null ) { is = loader.getResourceAsStream( resourceName ); } //see sourceforge bug 863053, this is a fix for a user that //needed to have PDFBox loaded by the bootstrap classloader try { if (is == null) { loader = ClassLoader.getSystemClassLoader(); if( loader != null ) { is = loader.getResourceAsStream( resourceName ); } } if( is == null ) { File f = new File( resourceName ); if( f.exists() ) { is = new FileInputStream( f ); } } } catch (SecurityException ex) { // PDFBOX-1946 ignore and continue } return is; } /** * This will attempt to load the resource given the resource name. * * @param resourceName The resource to try and load. * @param failIfNotFound Throw an error message if the properties were not found. * * @return The resource as a stream or null if it could not be found. * * @throws IOException If there is an error loading the properties. */ public static Properties loadProperties( String resourceName, boolean failIfNotFound ) throws IOException { Properties properties = null; InputStream is = null; try { is = loadResource( resourceName ); if( is != null ) { properties = new Properties(); properties.load( is ); } else { if( failIfNotFound ) { throw new IOException( "Error: could not find resource '" + resourceName + "' on classpath." ); } } } finally { if( is != null ) { is.close(); } } return properties; } /** * This will attempt to load the resource given the resource name. * * @param resourceName The resource to try and load. * @param defaults A stream of default properties. * * @return The resource as a stream or null if it could not be found. * * @throws IOException If there is an error loading the properties. */ public static Properties loadProperties( String resourceName, Properties defaults ) throws IOException { InputStream is = null; try { is = loadResource( resourceName ); if( is != null ) { defaults.load( is ); } } finally { if( is != null ) { is.close(); } } return defaults; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFHighlighter.java0000644000000000000000000001735012645757432025427 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; /** * Highlighting of words in a PDF document with an XML file. * * @author slagraulet (slagraulet@cardiweb.com) * @author Ben Litchfield * @version $Revision: 1.7 $ * * @see * Adobe Highlight File Format */ public class PDFHighlighter extends PDFTextStripper { private Writer highlighterOutput = null; //private Color highlightColor = Color.YELLOW; private String[] searchedWords; private ByteArrayOutputStream textOS = null; private Writer textWriter = null; private static final String ENCODING = "UTF-16"; /** * Default constructor. * * @throws IOException If there is an error constructing this class. */ public PDFHighlighter() throws IOException { super(ENCODING); super.setLineSeparator( "" ); super.setPageSeparator( "" ); super.setWordSeparator( "" ); super.setShouldSeparateByBeads( false ); super.setSuppressDuplicateOverlappingText( false ); } /** * Generate an XML highlight string based on the PDF. * * @param pdDocument The PDF to find words in. * @param highlightWord The word to search for. * @param xmlOutput The resulting output xml file. * * @throws IOException If there is an error reading from the PDF, or writing to the XML. */ public void generateXMLHighlight(PDDocument pdDocument, String highlightWord, Writer xmlOutput ) throws IOException { generateXMLHighlight( pdDocument, new String[] { highlightWord }, xmlOutput ); } /** * Generate an XML highlight string based on the PDF. * * @param pdDocument The PDF to find words in. * @param sWords The words to search for. * @param xmlOutput The resulting output xml file. * * @throws IOException If there is an error reading from the PDF, or writing to the XML. */ public void generateXMLHighlight(PDDocument pdDocument, String[] sWords, Writer xmlOutput ) throws IOException { highlighterOutput = xmlOutput; searchedWords = sWords; highlighterOutput.write("\n\n\n"); textOS = new ByteArrayOutputStream(); textWriter = new OutputStreamWriter( textOS, ENCODING); writeText(pdDocument, textWriter); highlighterOutput.write("\n\n"); highlighterOutput.flush(); } /** * {@inheritDoc} */ protected void endPage( PDPage pdPage ) throws IOException { textWriter.flush(); String page = new String( textOS.toByteArray(), ENCODING ); textOS.reset(); //page = page.replaceAll( "\n", "" ); //page = page.replaceAll( "\r", "" ); //page = CCRStringUtil.stripChar(page, '\n'); //page = CCRStringUtil.stripChar(page, '\r'); // Traitement des listes � puces (caract�res sp�ciaux) if (page.indexOf("a") != -1) { page = page.replaceAll("a[0-9]{1,3}", "."); } for (int i = 0; i < searchedWords.length; i++) { Pattern pattern = Pattern.compile(searchedWords[i], Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(page); while( matcher.find() ) { int begin = matcher.start(); int end = matcher.end(); highlighterOutput.write(" \n"); } } } /** * Command line application. * * @param args The command line arguments to the application. * * @throws IOException If there is an error generating the highlight file. */ public static void main(String[] args) throws IOException { PDFHighlighter xmlExtractor = new PDFHighlighter(); PDDocument doc = null; try { if( args.length < 2 ) { usage(); } String[] highlightStrings = new String[ args.length - 1]; System.arraycopy( args, 1, highlightStrings, 0, highlightStrings.length ); doc = PDDocument.load( args[0] ); xmlExtractor.generateXMLHighlight( doc, highlightStrings, new OutputStreamWriter( System.out ) ); } finally { if( doc != null ) { doc.close(); } } } private static void usage() { System.err.println( "usage: java " + PDFHighlighter.class.getName() + " word1 word2 word3 ..." ); System.exit( 1 ); } /** * Get the color to highlight the strings with. Default is Color.YELLOW. * * @return The color to highlight strings with. */ /*public Color getHighlightColor() { return highlightColor; }**/ /** * Get the color to highlight the strings with. Default is Color.YELLOW. * * @param color The color to highlight strings with. */ /*public void setHighlightColor(Color color) { this.highlightColor = color; }**/ /** * Set the highlight color using HTML like rgb string. The string must be 6 characters long. * * @param color The color to use for highlighting. Should be in the format of "FF0000". */ /*public void setHighlightColor( String color ) { highlightColor = Color.decode( color ); }**/ /** * Get the highlight color as an HTML like string. This will return a string of six characters. * * @return The current highlight color. For example FF0000 */ /*public String getHighlightColorAsString() { //BJL: kudos to anyone that has a cleaner way of doing this! String red = Integer.toHexString( highlightColor.getRed() ); String green = Integer.toHexString( highlightColor.getGreen() ); String blue = Integer.toHexString( highlightColor.getBlue() ); return (red.length() < 2 ? "0" + red : red) + (green.length() < 2 ? "0" + green : green) + (blue.length() < 2 ? "0" + blue : blue); }**/ } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFText2HTML.java0000644000000000000000000003225312645757432024663 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.font.PDFontDescriptor; /** * Wrap stripped text in simple HTML, trying to form HTML paragraphs. Paragraphs * broken by pages, columns, or figures are not mended. * * @author jjb - http://www.johnjbarton.com * */ public class PDFText2HTML extends PDFTextStripper { private static final int INITIAL_PDF_TO_HTML_BYTES = 8192; private boolean onFirstPage = true; private FontState fontState = new FontState(); /** * Constructor. * @param encoding The encoding to be used * @throws IOException If there is an error during initialization. */ public PDFText2HTML(String encoding) throws IOException { super(encoding); setLineSeparator(systemLineSeparator); setParagraphStart("

"); setParagraphEnd("

"+systemLineSeparator); setPageStart("
"); setPageEnd("
"+systemLineSeparator); setArticleStart(systemLineSeparator); setArticleEnd(systemLineSeparator); } /** * Write the header to the output document. Now also writes the tag defining * the character encoding. * * @throws IOException * If there is a problem writing out the header to the document. */ protected void writeHeader() throws IOException { StringBuffer buf = new StringBuffer(INITIAL_PDF_TO_HTML_BYTES); buf.append("\n"); buf.append(""); buf.append("" + escape(getTitle()) + "\n"); if(outputEncoding != null) { buf.append("\n"); } buf.append("\n"); buf.append("\n"); super.writeString(buf.toString()); } /** * {@inheritDoc} */ protected void writePage() throws IOException { if (onFirstPage) { writeHeader(); onFirstPage = false; } super.writePage(); } /** * {@inheritDoc} */ public void endDocument(PDDocument pdf) throws IOException { super.writeString(""); } /** * This method will attempt to guess the title of the document using * either the document properties or the first lines of text. * * @return returns the title. */ protected String getTitle() { String titleGuess = document.getDocumentInformation().getTitle(); if(titleGuess != null && titleGuess.length() > 0) { return titleGuess; } else { Iterator> textIter = getCharactersByArticle().iterator(); float lastFontSize = -1.0f; StringBuffer titleText = new StringBuffer(); while (textIter.hasNext()) { Iterator textByArticle = textIter.next().iterator(); while (textByArticle.hasNext()) { TextPosition position = textByArticle.next(); float currentFontSize = position.getFontSize(); //If we're past 64 chars we will assume that we're past the title //64 is arbitrary if (currentFontSize != lastFontSize || titleText.length() > 64) { if (titleText.length() > 0) { return titleText.toString(); } lastFontSize = currentFontSize; } if (currentFontSize > 13.0f) { // most body text is 12pt titleText.append(position.getCharacter()); } } } } return ""; } /** * Write out the article separator (div tag) with proper text direction * information. * * @param isltr true if direction of text is left to right * @throws IOException * If there is an error writing to the stream. */ protected void startArticle(boolean isltr) throws IOException { if (isltr) { super.writeString("
"); } else { super.writeString("
"); } } /** * Write out the article separator. * * @throws IOException * If there is an error writing to the stream. */ protected void endArticle() throws IOException { super.endArticle(); super.writeString("
"); } /** * Write a string to the output stream, maintain font state, and escape some HTML characters. * The font state is only preserved per word. * * @param text The text to write to the stream. * @param textPositions the corresponding text positions * @throws IOException If there is an error writing to the stream. */ protected void writeString(String text, List textPositions) throws IOException { super.writeString(fontState.push(text, textPositions)); } /** * Write a string to the output stream and escape some HTML characters. * * @param chars String to be written to the stream * @throws IOException * If there is an error writing to the stream. */ protected void writeString(String chars) throws IOException { super.writeString(escape(chars)); } /** * Writes the paragraph end "

" to the output. Furthermore, it will also clear the font state. * * {@inheritDoc} */ @Override protected void writeParagraphEnd() throws IOException { super.writeString(fontState.clear()); // do not escape HTML super.writeParagraphEnd(); } /** * Escape some HTML characters. * * @param chars String to be escaped * @return returns escaped String. */ private static String escape(String chars) { StringBuilder builder = new StringBuilder(chars.length()); for (int i = 0; i < chars.length(); i++) { appendEscaped(builder, chars.charAt(i)); } return builder.toString(); } private static void appendEscaped(StringBuilder builder, char character) { // write non-ASCII as named entities if ((character < 32) || (character > 126)) { int charAsInt = character; builder.append("&#").append(charAsInt).append(";"); } else { switch (character) { case 34: builder.append("""); break; case 38: builder.append("&"); break; case 60: builder.append("<"); break; case 62: builder.append(">"); break; default: builder.append(String.valueOf(character)); } } } /** * A helper class to maintain the current font state. It's public methods will emit opening and * closing tags as needed, and in the correct order. * * @author Axel Drfler */ private static class FontState { protected List stateList = new ArrayList(); protected Set stateSet = new HashSet(); /** * Pushes new {@link TextPosition TextPositions} into the font state. The state is only * preserved correctly for each letter if the number of letters in text matches * the number of {@link TextPosition} objects. Otherwise, it's done once for the complete * array (just by looking at its first entry). * * @return A string that contains the text including tag changes caused by its font state. */ public String push(String text, List textPositions) { StringBuilder buffer = new StringBuilder(); if (text.length() == textPositions.size()) { // There is a 1:1 mapping, and we can use the TextPositions directly for (int i = 0; i < text.length(); i++) { push(buffer, text.charAt(i), textPositions.get(i)); } } else if (text.length() > 0) { // The normalized text does not match the number of TextPositions, so we'll just // have a look at its first entry. // TODO change PDFTextStripper.normalize() such that it maintains the 1:1 relation if (textPositions.isEmpty()) { return text; } push(buffer, text.charAt(0), textPositions.get(0)); buffer.append(escape(text.substring(1))); } return buffer.toString(); } /** * Closes all open states. * @return A string that contains the closing tags of all currently open states. */ public String clear() { StringBuilder buffer = new StringBuilder(); closeUntil(buffer, null); stateList.clear(); stateSet.clear(); return buffer.toString(); } protected String push(StringBuilder buffer, char character, TextPosition textPosition) { boolean bold = false; boolean italics = false; PDFontDescriptor descriptor = textPosition.getFont().getFontDescriptor(); if (descriptor != null) { bold = isBold(descriptor); italics = isItalic(descriptor); } buffer.append(bold ? open("b") : close("b")); buffer.append(italics ? open("i") : close("i")); appendEscaped(buffer, character); return buffer.toString(); } private String open(String tag) { if (stateSet.contains(tag)) { return ""; } stateList.add(tag); stateSet.add(tag); return openTag(tag); } private String close(String tag) { if (!stateSet.contains(tag)) { return ""; } // Close all tags until (but including) the one we should close StringBuilder tagsBuilder = new StringBuilder(); int index = closeUntil(tagsBuilder, tag); // Remove from state stateList.remove(index); stateSet.remove(tag); // Now open the states that were closed but should remain open again for (; index < stateList.size(); index++) { tagsBuilder.append(openTag(stateList.get(index))); } return tagsBuilder.toString(); } private int closeUntil(StringBuilder tagsBuilder, String endTag) { for (int i = stateList.size(); i-- > 0;) { String tag = stateList.get(i); tagsBuilder.append(closeTag(tag)); if (endTag != null && tag.equals(endTag)) { return i; } } return -1; } private String openTag(String tag) { return "<" + tag + ">"; } private String closeTag(String tag) { return ""; } private boolean isBold(PDFontDescriptor descriptor) { if (descriptor.isForceBold()) { return true; } return descriptor.getFontName().contains("Bold"); } private boolean isItalic(PDFontDescriptor descriptor) { if (descriptor.isItalic()) { return true; } return descriptor.getFontName().contains("Italic"); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/ErrorLogger.java0000644000000000000000000000345412645757432025070 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; /** * This class deals with some logging that is not handled by the log4j replacement. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class ErrorLogger { /** * Utility class, should not be instantiated. * */ private ErrorLogger() { } /** * Log an error message. This is only used for log4j replacement and * should never be used when writing code. * * @param errorMessage The error message. */ public static void log( String errorMessage ) { System.err.println( errorMessage ); } /** * Log an error message. This is only used for log4j replacement and * should never be used when writing code. * * @param errorMessage The error message. * @param t The exception. */ public static void log( String errorMessage, Throwable t ) { System.err.println( errorMessage ); t.printStackTrace(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/ImageIOUtil.java0000644000000000000000000003052212645757432024743 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.stream.ImageOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import static org.apache.pdfbox.util.MetaUtil.STANDARD_METADATA_FORMAT; import org.w3c.dom.NodeList; /** * Handles some ImageIO operations. */ public class ImageIOUtil { /** * Log instance */ private static final Log LOG = LogFactory.getLog(ImageIOUtil.class); /** * Default screen resolution: 72dpi. */ public static final int DEFAULT_SCREEN_RESOLUTION = 72; /** * Default compression quality: 1.0f. */ public static final float DEFAULT_COMPRESSION_QUALITY = 1.0f; private ImageIOUtil() { } /** * Writes a buffered image to a file using the given image format. See * {@link #writeImage(BufferedImage image, String formatName, * OutputStream output, int dpi, float quality)} for more details. * * @param image the image to be written * @param filename used to construct the filename for the individual image. * Its suffix will be used as the image format. * @param dpi the resolution in dpi (dots per inch) * @return true if the image file was produced, false if there was an error. * @throws IOException if an I/O error occurs */ public static boolean writeImage(BufferedImage image, String filename, int dpi) throws IOException { File file = new File(filename); FileOutputStream output = new FileOutputStream(file); try { String formatName = filename.substring(filename.lastIndexOf('.') + 1); return writeImage(image, formatName, output, dpi); } finally { output.close(); } } /** * Writes a buffered image to a file using the given image format. See * {@link #writeImage(BufferedImage image, String formatName, * OutputStream output, int dpi, float quality)} for more details. * * @param image the image to be written * @param formatName the target format (ex. "png") which is also the suffix * for the filename * @param filename used to construct the filename for the individual image. * The formatName parameter will be used as the suffix. * @param dpi the resolution in dpi (dots per inch) * @return true if the image file was produced, false if there was an error. * @throws IOException if an I/O error occurs * @deprecated use * {@link #writeImage(BufferedImage image, String filename, int dpi)}, which * uses the full filename instead of just the prefix. */ @Deprecated public static boolean writeImage(BufferedImage image, String formatName, String filename, int dpi) throws IOException { File file = new File(filename + "." + formatName); FileOutputStream output = new FileOutputStream(file); try { return writeImage(image, formatName, output, dpi); } finally { output.close(); } } /** * Writes a buffered image to a file using the given image format. See * {@link #writeImage(BufferedImage image, String formatName, * OutputStream output, int dpi, float quality)} for more details. * * @param image the image to be written * @param formatName the target format (ex. "png") * @param output the output stream to be used for writing * @return true if the image file was produced, false if there was an error. * @throws IOException if an I/O error occurs */ public static boolean writeImage(BufferedImage image, String formatName, OutputStream output) throws IOException { return writeImage(image, formatName, output, DEFAULT_SCREEN_RESOLUTION); } /** * Writes a buffered image to a file using the given image format. See * {@link #writeImage(BufferedImage image, String formatName, * OutputStream output, int dpi, float quality)} for more details. * * @param image the image to be written * @param formatName the target format (ex. "png") * @param output the output stream to be used for writing * @param dpi resolution to be used when writing the image * @return true if the image file was produced, false if there was an error. * @throws IOException if an I/O error occurs */ public static boolean writeImage(BufferedImage image, String formatName, OutputStream output, int dpi) throws IOException { return writeImage(image, formatName, output, dpi, DEFAULT_COMPRESSION_QUALITY); } /** * Writes a buffered image to a file using the given image format. * Compression is fixed for PNG, GIF, BMP and WBMP, dependent of the quality * parameter for JPG, and dependent of bit count for TIFF (a bitonal image * will be compressed with CCITT G4, a color image with LZW). Creating a * TIFF image is only supported if the jai_imageio library is in the class * path. * * @param image the image to be written * @param formatName the target format (ex. "png") * @param output the output stream to be used for writing * @param dpi resolution to be used when writing the image * @param quality quality to be used when compressing the image (0 < * quality < 1.0f) * @return true if the image file was produced, false if there was an error. * @throws IOException if an I/O error occurs */ public static boolean writeImage(BufferedImage image, String formatName, OutputStream output, int dpi, float quality) throws IOException { ImageOutputStream imageOutput = null; ImageWriter writer = null; try { // find suitable image writer Iterator writers = ImageIO.getImageWritersByFormatName(formatName); ImageWriteParam param = null; IIOMetadata metadata = null; // Loop until we get the best driver, i.e. one that supports // setting dpi in the standard metadata format; however we'd also // accept a driver that can't, if a better one can't be found while (writers.hasNext()) { if (writer != null) { writer.dispose(); } writer = writers.next(); param = writer.getDefaultWriteParam(); metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(image), param); if (metadata != null && !metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) { break; } } if (writer == null) { LOG.error("No ImageWriter found for '" + formatName + "' format"); StringBuilder sb = new StringBuilder(); String[] writerFormatNames = ImageIO.getWriterFormatNames(); for (String fmt : writerFormatNames) { sb.append(fmt); sb.append(' '); } LOG.error("Supported formats: " + sb); return false; } // compression if (param != null && param.canWriteCompressed()) { param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); if (formatName.toLowerCase().startsWith("tif")) { // TIFF compression TIFFUtil.setCompressionType(param, image); } else { param.setCompressionType(param.getCompressionTypes()[0]); param.setCompressionQuality(quality); } } if (formatName.toLowerCase().startsWith("tif")) { // TIFF metadata TIFFUtil.updateMetadata(metadata, image, dpi); } else if ("jpeg".equals(formatName.toLowerCase()) || "jpg".equals(formatName.toLowerCase())) { // This segment must be run before other meta operations, // or else "IIOInvalidTreeException: Invalid node: app0JFIF" // The other (general) "meta" methods may not be used, because // this will break the reading of the meta data in tests JPEGUtil.updateMetadata(metadata, dpi); } else { // write metadata is possible if (metadata != null && !metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) { setDPI(metadata, dpi, formatName); } } // write imageOutput = ImageIO.createImageOutputStream(output); writer.setOutput(imageOutput); writer.write(null, new IIOImage(image, null, metadata), param); } finally { if (writer != null) { writer.dispose(); } if (imageOutput != null) { imageOutput.close(); } } return true; } /** * Gets the named child node, or creates and attaches it. * * @param parentNode the parent node * @param name name of the child node * * @return the existing or just created child node */ private static IIOMetadataNode getOrCreateChildNode(IIOMetadataNode parentNode, String name) { NodeList nodeList = parentNode.getElementsByTagName(name); if (nodeList != null && nodeList.getLength() > 0) { return (IIOMetadataNode) nodeList.item(0); } IIOMetadataNode childNode = new IIOMetadataNode(name); parentNode.appendChild(childNode); return childNode; } // sets the DPI metadata private static void setDPI(IIOMetadata metadata, int dpi, String formatName) { IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(STANDARD_METADATA_FORMAT); IIOMetadataNode dimension = getOrCreateChildNode(root, "Dimension"); // PNG writer doesn't conform to the spec which is // "The width of a pixel, in millimeters" // but instead counts the pixels per millimeter float res = "PNG".equals(formatName.toUpperCase()) ? dpi / 25.4f : 25.4f / dpi; IIOMetadataNode child; child = getOrCreateChildNode(dimension, "HorizontalPixelSize"); child.setAttribute("value", Double.toString(res)); child = getOrCreateChildNode(dimension, "VerticalPixelSize"); child.setAttribute("value", Double.toString(res)); try { metadata.mergeTree(STANDARD_METADATA_FORMAT, root); } catch (IIOInvalidTreeException e) { // should never happen throw new RuntimeException(e); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFImageWriter.java0000644000000000000000000001217712645757432025412 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.awt.HeadlessException; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; /** * This class writes single pages of a pdf to a file. * * @author Daniel Wilson * */ public class PDFImageWriter extends PDFStreamEngine { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFImageWriter.class); /** * Instantiate a new PDFImageWriter object. */ public PDFImageWriter() { } /** * Instantiate a new PDFImageWriter object. Loading all of the operator mappings from the properties object that is * passed in. * * @param props * The properties containing the mapping of operators to PDFOperator classes. * * @throws IOException * If there is an error reading the properties. */ public PDFImageWriter(Properties props) throws IOException { super(props); } /** * Converts a given page range of a PDF document to bitmap images by calling * {@link #writeImage(PDDocument document, String imageFormat, String password, int startPage, int endPage, * String outputPrefix, int imageType, int resolution)} with imageType {@link BufferedImage}.TYPE_INT_RGB * and screen resolution, or 96dpi if screen resolution is unavailable. * * @param document the PDF document * @param imageFormat the target format (ex. "png") * @param password the password (needed if the PDF is encrypted) * @param startPage the start page (1 is the first page) * @param endPage the end page (set to Integer.MAX_VALUE for all pages) * @param outputPrefix used to construct the filename for the individual images * @return true if the images were produced, false if there was an error * @throws IOException * if an I/O error occurs */ public boolean writeImage(PDDocument document, String imageFormat, String password, int startPage, int endPage, String outputPrefix) throws IOException { int resolution; try { resolution = Toolkit.getDefaultToolkit().getScreenResolution(); } catch (HeadlessException e) { resolution = 96; } return writeImage(document, imageFormat, password, startPage, endPage, outputPrefix, BufferedImage.TYPE_INT_RGB, resolution); } /** * Converts a given page range of a PDF document to bitmap images. * * @param document * the PDF document * @param imageFormat * the target format (ex. "png") * @param password * the password (needed if the PDF is encrypted) * @param startPage * the start page (1 is the first page) * @param endPage * the end page (set to Integer.MAX_VALUE for all pages) * @param outputPrefix * used to construct the filename for the individual images * @param imageType * the image type (see {@link BufferedImage}.TYPE_*) * @param resolution * the resolution in dpi (dots per inch) * @return true if the images were produced, false if there was an error * @throws IOException * if an I/O error occurs */ public boolean writeImage(PDDocument document, String imageFormat, String password, int startPage, int endPage, String outputPrefix, int imageType, int resolution) throws IOException { boolean bSuccess = true; List pages = document.getDocumentCatalog().getAllPages(); int pagesSize = pages.size(); for (int i = startPage - 1; i < endPage && i < pagesSize; i++) { PDPage page = pages.get(i); BufferedImage image = page.convertToImage(imageType, resolution); String fileName = outputPrefix + (i + 1) + "." + imageFormat; LOG.info("Writing: " + fileName); bSuccess &= ImageIOUtil.writeImage(image, fileName, resolution); } return bSuccess; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStripper.java0000644000000000000000000022336512645757432025653 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.SortedMap; import java.util.SortedSet; import java.util.StringTokenizer; import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; import java.util.regex.Pattern; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem; import org.apache.pdfbox.pdmodel.interactive.pagenavigation.PDThreadBead; /** * This class will take a pdf document and strip out all of the text and ignore the * formatting and such. Please note; it is up to clients of this class to verify that * a specific user has the correct permissions to extract text from the * PDF document. * * The basic flow of this process is that we get a document and use a series of * processXXX() functions that work on smaller and smaller chunks of the page. * Eventually, we fully process each page and then print it. * * @author Ben Litchfield * */ public class PDFTextStripper extends PDFStreamEngine { private static final String thisClassName = PDFTextStripper.class.getSimpleName().toLowerCase(); private static float DEFAULT_INDENT_THRESHOLD = 2.0f; private static float DEFAULT_DROP_THRESHOLD = 2.5f; private static final boolean useCustomQuicksort; //enable the ability to set the default indent/drop thresholds //with -D system properties: // pdftextstripper.indent // pdftextstripper.drop static { String sdrop = null, sindent = null; try { String prop = thisClassName + ".indent"; sindent = System.getProperty(prop); prop = thisClassName + ".drop"; sdrop = System.getProperty(prop); } catch (SecurityException e) { // PDFBOX-1946 when run in an applet // ignore and use default } if (sindent != null && sindent.length() > 0) { try { float f = Float.parseFloat(sindent); DEFAULT_INDENT_THRESHOLD = f; } catch (NumberFormatException nfe) { //ignore and use default } } if (sdrop != null && sdrop.length() > 0) { try { float f = Float.parseFloat(sdrop); DEFAULT_DROP_THRESHOLD = f; } catch (NumberFormatException nfe) { //ignore and use default } } // check if we need to use the custom quicksort algorithm as a // workaround to the transitivity issue of TextPositionComparator: // https://issues.apache.org/jira/browse/PDFBOX-1512 boolean is16orLess = false; try { String version = System.getProperty("java.specification.version"); StringTokenizer st = new StringTokenizer(version, "."); int majorVersion = Integer.parseInt(st.nextToken()); int minorVersion = 0; if (st.hasMoreTokens()) { minorVersion = Integer.parseInt(st.nextToken()); } is16orLess = majorVersion == 1 && minorVersion <= 6; } catch (SecurityException e) { // when run in an applet ignore and use default // assume 1.7 or higher so that quicksort is used } catch (NumberFormatException nfe) { // should never happen, but if it does, // assume 1.7 or higher so that quicksort is used } useCustomQuicksort = !is16orLess; } /** * The platforms line separator. */ protected final String systemLineSeparator = System.getProperty("line.separator"); private String lineSeparator = systemLineSeparator; private String pageSeparator = systemLineSeparator; private String wordSeparator = " "; private String paragraphStart = ""; private String paragraphEnd = ""; private String pageStart = ""; private String pageEnd = pageSeparator; private String articleStart = ""; private String articleEnd = ""; private int currentPageNo = 0; private int startPage = 1; private int endPage = Integer.MAX_VALUE; private PDOutlineItem startBookmark = null; private int startBookmarkPageNumber = -1; private PDOutlineItem endBookmark = null; private int endBookmarkPageNumber = -1; private boolean suppressDuplicateOverlappingText = true; private boolean shouldSeparateByBeads = true; private boolean sortByPosition = false; private boolean addMoreFormatting = false; private float indentThreshold = DEFAULT_INDENT_THRESHOLD; private float dropThreshold = DEFAULT_DROP_THRESHOLD; // We will need to estimate where to add spaces. // These are used to help guess. private float spacingTolerance = .5f; private float averageCharTolerance = .3f; private List beadRectangles = null; /** * The charactersByArticle is used to extract text by article divisions. For example * a PDF that has two columns like a newspaper, we want to extract the first column and * then the second column. In this example the PDF would have 2 beads(or articles), one for * each column. The size of the charactersByArticle would be 5, because not all text on the * screen will fall into one of the articles. The five divisions are shown below * * Text before first article * first article text * text between first article and second article * second article text * text after second article * * Most PDFs won't have any beads, so charactersByArticle will contain a single entry. */ protected Vector> charactersByArticle = new Vector>(); private Map>> characterListMapping = new HashMap>>(); /** * encoding that text will be written in (or null). */ protected String outputEncoding; /** * The document to read. */ protected PDDocument document; /** * The stream to write the output to. */ protected Writer output; /** * The normalizer is used to remove text ligatures/presentation forms * and to correct the direction of right to left text, such as Arabic and Hebrew. */ private TextNormalize normalize = null; /** * True if we started a paragraph but haven't ended it * yet. */ private boolean inParagraph; /** * Instantiate a new PDFTextStripper object. This object will load * properties from PDFTextStripper.properties and will not do * anything special to convert the text to a more encoding-specific * output. * * @throws IOException If there is an error loading the properties. */ public PDFTextStripper() throws IOException { super( ResourceLoader.loadProperties( "org/apache/pdfbox/resources/PDFTextStripper.properties", true ) ); this.outputEncoding = null; normalize = new TextNormalize(this.outputEncoding); } /** * Instantiate a new PDFTextStripper object. Loading all of the operator mappings * from the properties object that is passed in. Does not convert the text * to more encoding-specific output. * * @param props The properties containing the mapping of operators to PDFOperator * classes. * * @throws IOException If there is an error reading the properties. */ public PDFTextStripper( Properties props ) throws IOException { super( props ); this.outputEncoding = null; normalize = new TextNormalize(this.outputEncoding); } /** * Instantiate a new PDFTextStripper object. This object will load * properties from PDFTextStripper.properties and will apply * encoding-specific conversions to the output text. * * @param encoding The encoding that the output will be written in. * @throws IOException If there is an error reading the properties. */ public PDFTextStripper( String encoding ) throws IOException { super( ResourceLoader.loadProperties( "org/apache/pdfbox/resources/PDFTextStripper.properties", true )); this.outputEncoding = encoding; normalize = new TextNormalize(this.outputEncoding); } /** * This will return the text of a document. See writeText.
* NOTE: The document must not be encrypted when coming into this method. * * @param doc The document to get the text from. * @return The text of the PDF document. * @throws IOException if the doc state is invalid or it is encrypted. */ public String getText( PDDocument doc ) throws IOException { StringWriter outputStream = new StringWriter(); writeText( doc, outputStream ); return outputStream.toString(); } /** * @deprecated * @see PDFTextStripper#getText( PDDocument ) * @param doc The document to extract the text from. * @return The document text. * @throws IOException If there is an error extracting the text. */ public String getText( COSDocument doc ) throws IOException { return getText( new PDDocument( doc ) ); } /** * @deprecated * @see PDFTextStripper#writeText( PDDocument, Writer ) * @param doc The document to extract the text. * @param outputStream The stream to write the text to. * @throws IOException If there is an error extracting the text. */ public void writeText( COSDocument doc, Writer outputStream ) throws IOException { writeText( new PDDocument( doc ), outputStream ); } /** * {@inheritDoc} */ public void resetEngine() { super.resetEngine(); currentPageNo = 0; document = null; if (charactersByArticle != null) { charactersByArticle.clear(); } if (characterListMapping != null) { characterListMapping.clear(); } } /** * This will take a PDDocument and write the text of that document to the print writer. * * @param doc The document to get the data from. * @param outputStream The location to put the text. * * @throws IOException If the doc is in an invalid state. */ public void writeText( PDDocument doc, Writer outputStream ) throws IOException { resetEngine(); document = doc; output = outputStream; if (getAddMoreFormatting()) { paragraphEnd = lineSeparator; pageStart = lineSeparator; articleStart = lineSeparator; articleEnd = lineSeparator; } startDocument(document); processPages( document.getDocumentCatalog().getAllPages() ); endDocument(document); } /** * This will process all of the pages and the text that is in them. * * @param pages The pages object in the document. * * @throws IOException If there is an error parsing the text. */ protected void processPages( List pages ) throws IOException { if( startBookmark != null ) { startBookmarkPageNumber = getPageNumber( startBookmark, pages ); } if( endBookmark != null ) { endBookmarkPageNumber = getPageNumber( endBookmark, pages ); } if( startBookmarkPageNumber == -1 && startBookmark != null && endBookmarkPageNumber == -1 && endBookmark != null && startBookmark.getCOSObject() == endBookmark.getCOSObject() ) { //this is a special case where both the start and end bookmark //are the same but point to nothing. In this case //we will not extract any text. startBookmarkPageNumber = 0; endBookmarkPageNumber = 0; } Iterator pageIter = pages.iterator(); while( pageIter.hasNext() ) { PDPage nextPage = (PDPage)pageIter.next(); PDStream contentStream = nextPage.getContents(); currentPageNo++; if( contentStream != null ) { COSStream contents = contentStream.getStream(); processPage( nextPage, contents ); } } } private int getPageNumber( PDOutlineItem bookmark, List allPages ) throws IOException { int pageNumber = -1; PDPage page = bookmark.findDestinationPage( document ); if( page != null ) { pageNumber = allPages.indexOf( page )+1;//use one based indexing } return pageNumber; } /** * This method is available for subclasses of this class. It will be called before processing * of the document start. * * @param pdf The PDF document that is being processed. * @throws IOException If an IO error occurs. */ protected void startDocument(PDDocument pdf) throws IOException { // no default implementation, but available for subclasses } /** * This method is available for subclasses of this class. It will be called after processing * of the document finishes. * * @param pdf The PDF document that is being processed. * @throws IOException If an IO error occurs. */ protected void endDocument(PDDocument pdf ) throws IOException { // no default implementation, but available for subclasses } /** * This will process the contents of a page. * * @param page The page to process. * @param content The contents of the page. * * @throws IOException If there is an error processing the page. */ protected void processPage( PDPage page, COSStream content ) throws IOException { if( currentPageNo >= startPage && currentPageNo <= endPage && (startBookmarkPageNumber == -1 || currentPageNo >= startBookmarkPageNumber ) && (endBookmarkPageNumber == -1 || currentPageNo <= endBookmarkPageNumber )) { startPage( page ); int numberOfArticleSections = 1; if (shouldSeparateByBeads) { fillBeadRectangles(page); numberOfArticleSections += beadRectangles.size() * 2; } int originalSize = charactersByArticle.size(); charactersByArticle.setSize( numberOfArticleSections ); for( int i=0; i)charactersByArticle.get( i )).clear(); } else { charactersByArticle.set( i, new ArrayList() ); } } characterListMapping.clear(); processStream( page, page.findResources(), content ); writePage(); endPage( page ); } } private void fillBeadRectangles(PDPage page) { beadRectangles = new ArrayList(); for (PDThreadBead bead : page.getThreadBeads()) { if (bead == null) { // can't skip, because of null entry handling in processTextPosition() beadRectangles.add(null); continue; } PDRectangle rect = bead.getRectangle(); // bead rectangle is in PDF coordinates (y=0 is bottom), // glyphs are in image coordinates (y=0 is top), // so we must flip PDRectangle mediaBox = page.findMediaBox(); float upperRightY = mediaBox.getUpperRightY() - rect.getLowerLeftY(); float lowerLeftY = mediaBox.getUpperRightY() - rect.getUpperRightY(); rect.setLowerLeftY(lowerLeftY); rect.setUpperRightY(upperRightY); // adjust for cropbox PDRectangle cropBox = page.findCropBox(); if (cropBox.getLowerLeftX() != 0 || cropBox.getLowerLeftY() != 0) { rect.setLowerLeftX(rect.getLowerLeftX() - cropBox.getLowerLeftX()); rect.setLowerLeftY(rect.getLowerLeftY() - cropBox.getLowerLeftY()); rect.setUpperRightX(rect.getUpperRightX() - cropBox.getLowerLeftX()); rect.setUpperRightY(rect.getUpperRightY() - cropBox.getLowerLeftY()); } beadRectangles.add(rect); } } /** * Start a new article, which is typically defined as a column * on a single page (also referred to as a bead). This assumes * that the primary direction of text is left to right. * Default implementation is to do nothing. Subclasses * may provide additional information. * * @throws IOException If there is any error writing to the stream. */ protected void startArticle() throws IOException { startArticle(true); } /** * Start a new article, which is typically defined as a column * on a single page (also referred to as a bead). * Default implementation is to do nothing. Subclasses * may provide additional information. * * @param isltr true if primary direction of text is left to right. * @throws IOException If there is any error writing to the stream. */ protected void startArticle(boolean isltr) throws IOException { output.write(getArticleStart()); } /** * End an article. Default implementation is to do nothing. Subclasses * may provide additional information. * * @throws IOException If there is any error writing to the stream. */ protected void endArticle() throws IOException { output.write(getArticleEnd()); } /** * Start a new page. Default implementation is to do nothing. Subclasses * may provide additional information. * * @param page The page we are about to process. * * @throws IOException If there is any error writing to the stream. */ protected void startPage( PDPage page ) throws IOException { //default is to do nothing. } /** * End a page. Default implementation is to do nothing. Subclasses * may provide additional information. * * @param page The page we are about to process. * * @throws IOException If there is any error writing to the stream. */ protected void endPage( PDPage page ) throws IOException { //default is to do nothing } private static final float ENDOFLASTTEXTX_RESET_VALUE = -1; private static final float MAXYFORLINE_RESET_VALUE = -Float.MAX_VALUE; private static final float EXPECTEDSTARTOFNEXTWORDX_RESET_VALUE = -Float.MAX_VALUE; private static final float MAXHEIGHTFORLINE_RESET_VALUE = -1; private static final float MINYTOPFORLINE_RESET_VALUE = Float.MAX_VALUE; private static final float LASTWORDSPACING_RESET_VALUE = -1; /** * This will print the text of the processed page to "output". * It will estimate, based on the coordinates of the text, where * newlines and word spacings should be placed. The text will be * sorted only if that feature was enabled. * * @throws IOException If there is an error writing the text. */ protected void writePage() throws IOException { float maxYForLine = MAXYFORLINE_RESET_VALUE; float minYTopForLine = MINYTOPFORLINE_RESET_VALUE; float endOfLastTextX = ENDOFLASTTEXTX_RESET_VALUE; float lastWordSpacing = LASTWORDSPACING_RESET_VALUE; float maxHeightForLine = MAXHEIGHTFORLINE_RESET_VALUE; PositionWrapper lastPosition = null; PositionWrapper lastLineStartPosition = null; boolean startOfPage = true;//flag to indicate start of page boolean startOfArticle = true; if(charactersByArticle.size() > 0) { writePageStart(); } for( int i = 0; i < charactersByArticle.size(); i++) { List textList = charactersByArticle.get( i ); if( getSortByPosition() ) { TextPositionComparator comparator = new TextPositionComparator(); // because the TextPositionComparator is not transitive, but // JDK7+ enforces transitivity on comparators, we need to use // a custom quicksort implementation (which is slower, unfortunately). if(useCustomQuicksort) { QuickSort.sort( textList, comparator ); } else { Collections.sort( textList, comparator ); } } Iterator textIter = textList.iterator(); /* Before we can display the text, we need to do some normalizing. * Arabic and Hebrew text is right to left and is typically stored * in its logical format, which means that the rightmost character is * stored first, followed by the second character from the right etc. * However, PDF stores the text in presentation form, which is left to * right. We need to do some normalization to convert the PDF data to * the proper logical output format. * * Note that if we did not sort the text, then the output of reversing the * text is undefined and can sometimes produce worse output then not trying * to reverse the order. Sorting should be done for these languages. * */ /* First step is to determine if we have any right to left text, and * if so, is it dominant. */ int ltrCnt = 0; int rtlCnt = 0; while( textIter.hasNext() ) { TextPosition position = (TextPosition)textIter.next(); String stringValue = position.getCharacter(); for (int a = 0; a < stringValue.length(); a++) { byte dir = Character.getDirectionality(stringValue.charAt(a)); if ((dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT ) || (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING) || (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE )) { ltrCnt++; } else if ((dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT ) || (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) || (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING) || (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE )) { rtlCnt++; } } } // choose the dominant direction boolean isRtlDominant = rtlCnt > ltrCnt; startArticle(!isRtlDominant); startOfArticle = true; // we will later use this to skip reordering boolean hasRtl = rtlCnt > 0; /* Now cycle through to print the text. * We queue up a line at a time before we print so that we can convert * the line from presentation form to logical form (if needed). */ List line = new ArrayList(); textIter = textList.iterator(); // start from the beginning again /* PDF files don't always store spaces. We will need to guess where we should add * spaces based on the distances between TextPositions. Historically, this was done * based on the size of the space character provided by the font. In general, this worked * but there were cases where it did not work. Calculating the average character width * and using that as a metric works better in some cases but fails in some cases where the * spacing worked. So we use both. NOTE: Adobe reader also fails on some of these examples. */ //Keeps track of the previous average character width float previousAveCharWidth = -1; while( textIter.hasNext() ) { TextPosition position = (TextPosition)textIter.next(); PositionWrapper current = new PositionWrapper(position); String characterValue = position.getCharacter(); //Resets the average character width when we see a change in font // or a change in the font size if(lastPosition != null && ((position.getFont() != lastPosition.getTextPosition().getFont()) || (position.getFontSize() != lastPosition.getTextPosition().getFontSize()))) { previousAveCharWidth = -1; } float positionX; float positionY; float positionWidth; float positionHeight; /* If we are sorting, then we need to use the text direction * adjusted coordinates, because they were used in the sorting. */ if (getSortByPosition()) { positionX = position.getXDirAdj(); positionY = position.getYDirAdj(); positionWidth = position.getWidthDirAdj(); positionHeight = position.getHeightDir(); } else { positionX = position.getX(); positionY = position.getY(); positionWidth = position.getWidth(); positionHeight = position.getHeight(); } //The current amount of characters in a word int wordCharCount = position.getIndividualWidths().length; /* Estimate the expected width of the space based on the * space character with some margin. */ float wordSpacing = position.getWidthOfSpace(); float deltaSpace = 0; if (wordSpacing == 0 || Float.isNaN(wordSpacing)) { deltaSpace = Float.MAX_VALUE; } else { if( lastWordSpacing < 0 ) { deltaSpace = (wordSpacing * getSpacingTolerance()); } else { deltaSpace = (((wordSpacing+lastWordSpacing)/2f)* getSpacingTolerance()); } } /* Estimate the expected width of the space based on the * average character width with some margin. This calculation does not * make a true average (average of averages) but we found that it gave the * best results after numerous experiments. Based on experiments we also found that * .3 worked well. */ float averageCharWidth = -1; if(previousAveCharWidth < 0) { averageCharWidth = (positionWidth/wordCharCount); } else { averageCharWidth = (previousAveCharWidth + (positionWidth/wordCharCount))/2f; } float deltaCharWidth = (averageCharWidth * getAverageCharTolerance()); //Compares the values obtained by the average method and the wordSpacing method and picks //the smaller number. float expectedStartOfNextWordX = EXPECTEDSTARTOFNEXTWORDX_RESET_VALUE; if(endOfLastTextX != ENDOFLASTTEXTX_RESET_VALUE) { if(deltaCharWidth > deltaSpace) { expectedStartOfNextWordX = endOfLastTextX + deltaSpace; } else { expectedStartOfNextWordX = endOfLastTextX + deltaCharWidth; } } if( lastPosition != null ) { if(startOfArticle) { lastPosition.setArticleStart(); startOfArticle = false; } // RDD - Here we determine whether this text object is on the current // line. We use the lastBaselineFontSize to handle the superscript // case, and the size of the current font to handle the subscript case. // Text must overlap with the last rendered baseline text by at least // a small amount in order to be considered as being on the same line. /* XXX BC: In theory, this check should really check if the next char is in full range * seen in this line. This is what I tried to do with minYTopForLine, but this caused a lot * of regression test failures. So, I'm leaving it be for now. */ if(!overlap(positionY, positionHeight, maxYForLine, maxHeightForLine)) { writeLine(normalize(line,isRtlDominant,hasRtl),isRtlDominant); line.clear(); lastLineStartPosition = handleLineSeparation(current, lastPosition, lastLineStartPosition, maxHeightForLine); endOfLastTextX = ENDOFLASTTEXTX_RESET_VALUE; expectedStartOfNextWordX = EXPECTEDSTARTOFNEXTWORDX_RESET_VALUE; maxYForLine = MAXYFORLINE_RESET_VALUE; maxHeightForLine = MAXHEIGHTFORLINE_RESET_VALUE; minYTopForLine = MINYTOPFORLINE_RESET_VALUE; } //Test if our TextPosition starts after a new word would be expected to start. if (expectedStartOfNextWordX != EXPECTEDSTARTOFNEXTWORDX_RESET_VALUE && expectedStartOfNextWordX < positionX && //only bother adding a space if the last character was not a space lastPosition.getTextPosition().getCharacter() != null && !lastPosition.getTextPosition().getCharacter().endsWith( " " ) ) { line.add(WordSeparator.getSeparator()); } } if (positionY >= maxYForLine) { maxYForLine = positionY; } // RDD - endX is what PDF considers to be the x coordinate of the // end position of the text. We use it in computing our metrics below. endOfLastTextX = positionX + positionWidth; // add it to the list if (characterValue != null) { if(startOfPage && lastPosition==null) { writeParagraphStart();//not sure this is correct for RTL? } line.add(position); } maxHeightForLine = Math.max( maxHeightForLine, positionHeight ); minYTopForLine = Math.min(minYTopForLine,positionY - positionHeight); lastPosition = current; if(startOfPage) { lastPosition.setParagraphStart(); lastPosition.setLineStart(); lastLineStartPosition = lastPosition; startOfPage=false; } lastWordSpacing = wordSpacing; previousAveCharWidth = averageCharWidth; } // print the final line if (line.size() > 0) { writeLine(normalize(line,isRtlDominant,hasRtl),isRtlDominant); writeParagraphEnd(); } endArticle(); } writePageEnd(); } private boolean overlap( float y1, float height1, float y2, float height2 ) { return within( y1, y2, .1f) || (y2 <= y1 && y2 >= y1-height1) || (y1 <= y2 && y1 >= y2-height2); } /** * Write the page separator value to the output stream. * @throws IOException * If there is a problem writing out the pageseparator to the document. */ protected void writePageSeperator() throws IOException { // RDD - newline at end of flush - required for end of page (so that the top // of the next page starts on its own line. output.write(getPageSeparator()); output.flush(); } /** * Write the line separator value to the output stream. * @throws IOException * If there is a problem writing out the lineseparator to the document. */ protected void writeLineSeparator( ) throws IOException { output.write(getLineSeparator()); } /** * Write the word separator value to the output stream. * @throws IOException * If there is a problem writing out the wordseparator to the document. */ protected void writeWordSeparator() throws IOException { output.write(getWordSeparator()); } /** * Write the string in TextPosition to the output stream. * * @param text The text to write to the stream. * @throws IOException If there is an error when writing the text. */ protected void writeCharacters( TextPosition text ) throws IOException { output.write( text.getCharacter() ); } /** * Write a Java string to the output stream. The default implementation will ignore the textPositions * and just calls {@link #writeString(String)}. * * @param text The text to write to the stream. * @param textPositions The TextPositions belonging to the text. * @throws IOException If there is an error when writing the text. */ protected void writeString(String text, List textPositions) throws IOException { writeString(text); } /** * Write a Java string to the output stream. * * @param text The text to write to the stream. * @throws IOException If there is an error when writing the text. */ protected void writeString( String text ) throws IOException { output.write( text ); } /** * This will determine of two floating point numbers are within a specified variance. * * @param first The first number to compare to. * @param second The second number to compare to. * @param variance The allowed variance. */ private boolean within( float first, float second, float variance ) { return second < first + variance && second > first - variance; } /** * This will process a TextPosition object and add the * text to the list of characters on a page. It takes care of * overlapping text. * * @param text The text to process. */ protected void processTextPosition( TextPosition text ) { boolean showCharacter = true; if( suppressDuplicateOverlappingText ) { showCharacter = false; String textCharacter = text.getCharacter(); float textX = text.getX(); float textY = text.getY(); TreeMap> sameTextCharacters = characterListMapping.get( textCharacter ); if( sameTextCharacters == null ) { sameTextCharacters = new TreeMap>(); characterListMapping.put( textCharacter, sameTextCharacters ); } // RDD - Here we compute the value that represents the end of the rendered // text. This value is used to determine whether subsequent text rendered // on the same line overwrites the current text. // // We subtract any positive padding to handle cases where extreme amounts // of padding are applied, then backed off (not sure why this is done, but there // are cases where the padding is on the order of 10x the character width, and // the TJ just backs up to compensate after each character). Also, we subtract // an amount to allow for kerning (a percentage of the width of the last // character). // boolean suppressCharacter = false; float tolerance = (text.getWidth()/textCharacter.length())/3.0f; SortedMap> xMatches = sameTextCharacters.subMap(textX - tolerance, textX + tolerance ); for (TreeSet xMatch : xMatches.values()) { SortedSet yMatches = xMatch.subSet(textY - tolerance , textY + tolerance ); if (!yMatches.isEmpty()) { suppressCharacter = true; break; } } if( !suppressCharacter ) { TreeSet ySet = sameTextCharacters.get(textX); if (ySet == null) { ySet = new TreeSet(); sameTextCharacters.put( textX, ySet ); } ySet.add( textY ); showCharacter = true; } } if( showCharacter ) { //if we are showing the character then we need to determine which //article it belongs to. int foundArticleDivisionIndex = -1; int notFoundButFirstLeftAndAboveArticleDivisionIndex = -1; int notFoundButFirstLeftArticleDivisionIndex = -1; int notFoundButFirstAboveArticleDivisionIndex = -1; float x = text.getX(); float y = text.getY(); if (shouldSeparateByBeads) { for (int i = 0; i < beadRectangles.size() && foundArticleDivisionIndex == -1; i++) { PDRectangle rect = beadRectangles.get(i); if( rect != null ) { if( rect.contains( x, y ) ) { foundArticleDivisionIndex = i*2+1; } else if( (x < rect.getLowerLeftX() || y < rect.getUpperRightY()) && notFoundButFirstLeftAndAboveArticleDivisionIndex == -1) { notFoundButFirstLeftAndAboveArticleDivisionIndex = i*2; } else if( x < rect.getLowerLeftX() && notFoundButFirstLeftArticleDivisionIndex == -1) { notFoundButFirstLeftArticleDivisionIndex = i*2; } else if( y < rect.getUpperRightY() && notFoundButFirstAboveArticleDivisionIndex == -1) { notFoundButFirstAboveArticleDivisionIndex = i*2; } } else { foundArticleDivisionIndex = 0; } } } else { foundArticleDivisionIndex = 0; } int articleDivisionIndex = -1; if( foundArticleDivisionIndex != -1 ) { articleDivisionIndex = foundArticleDivisionIndex; } else if( notFoundButFirstLeftAndAboveArticleDivisionIndex != -1 ) { articleDivisionIndex = notFoundButFirstLeftAndAboveArticleDivisionIndex; } else if( notFoundButFirstLeftArticleDivisionIndex != -1 ) { articleDivisionIndex = notFoundButFirstLeftArticleDivisionIndex; } else if( notFoundButFirstAboveArticleDivisionIndex != -1 ) { articleDivisionIndex = notFoundButFirstAboveArticleDivisionIndex; } else { articleDivisionIndex = charactersByArticle.size()-1; } List textList = (List) charactersByArticle.get( articleDivisionIndex ); /* In the wild, some PDF encoded documents put diacritics (accents on * top of characters) into a separate Tj element. When displaying them * graphically, the two chunks get overlayed. With text output though, * we need to do the overlay. This code recombines the diacritic with * its associated character if the two are consecutive. */ if(textList.isEmpty()) { textList.add(text); } else { /* test if we overlap the previous entry. * Note that we are making an assumption that we need to only look back * one TextPosition to find what we are overlapping. * This may not always be true. */ TextPosition previousTextPosition = (TextPosition)textList.get(textList.size()-1); if(text.isDiacritic() && previousTextPosition.contains(text)) { previousTextPosition.mergeDiacritic(text, normalize); } /* If the previous TextPosition was the diacritic, merge it into this * one and remove it from the list. */ else if(previousTextPosition.isDiacritic() && text.contains(previousTextPosition)) { text.mergeDiacritic(previousTextPosition, normalize); textList.remove(textList.size()-1); textList.add(text); } else { textList.add(text); } } } } /** * This is the page that the text extraction will start on. The pages start * at page 1. For example in a 5 page PDF document, if the start page is 1 * then all pages will be extracted. If the start page is 4 then pages 4 and 5 * will be extracted. The default value is 1. * * @return Value of property startPage. */ public int getStartPage() { return startPage; } /** * This will set the first page to be extracted by this class. * * @param startPageValue New value of 1-based startPage property. */ public void setStartPage(int startPageValue) { startPage = startPageValue; } /** * This will get the last page that will be extracted. This is inclusive, * for example if a 5 page PDF an endPage value of 5 would extract the * entire document, an end page of 2 would extract pages 1 and 2. This defaults * to Integer.MAX_VALUE such that all pages of the pdf will be extracted. * * @return Value of property endPage. */ public int getEndPage() { return endPage; } /** * This will set the last page to be extracted by this class. * * @param endPageValue New value of 1-based endPage property. */ public void setEndPage(int endPageValue) { endPage = endPageValue; } /** * Set the desired line separator for output text. The line.separator * system property is used if the line separator preference is not set * explicitly using this method. * * @param separator The desired line separator string. */ public void setLineSeparator(String separator) { lineSeparator = separator; } /** * This will get the line separator. * * @return The desired line separator string. */ public String getLineSeparator() { return lineSeparator; } /** * Set the desired page separator for output text. The line.separator * system property is used if the page separator preference is not set * explicitly using this method. * * @param separator The desired page separator string. * * @deprecated use {@link #setPageStart(String) and {@link #setPageEnd(String)} instead */ public void setPageSeparator(String separator) { pageSeparator = separator; } /** * This will get the word separator. * * @return The desired word separator string. */ public String getWordSeparator() { return wordSeparator; } /** * Set the desired word separator for output text. The PDFBox text extraction * algorithm will output a space character if there is enough space between * two words. By default a space character is used. If you need and accurate * count of characters that are found in a PDF document then you might want to * set the word separator to the empty string. * * @param separator The desired page separator string. */ public void setWordSeparator(String separator) { wordSeparator = separator; } /** * This will get the page separator. * * @return The page separator string. * * @deprecated use {@link #getPageStart()} and {@link #getPageEnd()} instead */ public String getPageSeparator() { return pageSeparator; } /** * @return Returns the suppressDuplicateOverlappingText. */ public boolean getSuppressDuplicateOverlappingText() { return suppressDuplicateOverlappingText; } /** * Get the current page number that is being processed. * * @return A 1 based number representing the current page. */ protected int getCurrentPageNo() { return currentPageNo; } /** * The output stream that is being written to. * * @return The stream that output is being written to. */ protected Writer getOutput() { return output; } /** * Character strings are grouped by articles. It is quite common that there * will only be a single article. This returns a List that contains List objects, * the inner lists will contain TextPosition objects. * * @return A double List of TextPositions for all text strings on the page. */ protected Vector> getCharactersByArticle() { return charactersByArticle; } /** * By default the text stripper will attempt to remove text that overlapps each other. * Word paints the same character several times in order to make it look bold. By setting * this to false all text will be extracted, which means that certain sections will be * duplicated, but better performance will be noticed. * * @param suppressDuplicateOverlappingTextValue The suppressDuplicateOverlappingText to set. */ public void setSuppressDuplicateOverlappingText( boolean suppressDuplicateOverlappingTextValue) { suppressDuplicateOverlappingText = suppressDuplicateOverlappingTextValue; } /** * This will tell if the text stripper should separate by beads. * * @return If the text will be grouped by beads. */ public boolean getSeparateByBeads() { return shouldSeparateByBeads; } /** * Set if the text stripper should group the text output by a list of beads. The default value is true! * * @param aShouldSeparateByBeads The new grouping of beads. */ public void setShouldSeparateByBeads(boolean aShouldSeparateByBeads) { shouldSeparateByBeads = aShouldSeparateByBeads; } /** * Get the bookmark where text extraction should end, inclusive. Default is null. * * @return The ending bookmark. */ public PDOutlineItem getEndBookmark() { return endBookmark; } /** * Set the bookmark where the text extraction should stop. * * @param aEndBookmark The ending bookmark. */ public void setEndBookmark(PDOutlineItem aEndBookmark) { endBookmark = aEndBookmark; } /** * Get the bookmark where text extraction should start, inclusive. Default is null. * * @return The starting bookmark. */ public PDOutlineItem getStartBookmark() { return startBookmark; } /** * Set the bookmark where text extraction should start, inclusive. * * @param aStartBookmark The starting bookmark. */ public void setStartBookmark(PDOutlineItem aStartBookmark) { startBookmark = aStartBookmark; } /** * This will tell if the text stripper should add some more text formatting. * @return true if some more text formatting will be added */ public boolean getAddMoreFormatting() { return addMoreFormatting; } /** * There will some additional text formatting be added if addMoreFormatting * is set to true. Default is false. * @param newAddMoreFormatting Tell PDFBox to add some more text formatting */ public void setAddMoreFormatting(boolean newAddMoreFormatting) { addMoreFormatting = newAddMoreFormatting; } /** * This will tell if the text stripper should sort the text tokens * before writing to the stream. * * @return true If the text tokens will be sorted before being written. */ public boolean getSortByPosition() { return sortByPosition; } /** * The order of the text tokens in a PDF file may not be in the same * as they appear visually on the screen. For example, a PDF writer may * write out all text by font, so all bold or larger text, then make a second * pass and write out the normal text.
* The default is to not sort by position.
*
* A PDF writer could choose to write each character in a different order. By * default PDFBox does not sort the text tokens before processing them due to * performance reasons. * * @param newSortByPosition Tell PDFBox to sort the text positions. */ public void setSortByPosition(boolean newSortByPosition) { sortByPosition = newSortByPosition; } /** * Get the current space width-based tolerance value that is being used * to estimate where spaces in text should be added. Note that the * default value for this has been determined from trial and error. * * @return The current tolerance / scaling factor */ public float getSpacingTolerance() { return spacingTolerance; } /** * Set the space width-based tolerance value that is used * to estimate where spaces in text should be added. Note that the * default value for this has been determined from trial and error. * Setting this value larger will reduce the number of spaces added. * * @param spacingToleranceValue tolerance / scaling factor to use */ public void setSpacingTolerance(float spacingToleranceValue) { spacingTolerance = spacingToleranceValue; } /** * Get the current character width-based tolerance value that is being used * to estimate where spaces in text should be added. Note that the * default value for this has been determined from trial and error. * * @return The current tolerance / scaling factor */ public float getAverageCharTolerance() { return averageCharTolerance; } /** * Set the character width-based tolerance value that is used * to estimate where spaces in text should be added. Note that the * default value for this has been determined from trial and error. * Setting this value larger will reduce the number of spaces added. * * @param averageCharToleranceValue average tolerance / scaling factor to use */ public void setAverageCharTolerance(float averageCharToleranceValue) { averageCharTolerance = averageCharToleranceValue; } /** * returns the multiple of whitespace character widths * for the current text which the current * line start can be indented from the previous line start * beyond which the current line start is considered * to be a paragraph start. * @return the number of whitespace character widths to use * when detecting paragraph indents. */ public float getIndentThreshold() { return indentThreshold; } /** * sets the multiple of whitespace character widths * for the current text which the current * line start can be indented from the previous line start * beyond which the current line start is considered * to be a paragraph start. The default value is 2.0. * * @param indentThresholdValue the number of whitespace character widths to use * when detecting paragraph indents. */ public void setIndentThreshold(float indentThresholdValue) { indentThreshold = indentThresholdValue; } /** * the minimum whitespace, as a multiple * of the max height of the current characters * beyond which the current line start is considered * to be a paragraph start. * @return the character height multiple for * max allowed whitespace between lines in * the same paragraph. */ public float getDropThreshold() { return dropThreshold; } /** * sets the minimum whitespace, as a multiple * of the max height of the current characters * beyond which the current line start is considered * to be a paragraph start. The default value is 2.5. * * @param dropThresholdValue the character height multiple for * max allowed whitespace between lines in * the same paragraph. */ public void setDropThreshold(float dropThresholdValue) { dropThreshold = dropThresholdValue; } /** * Returns the string which will be used at the beginning of a paragraph. * @return the paragraph start string */ public String getParagraphStart() { return paragraphStart; } /** * Sets the string which will be used at the beginning of a paragraph. * @param s the paragraph start string */ public void setParagraphStart(String s) { paragraphStart = s; } /** * Returns the string which will be used at the end of a paragraph. * @return the paragraph end string */ public String getParagraphEnd() { return paragraphEnd; } /** * Sets the string which will be used at the end of a paragraph. * @param s the paragraph end string */ public void setParagraphEnd(String s) { paragraphEnd = s; } /** * Returns the string which will be used at the beginning of a page. * @return the page start string */ public String getPageStart() { return pageStart; } /** * Sets the string which will be used at the beginning of a page. * @param pageStartValue the page start string */ public void setPageStart(String pageStartValue) { pageStart = pageStartValue; } /** * Returns the string which will be used at the end of a page. * @return the page end string */ public String getPageEnd() { return pageEnd; } /** * Sets the string which will be used at the end of a page. * @param pageEndValue the page end string */ public void setPageEnd(String pageEndValue) { pageEnd = pageEndValue; } /** * Returns the string which will be used at the beginning of an article. * @return the article start string */ public String getArticleStart() { return articleStart; } /** * Sets the string which will be used at the beginning of an article. * @param articleStartValue the article start string */ public void setArticleStart(String articleStartValue) { articleStart = articleStartValue; } /** * Returns the string which will be used at the end of an article. * @return the article end string */ public String getArticleEnd() { return articleEnd; } /** * Sets the string which will be used at the end of an article. * @param articleEndValue the article end string */ public void setArticleEnd(String articleEndValue) { articleEnd = articleEndValue; } /** * Reverse characters of a compound Arabic glyph. * When getSortByPosition() is true, inspect the sequence encoded * by one glyph. If the glyph encodes two or more Arabic characters, * reverse these characters from a logical order to a visual order. * This ensures that the bidirectional algorithm that runs later will * convert them back to a logical order. * * @param str a string obtained from font.encoding() * * @return the reversed string */ public String inspectFontEncoding(String str) { if (!sortByPosition || str == null || str.length() < 2) { return str; } for (int i = 0; i < str.length(); ++i) { if (Character.getDirectionality(str.charAt(i)) != Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) { return str; } } StringBuilder reversed = new StringBuilder(str.length()); for (int i = str.length() - 1; i >= 0; --i) { reversed.append(str.charAt(i)); } return reversed.toString(); } /** * handles the line separator for a new line given * the specified current and previous TextPositions. * @param current the current text position * @param lastPosition the previous text position * @param lastLineStartPosition the last text position that followed a line * separator. * @param maxHeightForLine max height for positions since lastLineStartPosition * @return start position of the last line * @throws IOException if something went wrong */ protected PositionWrapper handleLineSeparation(PositionWrapper current, PositionWrapper lastPosition, PositionWrapper lastLineStartPosition, float maxHeightForLine) throws IOException { current.setLineStart(); isParagraphSeparation(current, lastPosition, lastLineStartPosition, maxHeightForLine); lastLineStartPosition = current; if (current.isParagraphStart()) { if(lastPosition.isArticleStart()) { writeParagraphStart(); } else { writeLineSeparator(); writeParagraphSeparator(); } } else { writeLineSeparator(); } return lastLineStartPosition; } /** * tests the relationship between the last text position, the current text * position and the last text position that followed a line separator to * decide if the gap represents a paragraph separation. This should * only be called for consecutive text positions that first pass the * line separation test. *

* This base implementation tests to see if the lastLineStartPosition is * null OR if the current vertical position has dropped below the last text * vertical position by at least 2.5 times the current text height OR if the * current horizontal position is indented by at least 2 times the current * width of a space character.

*

* This also attempts to identify text that is indented under a hanging indent.

*

* This method sets the isParagraphStart and isHangingIndent flags on the current * position object.

* * @param position the current text position. This may have its isParagraphStart * or isHangingIndent flags set upon return. * @param lastPosition the previous text position (should not be null). * @param lastLineStartPosition the last text position that followed a line * separator. May be null. * @param maxHeightForLine max height for text positions since lasLineStartPosition. */ protected void isParagraphSeparation(PositionWrapper position, PositionWrapper lastPosition, PositionWrapper lastLineStartPosition, float maxHeightForLine) { boolean result = false; if(lastLineStartPosition == null) { result = true; } else { float yGap = Math.abs(position.getTextPosition().getYDirAdj()- lastPosition.getTextPosition().getYDirAdj()); float newYVal = multiplyFloat(getDropThreshold(), maxHeightForLine); // do we need to flip this for rtl? float xGap = position.getTextPosition().getXDirAdj() - lastLineStartPosition.getTextPosition().getXDirAdj(); float newXVal = multiplyFloat(getIndentThreshold(), position.getTextPosition().getWidthOfSpace()); float positionWidth = multiplyFloat(0.25f, position.getTextPosition().getWidth()); if (yGap > newYVal) { result = true; } else if (xGap > newXVal) { //text is indented, but try to screen for hanging indent if(!lastLineStartPosition.isParagraphStart()) { result = true; } else { position.setHangingIndent(); } } else if(xGap < -position.getTextPosition().getWidthOfSpace()) { //text is left of previous line. Was it a hanging indent? if(!lastLineStartPosition.isParagraphStart()) { result = true; } } else if (Math.abs(xGap) < positionWidth) { //current horizontal position is within 1/4 a char of the last //linestart. We'll treat them as lined up. if(lastLineStartPosition.isHangingIndent()) { position.setHangingIndent(); } else if(lastLineStartPosition.isParagraphStart()) { //check to see if the previous line looks like //any of a number of standard list item formats Pattern liPattern = matchListItemPattern(lastLineStartPosition); if(liPattern!=null) { Pattern currentPattern = matchListItemPattern(position); if(liPattern == currentPattern) { result = true; } } } } } if(result) { position.setParagraphStart(); } } private float multiplyFloat(float value1, float value2) { // multiply 2 floats and truncate the resulting value to 3 decimal places // to avoid wrong results when comparing with another float return Math.round(value1 * value2 * 1000) / 1000f; } /** * writes the paragraph separator string to the output. * @throws IOException if something went wrong */ protected void writeParagraphSeparator()throws IOException { writeParagraphEnd(); writeParagraphStart(); } /** * Write something (if defined) at the start of a paragraph. * @throws IOException if something went wrong */ protected void writeParagraphStart() throws IOException { if (inParagraph) { writeParagraphEnd(); inParagraph = false; } output.write(getParagraphStart()); inParagraph = true; } /** * Write something (if defined) at the end of a paragraph. * @throws IOException if something went wrong */ protected void writeParagraphEnd() throws IOException { if (!inParagraph) { writeParagraphStart(); } output.write(getParagraphEnd()); inParagraph = false; } /** * Write something (if defined) at the start of a page. * @throws IOException if something went wrong */ protected void writePageStart()throws IOException { output.write(getPageStart()); } /** * Write something (if defined) at the end of a page. * @throws IOException if something went wrong */ protected void writePageEnd()throws IOException { output.write(getPageEnd()); } /** * returns the list item Pattern object that matches * the text at the specified PositionWrapper or null * if the text does not match such a pattern. The list * of Patterns tested against is given by the * {@link #getListItemPatterns()} method. To add to * the list, simply override that method (if sub-classing) * or explicitly supply your own list using * {@link #setListItemPatterns(List)}. * @param pw position * @return the matching pattern */ protected Pattern matchListItemPattern(PositionWrapper pw) { TextPosition tp = pw.getTextPosition(); String txt = tp.getCharacter(); return matchPattern(txt,getListItemPatterns()); } /** * a list of regular expressions that match commonly used * list item formats, i.e. bullets, numbers, letters, * Roman numerals, etc. Not meant to be * comprehensive. */ private static final String[] LIST_ITEM_EXPRESSIONS = { "\\.", "\\d+\\.", "\\[\\d+\\]", "\\d+\\)", "[A-Z]\\.", "[a-z]\\.", "[A-Z]\\)", "[a-z]\\)", "[IVXL]+\\.", "[ivxl]+\\.", }; private List listOfPatterns = null; /** * use to supply a different set of regular expression * patterns for matching list item starts. * * @param patterns list of patterns */ protected void setListItemPatterns(List patterns) { listOfPatterns = patterns; } /** * returns a list of regular expression Patterns representing * different common list item formats. For example * numbered items of form: *
    *
  1. some text
  2. *
  3. more text
  4. *
* or *
    *
  • some text
  • *
  • more text
  • *
* etc., all begin with some character pattern. The pattern "\\d+\." (matches "1.", "2.", ...) * or "\[\\d+\]" (matches "[1]", "[2]", ...). *

* This method returns a list of such regular expression Patterns. * @return a list of Pattern objects. */ protected List getListItemPatterns() { if(listOfPatterns == null) { listOfPatterns = new ArrayList(); for(String expression : LIST_ITEM_EXPRESSIONS) { Pattern p = Pattern.compile(expression); listOfPatterns.add(p); } } return listOfPatterns; } /** * iterates over the specified list of Patterns until * it finds one that matches the specified string. Then * returns the Pattern. *

* Order of the supplied list of patterns is important as * most common patterns should come first. Patterns * should be strict in general, and all will be * used with case sensitivity on. *

* @param string the string to be searched * @param patterns list of patterns * @return matching pattern */ protected static final Pattern matchPattern(String string, List patterns) { Pattern matchedPattern = null; for(Pattern p : patterns) { if(p.matcher(string).matches()) { return p; } } return matchedPattern; } /** * Write a list of string containing a whole line of a document. * @param line a list with the words of the given line * @param isRtlDominant determines if rtl or ltl is dominant * @throws IOException if something went wrong */ private void writeLine(List line, boolean isRtlDominant) throws IOException { int numberOfStrings = line.size(); for(int i=0; i normalize(List line, boolean isRtlDominant, boolean hasRtl) { LinkedList normalized = new LinkedList(); StringBuilder lineBuilder = new StringBuilder(); List wordPositions = new ArrayList(); // concatenate the pieces of text in opposite order if RTL is dominant if (isRtlDominant) { int numberOfPositions = line.size(); for(int i = numberOfPositions-1;i>=0;i--) { lineBuilder = normalizeAdd(normalized, lineBuilder, wordPositions, line.get(i)); } } else { for(TextPosition text : line) { lineBuilder = normalizeAdd(normalized, lineBuilder, wordPositions, text); } } if (lineBuilder.length() > 0) { normalized.add(createWord(lineBuilder.toString(), wordPositions)); } return normalized; } /** * Used within {@link #normalize(List, boolean, boolean)} to create a single {@link WordWithTextPositions} * entry. */ private WordWithTextPositions createWord(String word, List wordPositions) { return new WordWithTextPositions(normalize.normalizePres(word), wordPositions); } /** * Used within {@link #normalize(List, boolean, boolean)} to handle a {@link TextPosition}. * @return The StringBuilder that must be used when calling this method. */ private StringBuilder normalizeAdd(LinkedList normalized, StringBuilder lineBuilder, List wordPositions, TextPosition text) { if (text instanceof WordSeparator) { normalized.add(createWord(lineBuilder.toString(), new ArrayList(wordPositions))); lineBuilder = new StringBuilder(); wordPositions.clear(); } else { lineBuilder.append(text.getCharacter()); wordPositions.add(text); } return lineBuilder; } /** * internal marker class. Used as a place holder in * a line of TextPositions. * @author ME21969 * */ private static final class WordSeparator extends TextPosition { private static final WordSeparator separator = new WordSeparator(); private WordSeparator() { } public static final WordSeparator getSeparator() { return separator; } } /** * Internal class that maps strings to lists of {@link TextPosition} arrays. * Note that the number of entries in that list may differ from the number of characters in the * string due to normalization. * * @author Axel Drfler */ private static final class WordWithTextPositions { protected String text; protected List textPositions; public WordWithTextPositions(String word, List positions) { text = word; textPositions = positions; } public String getText() { return text; } public List getTextPositions() { return textPositions; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/JPEGUtil.java0000644000000000000000000000631112645757432024215 0ustar rootroot/* * Copyright 2014 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import static org.apache.pdfbox.util.MetaUtil.JPEG_NATIVE_FORMAT; import static org.apache.pdfbox.util.MetaUtil.debugLogMetadata; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * * @author Tilman Hausherr */ class JPEGUtil { /** * Set dpi in a JPEG file * * @param metadata the meta data * @param dpi the dpi * * @throws IIOInvalidTreeException if something goes wrong */ static void updateMetadata(IIOMetadata metadata, int dpi) throws IIOInvalidTreeException { debugLogMetadata(metadata, JPEG_NATIVE_FORMAT); // https://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/image/writer/imageio/ImageIOJPEGImageWriter.java // http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html Element root = (Element) metadata.getAsTree(JPEG_NATIVE_FORMAT); NodeList jvarNodeList = root.getElementsByTagName("JPEGvariety"); Element jvarChild; if (jvarNodeList.getLength() == 0) { jvarChild = new IIOMetadataNode("JPEGvariety"); root.appendChild(jvarChild); } else { jvarChild = (Element) jvarNodeList.item(0); } NodeList jfifNodeList = jvarChild.getElementsByTagName("app0JFIF"); Element jfifChild; if (jfifNodeList.getLength() == 0) { jfifChild = new IIOMetadataNode("app0JFIF"); jvarChild.appendChild(jfifChild); } else { jfifChild = (Element) jfifNodeList.item(0); } if (jfifChild.getAttribute("majorVersion").length() == 0) { jfifChild.setAttribute("majorVersion", "1"); } if (jfifChild.getAttribute("minorVersion").length() == 0) { jfifChild.setAttribute("minorVersion", "2"); } jfifChild.setAttribute("resUnits", "1"); // inch jfifChild.setAttribute("Xdensity", Integer.toString(dpi)); jfifChild.setAttribute("Ydensity", Integer.toString(dpi)); if (jfifChild.getAttribute("thumbWidth").length() == 0) { jfifChild.setAttribute("thumbWidth", "0"); } if (jfifChild.getAttribute("thumbHeight").length() == 0) { jfifChild.setAttribute("thumbHeight", "0"); } metadata.setFromTree(JPEG_NATIVE_FORMAT, root); // mergeTree doesn't work for ARGB } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/TextNormalize.java0000644000000000000000000001474012645757432025444 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.util.HashMap; /** * This class allows a caller to normalize text in various ways. It will load the ICU4J jar file if it is defined on the * classpath. * * @author Brian Carrier * */ public class TextNormalize { private ICU4JImpl icu4j = null; private static final HashMap DIACHASH = new HashMap(); private String outputEncoding; static { populateDiacHash(); } /** * * @param encoding The Encoding that the text will eventually be written as (or null) */ public TextNormalize(String encoding) { findICU4J(); outputEncoding = encoding; } private void findICU4J() { // see if we can load the icu4j classes from the classpath try { this.getClass().getClassLoader().loadClass("com.ibm.icu.text.Bidi"); this.getClass().getClassLoader().loadClass("com.ibm.icu.text.Normalizer"); icu4j = new ICU4JImpl(); } catch (ClassNotFoundException e) { icu4j = null; } } /* * Adds non-decomposing diacritics to the hash with their related combining character. These are values that the * unicode spec claims are equivalent but are not mapped in the form NFKC normalization method. Determined by going * through the Combining Diacritical Marks section of the Unicode spec and identifying which characters are not * mapped to by the normalization. */ private static void populateDiacHash() { DIACHASH.put(new Integer(0x0060), "\u0300"); DIACHASH.put(new Integer(0x02CB), "\u0300"); DIACHASH.put(new Integer(0x0027), "\u0301"); DIACHASH.put(new Integer(0x02B9), "\u0301"); DIACHASH.put(new Integer(0x02CA), "\u0301"); DIACHASH.put(new Integer(0x005e), "\u0302"); DIACHASH.put(new Integer(0x02C6), "\u0302"); DIACHASH.put(new Integer(0x007E), "\u0303"); DIACHASH.put(new Integer(0x02C9), "\u0304"); DIACHASH.put(new Integer(0x00B0), "\u030A"); DIACHASH.put(new Integer(0x02BA), "\u030B"); DIACHASH.put(new Integer(0x02C7), "\u030C"); DIACHASH.put(new Integer(0x02C8), "\u030D"); DIACHASH.put(new Integer(0x0022), "\u030E"); DIACHASH.put(new Integer(0x02BB), "\u0312"); DIACHASH.put(new Integer(0x02BC), "\u0313"); DIACHASH.put(new Integer(0x0486), "\u0313"); DIACHASH.put(new Integer(0x055A), "\u0313"); DIACHASH.put(new Integer(0x02BD), "\u0314"); DIACHASH.put(new Integer(0x0485), "\u0314"); DIACHASH.put(new Integer(0x0559), "\u0314"); DIACHASH.put(new Integer(0x02D4), "\u031D"); DIACHASH.put(new Integer(0x02D5), "\u031E"); DIACHASH.put(new Integer(0x02D6), "\u031F"); DIACHASH.put(new Integer(0x02D7), "\u0320"); DIACHASH.put(new Integer(0x02B2), "\u0321"); DIACHASH.put(new Integer(0x02CC), "\u0329"); DIACHASH.put(new Integer(0x02B7), "\u032B"); DIACHASH.put(new Integer(0x02CD), "\u0331"); DIACHASH.put(new Integer(0x005F), "\u0332"); DIACHASH.put(new Integer(0x204E), "\u0359"); } /** * Takes a line of text in presentation order and converts it to logical order. For most text other than Arabic and * Hebrew, the presentation and logical orders are the same. However, for Arabic and Hebrew, they are different and * if the text involves both RTL and LTR text then the Unicode BIDI algorithm must be used to determine how to map * between them. * * @param str Presentation form of line to convert (i.e. left most char is first char) * @param isRtlDominant true if the PAGE has a dominant right to left ordering * @return Logical form of string (or original string if ICU4J library is not on classpath) * * @deprecated isn't used anymore */ public String makeLineLogicalOrder(String str, boolean isRtlDominant) { if (icu4j != null) { return icu4j.makeLineLogicalOrder(str, isRtlDominant); } else { return str; } } /** * Normalize the presentation forms of characters in the string. For example, convert the single "fi" ligature to * "f" and "i". * * @param str String to normalize * @return Normalized string (or original string if ICU4J library is not on classpath) */ public String normalizePres(String str) { if (icu4j != null) { return icu4j.normalizePres(str); } else { return str; } } /** * Normalize the diacritic, for example, convert non-combining diacritic characters to their combining counterparts. * * @param str String to normalize * @return Normalized string (or original string if ICU4J library is not on classpath) */ public String normalizeDiac(String str) { /* * Unicode contains special combining forms of the diacritic characters and we want to use these. */ if (outputEncoding != null && outputEncoding.toUpperCase().startsWith("UTF")) { Integer c = new Integer(str.charAt(0)); // convert the characters not defined in the Unicode spec if (DIACHASH.containsKey(c)) { return (String) DIACHASH.get(c); } else if (icu4j != null) { return icu4j.normalizeDiac(str); } else { return str; } } else { return str; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java0000644000000000000000000006323212645757432025776 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDDocumentNameDestinationDictionary; import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.PDNumberTreeNode; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDFieldFactory; /** * This class will take a list of pdf documents and merge them, saving the * result in a new document. * * @author Ben Litchfield * */ public class PDFMergerUtility { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFMergerUtility.class); private static final String STRUCTURETYPE_DOCUMENT = "Document"; private final List sources; private final List fileInputStreams; private String destinationFileName; private OutputStream destinationStream; private boolean ignoreAcroFormErrors = false; /** * Instantiate a new PDFMergerUtility. */ public PDFMergerUtility() { sources = new ArrayList(); fileInputStreams = new ArrayList(); } /** * Get the name of the destination file. * * @return Returns the destination. */ public String getDestinationFileName() { return destinationFileName; } /** * Set the name of the destination file. * * @param destination The destination to set. */ public void setDestinationFileName(String destination) { destinationFileName = destination; } /** * Get the destination OutputStream. * * @return Returns the destination OutputStream. */ public OutputStream getDestinationStream() { return destinationStream; } /** * Set the destination OutputStream. * * @param destStream The destination to set. */ public void setDestinationStream(OutputStream destStream) { destinationStream = destStream; } /** * Add a source file to the list of files to merge. * * @param source Full path and file name of source document. */ public void addSource(String source) { addSource(new File(source)); } /** * Add a source file to the list of files to merge. * * @param source File representing source document */ public void addSource(File source) { try { FileInputStream stream = new FileInputStream(source); sources.add(stream); fileInputStreams.add(stream); } catch (Exception e) { throw new RuntimeException(e); } } /** * Add a source to the list of documents to merge. * * @param source InputStream representing source document */ public void addSource(InputStream source) { sources.add(source); } /** * Add a list of sources to the list of documents to merge. * * @param sourcesList List of InputStream objects representing source * documents */ public void addSources(List sourcesList) { sources.addAll(sourcesList); } /** * Merge the list of source documents, saving the result in the destination * file. * * @throws IOException If there is an error saving the document. * @throws COSVisitorException If an error occurs while saving the * destination file. */ public void mergeDocuments() throws IOException, COSVisitorException { mergeDocuments(false, null); } /** * Merge the list of source documents with the non sequential parser, saving * the result in the destination file. * * @param scratchFile location to store temp PDFBox data for this output * document, can be null if temp data is to be stored in memory * @throws IOException If there is an error saving the document. * @throws COSVisitorException If an error occurs while saving the * destination file. */ public void mergeDocumentsNonSeq(RandomAccess scratchFile) throws IOException, COSVisitorException { mergeDocuments(true, scratchFile); } private void mergeDocuments(boolean isNonSeq, RandomAccess scratchFile) throws IOException, COSVisitorException { PDDocument destination = null; InputStream sourceFile; PDDocument source; if (sources != null && sources.size() > 0) { ArrayList tobeclosed = new ArrayList(); try { Iterator sit = sources.iterator(); destination = new PDDocument(); while (sit.hasNext()) { sourceFile = sit.next(); if (isNonSeq) { source = PDDocument.loadNonSeq(sourceFile, scratchFile); } else { source = PDDocument.load(sourceFile); } tobeclosed.add(source); appendDocument(destination, source); } if (destinationStream == null) { destination.save(destinationFileName); } else { destination.save(destinationStream); } } finally { if (destination != null) { destination.close(); } for (PDDocument doc : tobeclosed) { doc.close(); } for (FileInputStream stream : fileInputStreams) { stream.close(); } } } } /** * append all pages from source to destination. * * @param destination the document to receive the pages * @param source the document originating the new pages * * @throws IOException If there is an error accessing data from either * document. */ public void appendDocument(PDDocument destination, PDDocument source) throws IOException { if (destination.isEncrypted()) { throw new IOException("Error: destination PDF is encrypted, can't append encrypted PDF documents."); } if (source.isEncrypted()) { throw new IOException("Error: source PDF is encrypted, can't append encrypted PDF documents."); } PDDocumentInformation destInfo = destination.getDocumentInformation(); PDDocumentInformation srcInfo = source.getDocumentInformation(); destInfo.getDictionary().mergeInto(srcInfo.getDictionary()); PDDocumentCatalog destCatalog = destination.getDocumentCatalog(); PDDocumentCatalog srcCatalog = source.getDocumentCatalog(); // use the highest version number for the resulting pdf float destVersion = destination.getDocument().getVersion(); float srcVersion = source.getDocument().getVersion(); if (destVersion < srcVersion) { destination.getDocument().setVersion(srcVersion); } if (destCatalog.getOpenAction() == null) { destCatalog.setOpenAction(srcCatalog.getOpenAction()); } PDFCloneUtility cloner = new PDFCloneUtility(destination); try { PDAcroForm destAcroForm = destCatalog.getAcroForm(); PDAcroForm srcAcroForm = srcCatalog.getAcroForm(); if (destAcroForm == null) { cloner.cloneForNewDocument(srcAcroForm); destCatalog.setAcroForm(srcAcroForm); } else { if (srcAcroForm != null) { mergeAcroForm(cloner, destAcroForm, srcAcroForm); } } } catch (IOException e) { // if we are not ignoring exceptions, we'll re-throw this if (!ignoreAcroFormErrors) { LOG.error (e, e); throw new IOException(e.getMessage()); } } catch (Exception e) { throw new RuntimeException(e); } COSArray destThreads = (COSArray) destCatalog.getCOSDictionary().getDictionaryObject(COSName.THREADS); COSArray srcThreads = (COSArray) cloner.cloneForNewDocument(destCatalog.getCOSDictionary().getDictionaryObject( COSName.THREADS)); if (destThreads == null) { destCatalog.getCOSDictionary().setItem(COSName.THREADS, srcThreads); } else { destThreads.addAll(srcThreads); } PDDocumentNameDictionary destNames = destCatalog.getNames(); PDDocumentNameDictionary srcNames = srcCatalog.getNames(); if (srcNames != null) { if (destNames == null) { destCatalog.getCOSDictionary().setItem(COSName.NAMES, cloner.cloneForNewDocument(srcNames)); } else { cloner.cloneMerge(srcNames, destNames); } } PDDocumentNameDestinationDictionary destDests = destCatalog.getDests(); PDDocumentNameDestinationDictionary srcDests = srcCatalog.getDests(); if (srcDests != null) { if (destDests == null) { destCatalog.getCOSDictionary().setItem(COSName.DESTS, cloner.cloneForNewDocument(srcDests)); } else { cloner.cloneMerge(srcDests, destDests); } } PDDocumentOutline destOutline = destCatalog.getDocumentOutline(); PDDocumentOutline srcOutline = srcCatalog.getDocumentOutline(); if (srcOutline != null) { if (destOutline == null) { PDDocumentOutline cloned = new PDDocumentOutline((COSDictionary) cloner.cloneForNewDocument(srcOutline)); destCatalog.setDocumentOutline(cloned); } else { PDOutlineItem first = srcOutline.getFirstChild(); if (first != null) { PDOutlineItem clonedFirst = new PDOutlineItem((COSDictionary) cloner.cloneForNewDocument(first)); destOutline.appendChild(clonedFirst); } } } String destPageMode = destCatalog.getPageMode(); String srcPageMode = srcCatalog.getPageMode(); if (destPageMode == null) { destCatalog.setPageMode(srcPageMode); } COSDictionary destLabels = (COSDictionary) destCatalog.getCOSDictionary().getDictionaryObject( COSName.PAGE_LABELS); COSDictionary srcLabels = (COSDictionary) srcCatalog.getCOSDictionary() .getDictionaryObject(COSName.PAGE_LABELS); if (srcLabels != null) { int destPageCount = destination.getNumberOfPages(); COSArray destNums; if (destLabels == null) { destLabels = new COSDictionary(); destNums = new COSArray(); destLabels.setItem(COSName.NUMS, destNums); destCatalog.getCOSDictionary().setItem(COSName.PAGE_LABELS, destLabels); } else { destNums = (COSArray) destLabels.getDictionaryObject(COSName.NUMS); } COSArray srcNums = (COSArray) srcLabels.getDictionaryObject(COSName.NUMS); if (srcNums != null) { for (int i = 0; i < srcNums.size(); i += 2) { COSNumber labelIndex = (COSNumber) srcNums.getObject(i); long labelIndexValue = labelIndex.intValue(); destNums.add(COSInteger.get(labelIndexValue + destPageCount)); destNums.add(cloner.cloneForNewDocument(srcNums.getObject(i + 1))); } } } COSStream destMetadata = (COSStream) destCatalog.getCOSDictionary().getDictionaryObject(COSName.METADATA); COSStream srcMetadata = (COSStream) srcCatalog.getCOSDictionary().getDictionaryObject(COSName.METADATA); if (destMetadata == null && srcMetadata != null) { PDStream newStream = new PDStream(destination, srcMetadata.getUnfilteredStream(), false); newStream.getStream().mergeInto(srcMetadata); destCatalog.getCOSDictionary().setItem(COSName.METADATA, newStream); } // merge logical structure hierarchy if logical structure information is available in both source pdf and // destination pdf boolean mergeStructTree = false; int destParentTreeNextKey = -1; COSDictionary destParentTreeDict = null; COSDictionary srcParentTreeDict = null; COSArray destNumbersArray = null; COSArray srcNumbersArray = null; PDMarkInfo destMark = destCatalog.getMarkInfo(); PDStructureTreeRoot destStructTree = destCatalog.getStructureTreeRoot(); PDMarkInfo srcMark = srcCatalog.getMarkInfo(); PDStructureTreeRoot srcStructTree = srcCatalog.getStructureTreeRoot(); if (destStructTree != null) { PDNumberTreeNode destParentTree = destStructTree.getParentTree(); destParentTreeNextKey = destStructTree.getParentTreeNextKey(); if (destParentTree != null) { destParentTreeDict = destParentTree.getCOSDictionary(); destNumbersArray = (COSArray) destParentTreeDict.getDictionaryObject(COSName.NUMS); if (destNumbersArray != null) { if (destParentTreeNextKey < 0) { destParentTreeNextKey = destNumbersArray.size() / 2; } if (destParentTreeNextKey > 0) { if (srcStructTree != null) { PDNumberTreeNode srcParentTree = srcStructTree.getParentTree(); if (srcParentTree != null) { srcParentTreeDict = srcParentTree.getCOSDictionary(); srcNumbersArray = (COSArray) srcParentTreeDict.getDictionaryObject(COSName.NUMS); if (srcNumbersArray != null) { mergeStructTree = true; } } } } } } if (destMark != null && destMark.isMarked() && !mergeStructTree) { destMark.setMarked(false); } if (!mergeStructTree) { destCatalog.setStructureTreeRoot(null); } } List pages = srcCatalog.getAllPages(); Iterator pageIter = pages.iterator(); HashMap objMapping = new HashMap(); while (pageIter.hasNext()) { PDPage page = pageIter.next(); PDPage newPage = new PDPage((COSDictionary) cloner.cloneForNewDocument(page.getCOSDictionary())); newPage.setCropBox(page.findCropBox()); newPage.setMediaBox(page.findMediaBox()); newPage.setRotation(page.findRotation()); // this is smart enough to just create references for resources that are used on multiple pages newPage.setResources(new PDResources((COSDictionary) cloner.cloneForNewDocument(page.findResources()))); if (mergeStructTree) { updateStructParentEntries(newPage, destParentTreeNextKey); objMapping.put(page.getCOSDictionary(), newPage.getCOSDictionary()); List oldAnnots = page.getAnnotations(); List newAnnots = newPage.getAnnotations(); for (int i = 0; i < oldAnnots.size(); i++) { objMapping.put(oldAnnots.get(i).getDictionary(), newAnnots.get(i).getDictionary()); } // TODO update mapping for XObjects } destination.addPage(newPage); } if (mergeStructTree) { updatePageReferences(srcNumbersArray, objMapping); for (int i = 0; i < srcNumbersArray.size() / 2; i++) { destNumbersArray.add(COSInteger.get(destParentTreeNextKey + i)); destNumbersArray.add(srcNumbersArray.getObject(i * 2 + 1)); } destParentTreeNextKey += srcNumbersArray.size() / 2; destParentTreeDict.setItem(COSName.NUMS, destNumbersArray); PDNumberTreeNode newParentTreeNode = new PDNumberTreeNode(destParentTreeDict, COSBase.class); destStructTree.setParentTree(newParentTreeNode); destStructTree.setParentTreeNextKey(destParentTreeNextKey); COSDictionary kDictLevel0 = new COSDictionary(); COSArray newKArray = new COSArray(); COSArray destKArray = destStructTree.getKArray(); COSArray srcKArray = srcStructTree.getKArray(); if (destKArray != null && srcKArray != null) { updateParentEntry(destKArray, kDictLevel0); newKArray.addAll(destKArray); if (mergeStructTree) { updateParentEntry(srcKArray, kDictLevel0); } newKArray.addAll(srcKArray); } kDictLevel0.setItem(COSName.K, newKArray); kDictLevel0.setItem(COSName.P, destStructTree); kDictLevel0.setItem(COSName.S, new COSString(STRUCTURETYPE_DOCUMENT)); destStructTree.setK(kDictLevel0); } } private int nextFieldNum = 1; /** * Merge the contents of the source form into the destination form for the * destination file. * * @param cloner the object cloner for the destination document * @param destAcroForm the destination form * @param srcAcroForm the source form * @throws IOException If an error occurs while adding the field. */ private void mergeAcroForm(PDFCloneUtility cloner, PDAcroForm destAcroForm, PDAcroForm srcAcroForm) throws IOException { List destFields = destAcroForm.getFields(); List srcFields = srcAcroForm.getFields(); if (srcFields != null) { if (destFields == null) { destFields = new COSArrayList(); destAcroForm.setFields(destFields); } Iterator srcFieldsIterator = srcFields.iterator(); while (srcFieldsIterator.hasNext()) { PDField srcField = (PDField) srcFieldsIterator.next(); PDField destField = PDFieldFactory.createField(destAcroForm, (COSDictionary) cloner.cloneForNewDocument(srcField.getDictionary())); // if the form already has a field with this name then we need to rename this field // to prevent merge conflicts. if (destAcroForm.getField(destField.getFullyQualifiedName()) != null) { destField.setPartialName("dummyFieldName" + (nextFieldNum++)); } destFields.add(destField); } } } /** * Indicates if acroform errors are ignored or not. * * @return true if acroform errors are ignored */ public boolean isIgnoreAcroFormErrors() { return ignoreAcroFormErrors; } /** * Set to true to ignore acroform errors. * * @param ignoreAcroFormErrorsValue true if acroform errors should be * ignored */ public void setIgnoreAcroFormErrors(boolean ignoreAcroFormErrorsValue) { ignoreAcroFormErrors = ignoreAcroFormErrorsValue; } /** * Update the Pg and Obj references to the new (merged) page. * * @param parentTreeEntry * @param objMapping mapping between old and new references */ private void updatePageReferences(COSDictionary parentTreeEntry, HashMap objMapping) { COSBase page = parentTreeEntry.getDictionaryObject(COSName.PG); if (page instanceof COSDictionary) { if (objMapping.containsKey(page)) { parentTreeEntry.setItem(COSName.PG, objMapping.get(page)); } } COSBase obj = parentTreeEntry.getDictionaryObject(COSName.OBJ); if (obj instanceof COSDictionary) { if (objMapping.containsKey(obj)) { parentTreeEntry.setItem(COSName.OBJ, objMapping.get(obj)); } } COSBase kSubEntry = parentTreeEntry.getDictionaryObject(COSName.K); if (kSubEntry instanceof COSArray) { updatePageReferences((COSArray) kSubEntry, objMapping); } else if (kSubEntry instanceof COSDictionary) { updatePageReferences((COSDictionary) kSubEntry, objMapping); } } private void updatePageReferences(COSArray parentTreeEntry, HashMap objMapping) { for (int i = 0; i < parentTreeEntry.size(); i++) { COSBase subEntry = parentTreeEntry.getObject(i); if (subEntry instanceof COSArray) { updatePageReferences((COSArray) subEntry, objMapping); } else if (subEntry instanceof COSDictionary) { updatePageReferences((COSDictionary) subEntry, objMapping); } } } /** * Update the P reference to the new parent dictionary. * * @param kArray the kids array * @param newParent the new parent */ private void updateParentEntry(COSArray kArray, COSDictionary newParent) { for (int i = 0; i < kArray.size(); i++) { COSBase subEntry = kArray.getObject(i); if (subEntry instanceof COSDictionary) { COSDictionary dictEntry = (COSDictionary) subEntry; if (dictEntry.getDictionaryObject(COSName.P) != null) { dictEntry.setItem(COSName.P, newParent); } } } } /** * Update the StructParents and StructParent values in a PDPage. * * @param page the new page * @param structParentOffset the offset which should be applied */ private void updateStructParentEntries(PDPage page, int structParentOffset) throws IOException { page.setStructParents(page.getStructParents() + structParentOffset); List annots = page.getAnnotations(); List newannots = new ArrayList(); for (PDAnnotation annot : annots) { annot.setStructParent(annot.getStructParent() + structParentOffset); newannots.add(annot); } page.setAnnotations(newannots); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/0000755000000000000000000000000012645757432023621 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingSeparation.java0000644000000000000000000000421112645757432030764 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDSeparation; import org.apache.pdfbox.util.PDFOperator; /** * * @author Daniel Wilson * @version $Revision: 1.0 $ */ public class SetStrokingSeparation extends OperatorProcessor { /** * scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getStrokingColor(); PDColorSpace colorSpace = colorInstance.getColorSpace(); if (colorSpace != null) { PDSeparation sep = (PDSeparation) colorSpace; colorSpace = sep.getAlternateColorSpace(); COSArray values = sep.calculateColorValues(arguments.get(0)); colorInstance.setColorSpaceValue(values.toFloatArray()); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingGrayColor.java0000644000000000000000000000437412645757432031245 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray; import org.apache.pdfbox.util.PDFOperator; /** *

Set the non stroking color space.

* * @author Ben Litchfield * @version $Revision: 1.1 $ */ public class SetNonStrokingGrayColor extends OperatorProcessor { /** * rg Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorSpace cs = new PDDeviceGray(); PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); colorInstance.setColorSpace( cs ); float[] values = new float[1]; if( arguments.size() >= 1 ) { values[0] = ((COSNumber)arguments.get( 0 )).floatValue(); } else { throw new IOException( "Error: Expected at least one argument when setting non stroking gray color"); } colorInstance.setColorSpaceValue( values ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingRGBColor.java0000644000000000000000000000416512645757432030753 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.util.PDFOperator; /** *

Set the non stroking color space.

* * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class SetNonStrokingRGBColor extends OperatorProcessor { /** * rg Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorSpace cs = PDDeviceRGB.INSTANCE; PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); colorInstance.setColorSpace( cs ); float[] values = new float[3]; for( int i=0; i arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getStrokingColor(); PDColorSpace colorSpace = colorInstance.getColorSpace(); if (colorSpace != null) { PDDeviceN sep = (PDDeviceN) colorSpace; colorSpace = sep.getAlternateColorSpace(); COSArray colorValues = sep.calculateColorValues(arguments); colorInstance.setColorSpaceValue(colorValues.toFloatArray()); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingDeviceN.java0000644000000000000000000000410012645757432030644 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceN; import org.apache.pdfbox.util.PDFOperator; /** * * @version $Revision: 1.0 $ */ public class SetNonStrokingDeviceN extends OperatorProcessor { /** * scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); PDColorSpace colorSpace = colorInstance.getColorSpace(); if (colorSpace != null) { PDDeviceN sep = (PDDeviceN) colorSpace; colorSpace = sep.getAlternateColorSpace(); COSArray colorValues = sep.calculateColorValues(arguments); colorInstance.setColorSpaceValue(colorValues.toFloatArray()); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingLabColor.java0000644000000000000000000000316312645757432030361 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.util.PDFOperator; /** * Sets the stroking color values for Lab colorspace. * */ public class SetStrokingLabColor extends OperatorProcessor { /** * {@inheritDoc} */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState color = context.getGraphicsState().getStrokingColor(); float[] values = new float[3]; for( int i=0; i arguments) throws IOException { if (arguments.size() < 1) { return; } COSBase base = arguments.get(0); if (!(base instanceof COSArray)) { return; } COSArray array = (COSArray) base; int arraySize = array.size(); float fontsize = context.getGraphicsState().getTextState().getFontSize(); float horizontalScaling = context.getGraphicsState().getTextState().getHorizontalScalingPercent()/100; for( int i=0; i arguments) throws IOException { // Move to start of next text line, and show text // context.processOperator("T*", null); context.processOperator("Tj", arguments); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingPattern.java0000644000000000000000000000474112645757432030757 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import java.util.Map; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.pattern.PDPatternResources; import org.apache.pdfbox.util.PDFOperator; /** *

Set the non stroking pattern.

* * @version $Revision: 1.0 $ */ public class SetNonStrokingPattern extends OperatorProcessor { /** * Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the pattern. */ public void process(PDFOperator operator, List arguments) throws IOException { COSName selectedPattern; int numberOfArguments = arguments.size(); COSArray colorValues; if (numberOfArguments == 1) { selectedPattern = (COSName)arguments.get(0); } else { // uncolored tiling patterns shall have some additional color values // TODO: pass these values to the colorstate colorValues = new COSArray(); for (int i=0;i patterns = getContext().getResources().getPatterns(); PDPatternResources pattern = patterns.get(selectedPattern.getName()); getContext().getGraphicsState().getNonStrokingColor().setPattern(pattern); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingCMYKColor.java0000644000000000000000000000416712645757432031106 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; import org.apache.pdfbox.util.PDFOperator; /** *

Set the non stroking color space.

* * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class SetNonStrokingCMYKColor extends OperatorProcessor { /** * k Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorSpace cs = PDDeviceCMYK.INSTANCE; PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); colorInstance.setColorSpace( cs ); float[] values = new float[4]; for( int i=0; i arguments) throws IOException { //there are some documents that are incorrectly structured and //arguments are in the wrong spot, so we will silently ignore them //if there are no arguments if( arguments.size() >= 2 ) { //set font and size COSBase base0 = arguments.get(0); COSBase base1 = arguments.get(1); if (!(base0 instanceof COSName)) { return; } if (!(base1 instanceof COSNumber)) { return; } COSName fontName = (COSName) base0; float fontSize = ((COSNumber) base1).floatValue(); context.getGraphicsState().getTextState().setFontSize( fontSize ); PDFont font = (PDFont) context.getFonts().get(fontName.getName()); if( font == null ) { LOG.error("Could not find font(" + fontName + ") in map=" + context.getFonts() + ", creating default font"); font = PDFontFactory.createDefaultFont(); } context.getGraphicsState().getTextState().setFont(font); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingIndexed.java0000644000000000000000000000412012645757432030711 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDIndexed; import org.apache.pdfbox.util.PDFOperator; /** * * @version $Revision: 1.0 $ */ public class SetNonStrokingIndexed extends OperatorProcessor { /** * scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); PDColorSpace colorSpace = colorInstance.getColorSpace(); if (colorSpace != null) { PDIndexed indexed = (PDIndexed) colorSpace; colorSpace = indexed.getBaseColorSpace(); COSInteger colorValue = (COSInteger)arguments.get(0); colorInstance.setColorSpaceValue(indexed.calculateColorValues(colorValue.intValue())); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingPattern.java0000644000000000000000000000475012645757432030304 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import java.util.Map; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.pattern.PDPatternResources; import org.apache.pdfbox.util.PDFOperator; /** *

Set the stroking pattern.

* * @version $Revision: 1.0 $ */ public class SetStrokingPattern extends OperatorProcessor { /** * Set pattern instead of a color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the pattern. */ public void process(PDFOperator operator, List arguments) throws IOException { COSName selectedPattern; int numberOfArguments = arguments.size(); COSArray colorValues; if (numberOfArguments == 1) { selectedPattern = (COSName)arguments.get(0); } else { // uncolored tiling patterns shall have some additional color values // TODO: pass these values to the colorstate colorValues = new COSArray(); for (int i=0;i patterns = getContext().getResources().getPatterns(); PDPatternResources pattern = patterns.get(selectedPattern.getName()); getContext().getGraphicsState().getStrokingColor().setPattern(pattern); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingGrayColor.java0000644000000000000000000000435312645757432030567 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray; import org.apache.pdfbox.util.PDFOperator; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.1 $ */ public class SetStrokingGrayColor extends OperatorProcessor { /** * RG Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState color = context.getGraphicsState().getStrokingColor(); color.setColorSpace( new PDDeviceGray() ); float[] values = new float[1]; if( arguments.size() >= 1 ) { values[0] = ((COSNumber)arguments.get( 0 )).floatValue(); } else { throw new IOException( "Error: Expected at least one argument when setting non stroking gray color"); } color.setColorSpaceValue( values ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/EndMarkedContentSequence.java0000644000000000000000000000277112645757432031351 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.PDFMarkedContentExtractor; import org.apache.pdfbox.util.PDFOperator; /** * EMC : Ends a marked-content sequence begun by BMC or BDC. * @author koch * @version $Revision: $ */ public class EndMarkedContentSequence extends OperatorProcessor { /** * {@inheritDoc} */ public void process(PDFOperator operator, List arguments) throws IOException { if (this.context instanceof PDFMarkedContentExtractor) { ((PDFMarkedContentExtractor) this.context).endMarkedContentSequence(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/MoveText.java0000644000000000000000000000402312645757432026236 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFOperator; /** * * @author Huault : huault@free.fr * @version $Revision: 1.4 $ */ public class MoveText extends OperatorProcessor { /** * process : Td : Move text position. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { if (arguments.size() < 2) { return; } COSBase base0 = arguments.get(0); COSBase base1 = arguments.get(1); if (!(base0 instanceof COSNumber)) { return; } if (!(base1 instanceof COSNumber)) { return; } COSNumber x = (COSNumber) base0; COSNumber y = (COSNumber) base1; Matrix td = new Matrix(); td.setValue( 2, 0, x.floatValue() ); td.setValue( 2, 1, y.floatValue() ); context.setTextLineMatrix( td.multiply( context.getTextLineMatrix() ) ); context.setTextMatrix( context.getTextLineMatrix().copy() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GSave.java0000644000000000000000000000266612645757432025503 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; import org.apache.pdfbox.util.PDFOperator; /** * * @author Huault : huault@free.fr * @version $Revision: 1.4 $ */ public class GSave extends OperatorProcessor { /** * process : q : Save graphics state. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { context.getGraphicsStack().push( (PDGraphicsState)context.getGraphicsState().clone() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetCharSpacing.java0000644000000000000000000000365712645757432027335 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; /** * * @author Huault : huault@free.fr * @version $Revision: 1.5 $ */ public class SetCharSpacing extends OperatorProcessor { /** * process : Tc Set character spacing. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { //set character spacing if( arguments.size() > 0 ) { //There are some documents which are incorrectly structured, and have //a wrong number of arguments to this, so we will assume the last argument //in the list Object charSpacing = arguments.get( arguments.size()-1 ); if( charSpacing instanceof COSNumber ) { COSNumber characterSpacing = (COSNumber)charSpacing; context.getGraphicsState().getTextState().setCharacterSpacing( characterSpacing.floatValue() ); } } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingRGBColor.java0000644000000000000000000000414412645757432030275 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.util.PDFOperator; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class SetStrokingRGBColor extends OperatorProcessor { /** * RG Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState color = context.getGraphicsState().getStrokingColor(); color.setColorSpace( PDDeviceRGB.INSTANCE ); float[] values = new float[3]; for( int i=0; i This package contains implementations of all of the PDF operators. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingICCBasedColor.java0000644000000000000000000000410212645757432031665 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.util.PDFOperator; /** * * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class SetNonStrokingICCBasedColor extends OperatorProcessor { /** * scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); PDColorSpace cs = colorInstance.getColorSpace(); int numberOfComponents = cs.getNumberOfComponents(); float[] values = new float[numberOfComponents]; for( int i=0; iStructal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class SetLineWidth extends OperatorProcessor { /** * w Set line width. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { COSNumber width = (COSNumber)arguments.get( 0 ); context.getGraphicsState().setLineWidth( width.doubleValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetTextRenderingMode.java0000644000000000000000000000371012645757432030530 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class SetTextRenderingMode extends OperatorProcessor { /** * Tr Set text rendering mode. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { if (arguments.size() < 1) { return; } COSBase base0 = arguments.get(0); if (!(base0 instanceof COSNumber)) { return; } COSNumber mode = (COSNumber) base0; context.getGraphicsState().getTextState().setRenderingMode( mode.intValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetTextLeading.java0000644000000000000000000000271412645757432027354 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; /** * @author Huault : huault@free.fr * @version $Revision: 1.4 $ */ public class SetTextLeading extends OperatorProcessor { /** * TL Set text leading. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { COSNumber leading = (COSNumber)arguments.get( 0 ); context.getGraphicsState().getTextState().setLeading( leading.floatValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingSeparation.java0000644000000000000000000000422712645757432031446 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDSeparation; import org.apache.pdfbox.util.PDFOperator; /** * * @author Daniel Wilson * @version $Revision: 1.0 $ */ public class SetNonStrokingSeparation extends OperatorProcessor { /** * scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); PDColorSpace colorSpace = colorInstance.getColorSpace(); if (colorSpace != null) { PDSeparation sep = (PDSeparation) colorSpace; colorSpace = sep.getAlternateColorSpace(); COSArray values = sep.calculateColorValues(arguments.get(0)); colorInstance.setColorSpaceValue(values.toFloatArray()); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingIndexed.java0000644000000000000000000000411212645757432030237 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDIndexed; import org.apache.pdfbox.util.PDFOperator; /** * * @version $Revision: 1.0 $ */ public class SetStrokingIndexed extends OperatorProcessor { /** * scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getStrokingColor(); PDColorSpace colorSpace = colorInstance.getColorSpace(); if (colorSpace != null) { PDIndexed indexed = (PDIndexed) colorSpace; colorSpace = indexed.getBaseColorSpace(); COSInteger colorValue = (COSInteger)arguments.get(0); colorInstance.setColorSpaceValue(indexed.calculateColorValues(colorValue.intValue())); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingCalRGBColor.java0000644000000000000000000000364212645757432031372 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.util.PDFOperator; /** *

Set the non stroking color space.

* * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class SetNonStrokingCalRGBColor extends OperatorProcessor { /** * rg Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); float[] values = new float[3]; for( int i=0; i arguments) throws IOException { //move to start of next text line ArrayList args = new ArrayList(); args.add(new COSFloat(0.0f)); // this must be -leading instead of just leading as written in the // specification (p.369) the acrobat reader seems to implement it the same way args.add(new COSFloat(-1*context.getGraphicsState().getTextState().getLeading())); // use Td instead of repeating code context.processOperator("Td", args); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/BeginMarkedContentSequence.java0000644000000000000000000000336712645757432031671 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.util.PDFMarkedContentExtractor; import org.apache.pdfbox.util.PDFOperator; /** * BMC : Begins a marked-content sequence. * @author koch * @version $Revision$ * */ public class BeginMarkedContentSequence extends OperatorProcessor { /** * {@inheritDoc} */ @Override public void process(PDFOperator operator, List arguments) throws IOException { COSName tag = null; for (COSBase argument : arguments) { if (argument instanceof COSName) { tag = (COSName) argument; } } if (this.context instanceof PDFMarkedContentExtractor) { ((PDFMarkedContentExtractor) this.context).beginMarkedContentSequence(tag, null); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/Invoke.java0000644000000000000000000000627112645757432025725 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFMarkedContentExtractor; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; import java.util.List; import java.util.Map; /** * Invoke named XObject. * * @author Ben Litchfield * @author Mario Ivankovits * * @version $Revision: 1.9 $ */ public class Invoke extends OperatorProcessor { /** * process : Do - Invoke a named xobject. * * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If there is an error processing this operator. */ public void process(PDFOperator operator, List arguments) throws IOException { if (arguments.size() < 1) { return; } COSBase base0 = arguments.get(0); if (!(base0 instanceof COSName)) { return; } COSName name = (COSName) base0; Map xobjects = context.getXObjects(); PDXObject xobject = (PDXObject) xobjects.get(name.getName()); if (context instanceof PDFMarkedContentExtractor) { ((PDFMarkedContentExtractor) context).xobject(xobject); } if(xobject instanceof PDXObjectForm) { PDXObjectForm form = (PDXObjectForm)xobject; COSStream formContentstream = form.getCOSStream(); // if there is an optional form matrix, we have to map the form space to the user space Matrix matrix = form.getMatrix(); if (matrix != null) { Matrix xobjectCTM = matrix.multiply( context.getGraphicsState().getCurrentTransformationMatrix()); context.getGraphicsState().setCurrentTransformationMatrix(xobjectCTM); } // find some optional resources, instead of using the current resources PDResources pdResources = form.getResources(); context.processSubStream( context.getCurrentPage(), pdResources, formContentstream ); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetLineJoinStyle.java0000644000000000000000000000325212645757432027672 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author arguments) throws IOException; } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetWordSpacing.java0000644000000000000000000000325312645757432027363 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; /** * @author Huault : huault@free.fr * @version $Revision: 1.4 $ */ public class SetWordSpacing extends OperatorProcessor { /** * Tw Set word spacing. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { //set word spacing if (arguments.size() < 1) { return; } COSBase base = arguments.get(0); if (!(base instanceof COSNumber)) { return; } COSNumber wordSpacing = (COSNumber) base; context.getGraphicsState().getTextState().setWordSpacing( wordSpacing.floatValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingCMYKColor.java0000644000000000000000000000414612645757432030430 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; import org.apache.pdfbox.util.PDFOperator; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author
Ben Litchfield * @version $Revision: 1.4 $ */ public class SetStrokingCMYKColor extends OperatorProcessor { /** * K Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState color = context.getGraphicsState().getStrokingColor(); color.setColorSpace( PDDeviceCMYK.INSTANCE ); float[] values = new float[4]; for( int i=0; i arguments) throws IOException { if (arguments.size() < 1) { // ignore ( )Tj return; } COSBase base = arguments.get(0); if (!(base instanceof COSString)) { // ignore return; } COSString string = (COSString) base; context.processEncodedText( string.getBytes() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/MoveTextSetLeading.java0000644000000000000000000000400612645757432030177 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; /** * * @author Huault : huault@free.fr * @version $Revision: 1.5 $ */ public class MoveTextSetLeading extends OperatorProcessor { /** * process : TD Move text position and set leading. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If there is an error during processing. */ public void process(PDFOperator operator, List arguments) throws IOException { //move text position and set leading if (arguments.size() < 2) { return; } COSBase base1 = arguments.get(1); if (!(base1 instanceof COSNumber)) { return; } COSNumber y = (COSNumber) base1; ArrayList args = new ArrayList(); args.add(new COSFloat(-1*y.floatValue())); context.processOperator("TL", args); context.processOperator("Td", arguments); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingColor.java0000644000000000000000000001055212645757432030415 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceN; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; import org.apache.pdfbox.pdmodel.graphics.color.PDICCBased; import org.apache.pdfbox.pdmodel.graphics.color.PDCalRGB; import org.apache.pdfbox.pdmodel.graphics.color.PDIndexed; import org.apache.pdfbox.pdmodel.graphics.color.PDLab; import org.apache.pdfbox.pdmodel.graphics.color.PDPattern; import org.apache.pdfbox.pdmodel.graphics.color.PDSeparation; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** *

Set the non stroking color space.

* * @version $Revision: 1.0 $ */ public class SetNonStrokingColor extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(SetNonStrokingColor.class); /** * sc,scn Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorSpace colorSpace = context.getGraphicsState().getNonStrokingColor().getColorSpace(); if (colorSpace != null) { OperatorProcessor newOperator = null; if (colorSpace instanceof PDDeviceGray) { newOperator = new SetNonStrokingGrayColor(); } else if (colorSpace instanceof PDDeviceRGB) { newOperator = new SetNonStrokingRGBColor(); } else if (colorSpace instanceof PDDeviceCMYK) { newOperator = new SetNonStrokingCMYKColor(); } else if (colorSpace instanceof PDICCBased) { newOperator = new SetNonStrokingICCBasedColor(); } else if (colorSpace instanceof PDCalRGB) { newOperator = new SetNonStrokingCalRGBColor(); } else if (colorSpace instanceof PDSeparation) { newOperator = new SetNonStrokingSeparation(); } else if (colorSpace instanceof PDDeviceN) { newOperator = new SetNonStrokingDeviceN(); } else if (colorSpace instanceof PDPattern) { newOperator = new SetNonStrokingPattern(); } else if (colorSpace instanceof PDIndexed) { newOperator = new SetNonStrokingIndexed(); } else if (colorSpace instanceof PDLab) { newOperator = new SetNonStrokingLabColor(); } if (newOperator != null) { newOperator.setContext(getContext()); newOperator.process(operator, arguments); } else { LOG.warn("Not supported colorspace "+colorSpace.getName() + " within operator "+operator.getOperation()); } } else { LOG.warn("Colorspace not found in "+getClass().getName()+".process!!"); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingICCBasedColor.java0000644000000000000000000000404012645757432031213 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.util.PDFOperator; /** * * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class SetStrokingICCBasedColor extends OperatorProcessor { /** * scn Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState color = context.getGraphicsState().getStrokingColor(); PDColorSpace cs = color.getColorSpace(); int numberOfComponents = cs.getNumberOfComponents(); float[] values = new float[numberOfComponents]; for( int i=0; i arguments) throws IOException { //concatenate matrix to current transformation matrix COSNumber a = (COSNumber) arguments.get(0); COSNumber b = (COSNumber) arguments.get(1); COSNumber c = (COSNumber) arguments.get(2); COSNumber d = (COSNumber) arguments.get(3); COSNumber e = (COSNumber) arguments.get(4); COSNumber f = (COSNumber) arguments.get(5); Matrix newMatrix = new Matrix(); newMatrix.setValue(0, 0, a.floatValue()); newMatrix.setValue(0, 1, b.floatValue()); newMatrix.setValue(1, 0, c.floatValue()); newMatrix.setValue(1, 1, d.floatValue()); newMatrix.setValue(2, 0, e.floatValue()); newMatrix.setValue(2, 1, f.floatValue()); //this line has changed context.getGraphicsState().setCurrentTransformationMatrix( newMatrix.multiply( context.getGraphicsState().getCurrentTransformationMatrix() ) ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetHorizontalTextScaling.java0000644000000000000000000000344612645757432031446 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class SetHorizontalTextScaling extends OperatorProcessor { /** * Tz Set horizontal text scaling. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { COSNumber scaling = (COSNumber)arguments.get(0); context.getGraphicsState().getTextState().setHorizontalScalingPercent( scaling.floatValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetMoveAndShow.java0000644000000000000000000000342712645757432027340 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** * @author Huault : huault@free.fr * @version $Revision: 1.6 $ */ public class SetMoveAndShow extends OperatorProcessor { /** * " Set word and character spacing, move to next line, and show text. * @param operator The operator that is being executed. * @param arguments List. * @throws IOException If there is an error processing the operator. */ public void process(PDFOperator operator, List arguments) throws IOException { //Set word and character spacing, move to next line, and show text // if (arguments.size() < 3) { return; } context.processOperator("Tw", arguments.subList(0,1)); context.processOperator("Tc", arguments.subList(1,2)); context.processOperator("'", arguments.subList(2,3)); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/0000755000000000000000000000000012645757432025742 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/StrokePath.java0000644000000000000000000000317512645757432030677 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * */ public class StrokePath extends OperatorProcessor { /** * S stroke the path. * * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { ((PageDrawer)context).strokePath(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/MoveTo.java0000644000000000000000000000447212645757432030025 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.Point2D; import java.util.List; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class MoveTo extends OperatorProcessor { /** * Log instance. */ private static final Log log = LogFactory.getLog(MoveTo.class); /** * process : m : Begin new subpath. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If there is an error processing the operator. */ public void process(PDFOperator operator, List arguments) throws IOException { try { PageDrawer drawer = (PageDrawer)context; COSNumber x = (COSNumber)arguments.get( 0 ); COSNumber y = (COSNumber)arguments.get( 1 ); Point2D pos = drawer.transformedPoint(x.doubleValue(), y.doubleValue()); drawer.getLinePath().moveTo((float)pos.getX(), (float)pos.getY()); } catch (Exception exception) { log.warn( exception, exception); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroRule.java0000644000000000000000000000416312645757432031642 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.GeneralPath; import java.io.IOException; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class FillNonZeroRule extends OperatorProcessor { /** * Log instance. */ private static final Log log = LogFactory.getLog(FillNonZeroRule.class); /** * process : F/f : fill path using non zero winding rule. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If there is an error during the processing. */ public void process(PDFOperator operator, List arguments) throws IOException { try { ///dwilson refactoring PageDrawer drawer = (PageDrawer)context; drawer.fillPath(GeneralPath.WIND_NON_ZERO); } catch (Exception e) { log.warn(e, e); } } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.0000644000000000000000000000563712645757432032132 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * */ public class AppendRectangleToPath extends OperatorProcessor { /** * process : re : append rectangle to path. * * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { PageDrawer drawer = (PageDrawer) context; COSNumber x = (COSNumber) arguments.get(0); COSNumber y = (COSNumber) arguments.get(1); COSNumber w = (COSNumber) arguments.get(2); COSNumber h = (COSNumber) arguments.get(3); double x1 = x.doubleValue(); double y1 = y.doubleValue(); // create a pair of coordinates for the transformation double x2 = w.doubleValue() + x1; double y2 = h.doubleValue() + y1; Point2D p0 = drawer.transformedPoint(x1, y1); Point2D p1 = drawer.transformedPoint(x2, y1); Point2D p2 = drawer.transformedPoint(x2, y2); Point2D p3 = drawer.transformedPoint(x1, y2); // to ensure that the path is created in the right direction, we have to create // it by combining single lines instead of creating a simple rectangle GeneralPath path = drawer.getLinePath(); path.moveTo((float) p0.getX(), (float) p0.getY()); path.lineTo((float) p1.getX(), (float) p1.getY()); path.lineTo((float) p2.getX(), (float) p2.getY()); path.lineTo((float) p3.getX(), (float) p3.getY()); // close the subpath instead of adding the last line so that a possible set line // cap style isn't taken into account at the "beginning" of the rectangle path.closePath(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/package.html0000644000000000000000000000172012645757432030223 0ustar rootroot This package contains implementations of all of the PDF operators. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SetLineWidth.java0000644000000000000000000000432012645757432031147 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import java.awt.BasicStroke; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class SetLineWidth extends org.apache.pdfbox.util.operator.SetLineWidth { /** * w Set line width. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ @Override public void process(PDFOperator operator, List arguments) throws IOException { super.process( operator, arguments ); float lineWidth = (float)context.getGraphicsState().getLineWidth(); PageDrawer drawer = (PageDrawer)context; BasicStroke stroke = (BasicStroke)drawer.getStroke(); if (stroke == null) { drawer.setStroke( new BasicStroke( lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER ) ); } else { drawer.setStroke( new BasicStroke(lineWidth, stroke.getEndCap(), stroke.getLineJoin(), stroke.getMiterLimit(), stroke.getDashArray(), stroke.getDashPhase()) ); } } } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalPoint.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalP0000644000000000000000000000434012645757432032200 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import java.awt.geom.Point2D; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class CurveToReplicateFinalPoint extends OperatorProcessor { /** * process : y : Append curved segment to path (final point replicated). * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { PageDrawer drawer = (PageDrawer)context; COSNumber x1 = (COSNumber)arguments.get( 0 ); COSNumber y1 = (COSNumber)arguments.get( 1 ); COSNumber x3 = (COSNumber)arguments.get( 2 ); COSNumber y3 = (COSNumber)arguments.get( 3 ); Point2D point1 = drawer.transformedPoint(x1.doubleValue(), y1.doubleValue()); Point2D point3 = drawer.transformedPoint(x3.doubleValue(), y3.doubleValue()); drawer.getLinePath().curveTo((float)point1.getX(), (float)point1.getY(), (float)point3.getX(), (float)point3.getY(), (float)point3.getX(), (float)point3.getY()); } } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePath.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePa0000644000000000000000000000362112645757432032164 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import java.awt.geom.GeneralPath; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.1 $ */ public class FillNonZeroAndStrokePath extends org.apache.pdfbox.util.operator.OperatorProcessor { /** * fill and stroke the path. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PageDrawer drawer = (PageDrawer)context; GeneralPath currentPath = (GeneralPath)drawer.getLinePath().clone(); context.processOperator( "f", arguments ); drawer.setLinePath( currentPath ); context.processOperator( "S", arguments ); } } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePath.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePa0000644000000000000000000000362212645757432032117 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import java.awt.geom.GeneralPath; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Andreas Lehmkühler * @version $Revision: 101 $ */ public class FillEvenOddAndStrokePath extends org.apache.pdfbox.util.operator.OperatorProcessor { /** * fill and stroke the path. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PageDrawer drawer = (PageDrawer)context; GeneralPath currentPath = (GeneralPath)drawer.getLinePath().clone(); context.processOperator( "f*", arguments ); drawer.setLinePath( currentPath ); context.processOperator( "S", arguments ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveTo.java0000644000000000000000000000456612645757432030207 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import java.awt.geom.Point2D; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class CurveTo extends OperatorProcessor { /** * process : c : Append curved segment to path. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { PageDrawer drawer = (PageDrawer)context; COSNumber x1 = (COSNumber)arguments.get( 0 ); COSNumber y1 = (COSNumber)arguments.get( 1 ); COSNumber x2 = (COSNumber)arguments.get( 2 ); COSNumber y2 = (COSNumber)arguments.get( 3 ); COSNumber x3 = (COSNumber)arguments.get( 4 ); COSNumber y3 = (COSNumber)arguments.get( 5 ); Point2D point1 = drawer.transformedPoint(x1.doubleValue(), y1.doubleValue()); Point2D point2 = drawer.transformedPoint(x2.doubleValue(), y2.doubleValue()); Point2D point3 = drawer.transformedPoint(x3.doubleValue(), y3.doubleValue()); drawer.getLinePath().curveTo((float)point1.getX(), (float)point1.getY(), (float)point2.getX(), (float)point2.getY(), (float)point3.getX(), (float)point3.getY()); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java0000644000000000000000000001700412645757432030042 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class Invoke extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(Invoke.class); /** * process : Do : Paint the specified XObject (section 4.7). * @param operator The operator that is being executed. * @param arguments List * @throws IOException If there is an error invoking the sub object. */ public void process(PDFOperator operator, List arguments) throws IOException { PageDrawer drawer = (PageDrawer)context; PDPage page = drawer.getPage(); if (arguments.size() < 1) { return; } COSBase base0 = arguments.get(0); if (!(base0 instanceof COSName)) { return; } COSName objectName = (COSName) base0; Map xobjects = drawer.getResources().getXObjects(); PDXObject xobject = (PDXObject)xobjects.get( objectName.getName() ); if ( xobject == null ) { LOG.warn("Can't find the XObject for '"+objectName.getName()+"'"); } else if( xobject instanceof PDXObjectImage ) { PDXObjectImage image = (PDXObjectImage)xobject; try { if (image.getImageMask()) { // set the current non stroking colorstate, so that it can // be used to create a stencil masked image image.setStencilColor(drawer.getGraphicsState().getNonStrokingColor()); } BufferedImage awtImage = image.getRGBImage(); if (awtImage == null) { LOG.warn("getRGBImage returned NULL"); return;//TODO PKOCH } int imageWidth = awtImage.getWidth(); int imageHeight = awtImage.getHeight(); double pageHeight = drawer.getPageSize().getHeight(); LOG.debug("imageWidth: " + imageWidth + "\t\timageHeight: " + imageHeight); Matrix ctm = drawer.getGraphicsState().getCurrentTransformationMatrix(); float yScaling = ctm.getYScale(); float angle = (float)Math.acos(ctm.getValue(0, 0)/ctm.getXScale()); if (ctm.getValue(0, 1) < 0 && ctm.getValue(1, 0) > 0) { angle = (-1)*angle; } ctm.setValue(2, 1, (float)(pageHeight - ctm.getYPosition() - Math.cos(angle)*yScaling)); ctm.setValue(2, 0, (float)(ctm.getXPosition() - Math.sin(angle)*yScaling)); // because of the moved 0,0-reference, we have to shear in the opposite direction ctm.setValue(0, 1, (-1)*ctm.getValue(0, 1)); ctm.setValue(1, 0, (-1)*ctm.getValue(1, 0)); AffineTransform ctmAT = ctm.createAffineTransform(); ctmAT.scale(1f/imageWidth, 1f/imageHeight); drawer.drawImage( awtImage, ctmAT ); } catch( Exception e ) { LOG.error(e, e); } } else if(xobject instanceof PDXObjectForm) { // save the graphics state context.getGraphicsStack().push( (PDGraphicsState)context.getGraphicsState().clone() ); PDXObjectForm form = (PDXObjectForm)xobject; COSStream formContentstream = form.getCOSStream(); // find some optional resources, instead of using the current resources PDResources pdResources = form.getResources(); // if there is an optional form matrix, we have to map the form space to the user space Matrix matrix = form.getMatrix(); if (matrix != null) { Matrix xobjectCTM = matrix.multiply( context.getGraphicsState().getCurrentTransformationMatrix()); context.getGraphicsState().setCurrentTransformationMatrix(xobjectCTM); } if (form.getBBox() != null) { PDGraphicsState graphicsState = context.getGraphicsState(); PDRectangle bBox = form.getBBox(); float x1 = bBox.getLowerLeftX(); float y1 = bBox.getLowerLeftY(); float x2 = bBox.getUpperRightX(); float y2 = bBox.getUpperRightY(); Point2D p0 = drawer.transformedPoint(x1, y1); Point2D p1 = drawer.transformedPoint(x2, y1); Point2D p2 = drawer.transformedPoint(x2, y2); Point2D p3 = drawer.transformedPoint(x1, y2); GeneralPath bboxPath = new GeneralPath(); bboxPath.moveTo((float) p0.getX(), (float) p0.getY()); bboxPath.lineTo((float) p1.getX(), (float) p1.getY()); bboxPath.lineTo((float) p2.getX(), (float) p2.getY()); bboxPath.lineTo((float) p3.getX(), (float) p3.getY()); bboxPath.closePath(); Area resultClippingArea = new Area(graphicsState.getCurrentClippingPath()); Area newArea = new Area(bboxPath); resultClippingArea.intersect(newArea); graphicsState.setCurrentClippingPath(resultClippingArea); } getContext().processSubStream(page, pdResources, formContentstream); // restore the graphics state context.setGraphicsState( (PDGraphicsState)context.getGraphicsStack().pop() ); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/LineTo.java0000644000000000000000000000371412645757432030004 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import java.awt.geom.Point2D; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class LineTo extends OperatorProcessor { /** * process : l : Append straight line segment to path. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { PageDrawer drawer = (PageDrawer)context; //append straight line segment from the current point to the point. COSNumber x = (COSNumber)arguments.get( 0 ); COSNumber y = (COSNumber)arguments.get( 1 ); Point2D pos = drawer.transformedPoint(x.doubleValue(), y.doubleValue()); drawer.getLinePath().lineTo((float)pos.getX(), (float)pos.getY()); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SetLineJoinStyle.java0000644000000000000000000000433512645757432032016 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Daniel Wilson * @version $Revision: 1.1 $ */ public class ClipEvenOddRule extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(ClipEvenOddRule.class); /** * process : W* : set clipping path using even odd rule. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException if there is an error during execution. */ public void process(PDFOperator operator, List arguments) throws IOException { try { PageDrawer drawer = (PageDrawer)context; drawer.setClippingWindingRule(GeneralPath.WIND_EVEN_ODD); } catch (Exception e) { LOG.warn(e, e); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/BeginInlineImage.java0000644000000000000000000001146512645757432031742 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.graphics.xobject.PDInlinedImage; import org.apache.pdfbox.util.ImageParameters; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class BeginInlineImage extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(BeginInlineImage.class); /** * process : BI : begin inline image. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If there is an error displaying the inline image. */ public void process(PDFOperator operator, List arguments) throws IOException { PageDrawer drawer = (PageDrawer)context; PDPage page = drawer.getPage(); //begin inline image object ImageParameters params = operator.getImageParameters(); PDInlinedImage image = new PDInlinedImage(); image.setImageParameters( params ); image.setImageData( operator.getImageData() ); if (params.isStencil()) { //TODO implement inline image stencil masks LOG.warn("Stencil masks are not implemented, background may be incorrect"); } BufferedImage awtImage = image.createImage( context.getColorSpaces() ); if (awtImage == null) { LOG.warn("BeginInlineImage.process(): createImage returned NULL"); return; } int imageWidth = awtImage.getWidth(); int imageHeight = awtImage.getHeight(); double pageHeight = drawer.getPageSize().getHeight(); Matrix ctm = drawer.getGraphicsState().getCurrentTransformationMatrix(); int rotationAngle = page.findRotation(); // normalize the rotation angle while (rotationAngle < 0) { rotationAngle += 360; } while (rotationAngle >= 360) { rotationAngle -= 360; } AffineTransform ctmAT = ctm.createAffineTransform(); ctmAT.scale(1f/imageWidth, 1f/imageHeight); Matrix rotationMatrix = new Matrix(); rotationMatrix.setFromAffineTransform( ctmAT ); // calculate the inverse rotation angle // scaleX = m00 = cos // shearX = m01 = -sin // tan = sin/cos double angle = Math.atan(ctmAT.getShearX()/ctmAT.getScaleX()); Matrix translationMatrix = null; if (rotationAngle == 0 || rotationAngle == 180) { translationMatrix = Matrix.getTranslatingInstance((float)(Math.sin(angle)*ctm.getXScale()), (float)(pageHeight-2*ctm.getYPosition()-Math.cos(angle)*ctm.getYScale())); } else if (rotationAngle == 90 || rotationAngle == 270) { translationMatrix = Matrix.getTranslatingInstance((float)(Math.sin(angle)*ctm.getYScale()), (float)(pageHeight-2*ctm.getYPosition())); } rotationMatrix = rotationMatrix.multiply(translationMatrix); rotationMatrix.setValue(0, 1, (-1)*rotationMatrix.getValue(0, 1)); rotationMatrix.setValue(1, 0, (-1)*rotationMatrix.getValue(1, 0)); AffineTransform at = new AffineTransform( rotationMatrix.getValue(0,0),rotationMatrix.getValue(0,1), rotationMatrix.getValue(1,0), rotationMatrix.getValue( 1, 1), rotationMatrix.getValue(2,0),rotationMatrix.getValue(2,1) ); drawer.drawImage(awtImage, at); } }././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitialPoint.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitia0000644000000000000000000000457112645757432032252 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class CurveToReplicateInitialPoint extends OperatorProcessor { /** * process : v : Append curved segment to path (initial point replicated). * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { PageDrawer drawer = (PageDrawer)context; COSNumber x2 = (COSNumber)arguments.get( 0 ); COSNumber y2 = (COSNumber)arguments.get( 1 ); COSNumber x3 = (COSNumber)arguments.get( 2 ); COSNumber y3 = (COSNumber)arguments.get( 3 ); GeneralPath path = drawer.getLinePath(); Point2D currentPoint = path.getCurrentPoint(); Point2D point2 = drawer.transformedPoint(x2.doubleValue(), y2.doubleValue()); Point2D point3 = drawer.transformedPoint(x3.doubleValue(), y3.doubleValue()); drawer.getLinePath().curveTo((float)currentPoint.getX(), (float)currentPoint.getY(), (float)point2.getX(), (float)point2.getY(), (float)point3.getX(), (float)point3.getY()); } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SetLineDashPattern.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SetLineDashPattern.jav0000644000000000000000000000605012645757432032146 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern; import org.apache.pdfbox.util.PDFOperator; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class SetLineDashPattern extends org.apache.pdfbox.util.operator.SetLineDashPattern { /** * Set the line dash pattern. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { super.process( operator, arguments ); PDLineDashPattern lineDashPattern = context.getGraphicsState().getLineDashPattern(); PageDrawer drawer = (PageDrawer)context; BasicStroke stroke = (BasicStroke)drawer.getStroke(); if (stroke == null) { if (lineDashPattern.isDashPatternEmpty()) { drawer.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f) ); } else { drawer.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f, lineDashPattern.getCOSDashPattern().toFloatArray(), lineDashPattern.getPhaseStart()) ); } } else { if (lineDashPattern.isDashPatternEmpty()) { drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin(), stroke.getMiterLimit()) ); } else { drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin(), stroke.getMiterLimit(), lineDashPattern.getCOSDashPattern().toFloatArray(), lineDashPattern.getPhaseStart()) ); } } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SetLineCapStyle.java0000644000000000000000000000433112645757432031616 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class FillEvenOddRule extends OperatorProcessor { /** * Log instance. */ private static final Log log = LogFactory.getLog(FillEvenOddRule.class); /** * process : f* : fill path using even odd rule. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException if there is an error during execution. */ public void process(PDFOperator operator, List arguments) throws IOException { try { ///dwilson refactoring PageDrawer drawer = (PageDrawer)context; drawer.fillPath(GeneralPath.WIND_EVEN_ODD); } catch (Exception e) { log.warn(e, e); } } } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CloseFillEvenOddAndStrokePath.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CloseFillEvenOddAndStr0000644000000000000000000000333712645757432032130 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class CloseFillEvenOddAndStrokePath extends org.apache.pdfbox.util.operator.OperatorProcessor { /** * fill and stroke the path. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { // execute ClosePath context.processOperator( "h", arguments ); // execute FillEvenOddAndStroke context.processOperator( "B*", arguments ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipNonZeroRule.java0000644000000000000000000000416712645757432031647 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.awt.geom.GeneralPath; import java.io.IOException; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Daniel Wilson * @version $Revision: 1.1 $ */ public class ClipNonZeroRule extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(ClipNonZeroRule.class); /** * process : W : Set the clipping path using non zero winding rule. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If there is an error during the processing. */ public void process(PDFOperator operator, List arguments) throws IOException { try { PageDrawer drawer = (PageDrawer)context; drawer.setClippingWindingRule(GeneralPath.WIND_NON_ZERO); } catch (Exception e) { LOG.warn(e, e); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SetLineMiterLimit.java0000644000000000000000000000436712645757432032162 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class SetLineMiterLimit extends org.apache.pdfbox.util.operator.SetLineMiterLimit { /** * Set the line dash pattern. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { super.process(operator, arguments); float miterLimit = (float)context.getGraphicsState().getMiterLimit(); PageDrawer drawer = (PageDrawer)context; BasicStroke stroke = (BasicStroke)drawer.getStroke(); if (stroke == null) { drawer.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, miterLimit, null, 0.0f)); } else { drawer.setStroke( new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin(), miterLimit, null, 0.0f)); } } } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CloseFillNonZeroAndStrokePath.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CloseFillNonZeroAndStr0000644000000000000000000000337012645757432032173 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.1 $ */ public class CloseFillNonZeroAndStrokePath extends OperatorProcessor { /** * fill and stroke the path. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { // execute ClosePath context.processOperator( "h", arguments ); // execute FillNonZeroAndStroke context.processOperator( "B", arguments ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClosePath.java0000644000000000000000000000376012645757432030475 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class ClosePath extends OperatorProcessor { /** * Log instance. */ private static final Log log = LogFactory.getLog(ClosePath.class); /** * process : h : Close path. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException if something went wrong during logging */ public void process(PDFOperator operator, List arguments) throws IOException { PageDrawer drawer = (PageDrawer)context; try { drawer.getLinePath().closePath(); } catch( Throwable t ) { log.warn(t, t); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/EndPath.java0000644000000000000000000000306112645757432030130 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class EndPath extends OperatorProcessor { /** * process : n : End path. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { PageDrawer drawer = (PageDrawer)context; drawer.endPath(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SHFill.java0000644000000000000000000000415112645757432027727 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator.pagedrawer; import java.io.IOException; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdfviewer.PageDrawer; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * Implementation of sh operator for page drawer. * See section 4.6.3 of the PDF 1.7 specification. * * @author Daniel Wilson * @version $Revision: 1.0 $ */ public class SHFill extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(SHFill.class); /** * process : sh : shade fill the clipping area. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException if there is an error during execution. */ public void process(PDFOperator operator, List arguments) throws IOException { try { PageDrawer drawer = (PageDrawer)context; drawer.shFill((COSName)(arguments.get(0))); } catch (Exception e) { LOG.warn(e, e); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetLineDashPattern.java0000644000000000000000000000441612645757432030172 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.1 $ */ public class SetLineDashPattern extends OperatorProcessor { /** * log instance */ private static final Log LOG = LogFactory.getLog(SetLineDashPattern.class); /** * Set the line dash pattern. * * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { COSArray dashArray = (COSArray) arguments.get(0); int dashPhase = ((COSNumber) arguments.get(1)).intValue(); if (dashPhase < 0) { LOG.warn("dash phaseStart has negative value " + dashPhase + ", set to 0"); dashPhase = 0; } PDLineDashPattern lineDash = new PDLineDashPattern(dashArray, dashPhase); context.getGraphicsState().setLineDashPattern(lineDash); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingColorSpace.java0000644000000000000000000000542012645757432030714 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; import org.apache.pdfbox.util.PDFOperator; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class SetStrokingColorSpace extends OperatorProcessor { private static final float[] EMPTY_FLOAT_ARRAY = new float[0]; /** * CS Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { //(PDF 1.1) Set color space for stroking operations COSName name = (COSName)arguments.get( 0 ); PDColorSpace cs = PDColorSpaceFactory.createColorSpace( name, context.getColorSpaces(), context.getResources().getPatterns() ); PDColorState color = context.getGraphicsState().getStrokingColor(); color.setColorSpace( cs ); int numComponents = cs.getNumberOfComponents(); float[] values = EMPTY_FLOAT_ARRAY; if( numComponents >= 0 ) { values = new float[numComponents]; for( int i=0; i arguments) throws IOException { PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); float[] values = new float[3]; for (int i = 0; i < arguments.size(); i++) { values[i] = ((COSNumber) arguments.get(i)).floatValue(); } colorInstance.setColorSpaceValue(values); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetStrokingCalRGBColor.java0000644000000000000000000000376612645757432030726 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.util.PDFOperator; /** *

Structural modification of the PDFEngine class : * the long sequence of conditions in processOperator is replaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class SetStrokingCalRGBColor extends OperatorProcessor { /** * RG Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorState color = context.getGraphicsState().getStrokingColor(); float[] values = new float[3]; for( int i=0; iSet the stroking color space.

* * @version $Revision: 1.0 $ */ public class SetStrokingColor extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(SetStrokingColor.class); /** * SC,SCN Set color space for stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { PDColorSpace colorSpace = context.getGraphicsState().getStrokingColor().getColorSpace(); if (colorSpace != null) { OperatorProcessor newOperator = null; if (colorSpace instanceof PDDeviceGray) { newOperator = new SetStrokingGrayColor(); } else if (colorSpace instanceof PDDeviceRGB) { newOperator = new SetStrokingRGBColor(); } else if (colorSpace instanceof PDDeviceCMYK) { newOperator = new SetStrokingCMYKColor(); } else if (colorSpace instanceof PDICCBased) { newOperator = new SetStrokingICCBasedColor(); } else if (colorSpace instanceof PDCalRGB) { newOperator = new SetStrokingCalRGBColor(); } else if (colorSpace instanceof PDSeparation) { newOperator = new SetStrokingSeparation(); } else if (colorSpace instanceof PDDeviceN) { newOperator = new SetStrokingDeviceN(); } else if (colorSpace instanceof PDPattern) { newOperator = new SetStrokingPattern(); } else if (colorSpace instanceof PDIndexed) { newOperator = new SetStrokingIndexed(); } else if (colorSpace instanceof PDLab) { newOperator = new SetStrokingLabColor(); } if (newOperator != null) { newOperator.setContext(getContext()); newOperator.process(operator, arguments); } else { LOG.info("Not supported colorspace "+colorSpace.getName() + " within operator "+operator.getOperation()); } } else { LOG.warn("Colorspace not found in "+getClass().getName()+".process!!"); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/CloseAndStrokePath.java0000644000000000000000000000314712645757432030166 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** * Implementation of content stream operator for page drawer. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class CloseAndStrokePath extends OperatorProcessor { /** * s close and stroke the path. * @param operator The operator that is being executed. * @param arguments List * * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { context.processOperator( "h", arguments ); context.processOperator( "S", arguments ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GRestore.java0000644000000000000000000000351212645757432026217 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; import org.apache.pdfbox.util.PDFOperator; /** * Process the Q operator. * * @author Huault : huault@free.fr * */ public class GRestore extends OperatorProcessor { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(GRestore.class); /** * {@inheritDoc} */ public void process(PDFOperator operator, List arguments) { if (context.getGraphicsStack().size() > 0) { context.setGraphicsState((PDGraphicsState) context.getGraphicsStack().pop()); } else { // this shouldn't happen but it does, see PDFBOX-161 // TODO make this self healing mechanism optional for preflight?? LOG.error("GRestore: no graphics state left to be restored."); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetGraphicsStateParameters.java0000644000000000000000000000403412645757432031726 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.PDExtendedGraphicsState; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class SetGraphicsStateParameters extends OperatorProcessor { /** * gs Set parameters from graphics state parameter dictionary. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { //set parameters from graphics state parameter dictionary COSName graphicsName = (COSName)arguments.get( 0 ); PDExtendedGraphicsState gs = (PDExtendedGraphicsState)context.getGraphicsStates().get( graphicsName.getName() ); gs.copyIntoGraphicsState( context.getGraphicsState() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetLineMiterLimit.java0000644000000000000000000000337612645757432030040 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class SetLineMiterLimit extends OperatorProcessor { /** * w Set miter limit. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { COSNumber miterLimit = (COSNumber)arguments.get( 0 ); context.getGraphicsState().setMiterLimit( miterLimit.doubleValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetMatrix.java0000644000000000000000000000425312645757432026410 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFOperator; /** * @author Huault : huault@free.fr * @version $Revision: 1.4 $ */ public class SetMatrix extends OperatorProcessor { /** * Tm Set text matrix and text line matrix. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { //Set text matrix and text line matrix COSNumber a = (COSNumber)arguments.get( 0 ); COSNumber b = (COSNumber)arguments.get( 1 ); COSNumber c = (COSNumber)arguments.get( 2 ); COSNumber d = (COSNumber)arguments.get( 3 ); COSNumber e = (COSNumber)arguments.get( 4 ); COSNumber f = (COSNumber)arguments.get( 5 ); Matrix textMatrix = new Matrix(); textMatrix.setValue( 0, 0, a.floatValue() ); textMatrix.setValue( 0, 1, b.floatValue() ); textMatrix.setValue( 1, 0, c.floatValue() ); textMatrix.setValue( 1, 1, d.floatValue() ); textMatrix.setValue( 2, 0, e.floatValue() ); textMatrix.setValue( 2, 1, f.floatValue() ); context.setTextMatrix( textMatrix ); context.setTextLineMatrix( textMatrix.copy() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetNonStrokingColorSpace.java0000644000000000000000000000530512645757432031371 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; import org.apache.pdfbox.util.PDFOperator; /** *

Set the non stroking color space.

* * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class SetNonStrokingColorSpace extends OperatorProcessor { private static final float[] EMPTY_FLOAT_ARRAY = new float[0]; /** * cs Set color space for non stroking operations. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { // (PDF 1.1) Set color space for stroking operations COSName name = (COSName)arguments.get( 0 ); PDColorSpace cs = PDColorSpaceFactory.createColorSpace( name, context.getColorSpaces(), context.getResources().getPatterns() ); PDColorState colorInstance = context.getGraphicsState().getNonStrokingColor(); colorInstance.setColorSpace( cs ); int numComponents = cs.getNumberOfComponents(); float[] values = EMPTY_FLOAT_ARRAY; if( numComponents >= 0 ) { values = new float[numComponents]; for( int i=0; i arguments) throws IOException { COSName tag = null; COSDictionary properties = null; for (COSBase argument : arguments) { if (argument instanceof COSName) { tag = (COSName) argument; } else if (argument instanceof COSDictionary) { properties = (COSDictionary) argument; } } if (this.context instanceof PDFMarkedContentExtractor) { ((PDFMarkedContentExtractor) this.context).beginMarkedContentSequence(tag, properties); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/BeginText.java0000644000000000000000000000275112645757432026362 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.PDFOperator; /** * * @author Ben Litchfield * @author Huault : huault@free.fr * @version $Revision: 1.5 $ */ public class BeginText extends OperatorProcessor { /** * process : BT : Begin text object. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { context.setTextMatrix( new Matrix()); context.setTextLineMatrix( new Matrix() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/EndText.java0000644000000000000000000000255112645757432026042 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.util.PDFOperator; /** * * @author Huault : huault@free.fr * @version $Revision: 1.4 $ */ public class EndText extends OperatorProcessor { /** * process : ET : End text object. * @param operator The operator that is being executed. * @param arguments List */ public void process(PDFOperator operator, List arguments) { context.setTextMatrix( null); context.setTextLineMatrix( null); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetTextRise.java0000644000000000000000000000365312645757432026716 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util.operator; import java.util.List; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.util.PDFOperator; import java.io.IOException; /** *

Structal modification of the PDFEngine class : * the long sequence of conditions in processOperator is remplaced by * this strategy pattern.

* * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class SetTextRise extends OperatorProcessor { /** * Ts Set text rise. * @param operator The operator that is being executed. * @param arguments List * @throws IOException If an error occurs while processing the font. */ public void process(PDFOperator operator, List arguments) throws IOException { if (arguments.size() < 1) { return; } COSBase base = arguments.get(0); if (!(base instanceof COSNumber)) { return; } COSNumber rise = (COSNumber) base; context.getGraphicsState().getTextState().setRise( rise.floatValue() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/ExtensionFileFilter.java0000644000000000000000000000410212645757432026550 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.File; import javax.swing.filechooser.FileFilter; /** * A FileFilter that will only accept files of a certain extension. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class ExtensionFileFilter extends FileFilter { private String[] extensions = null; private String desc; /** * Constructor. * * @param ext A list of filename extensions, ie new String[] { "PDF"}. * @param description A description of the files. */ public ExtensionFileFilter( String[] ext, String description ) { extensions = ext; desc = description; } /** * {@inheritDoc} */ public boolean accept(File pathname) { if (pathname.isDirectory()) { return true; } boolean acceptable = false; String name = pathname.getName().toUpperCase(); for( int i=0; !acceptable && iBen Litchfield * @version $Revision: 1.4 $ */ public class BitFlagHelper { private BitFlagHelper() { //helper class should not be constructed } /** * Sets the given boolean value at bitPos in the flags. * * @param dic The dictionary to set the value into. * @param field The name of the field to set the value into. * @param bitFlag the bit position to set the value in. * @param value the value the bit position should have. * * @deprecated use {@link #setFlag(COSDictionary, COSName, int, boolean)} using COSName constants instead */ public static final void setFlag( COSDictionary dic, String field, int bitFlag, boolean value ) { setFlag(dic, COSName.getPDFName(field), bitFlag, value); } /** * Sets the given boolean value at bitPos in the flags. * * @param dic The dictionary to set the value into. * @param field The COSName of the field to set the value into. * @param bitFlag the bit position to set the value in. * @param value the value the bit position should have. */ public static final void setFlag( COSDictionary dic, COSName field, int bitFlag, boolean value ) { int currentFlags = dic.getInt( field, 0 ); if( value ) { currentFlags = currentFlags | bitFlag; } else { currentFlags = currentFlags &= ~bitFlag; } dic.setInt( field, currentFlags ); } /** * Gets the boolean value from the flags at the given bit * position. * * @param dic The dictionary to get the field from. * @param field The name of the field to get the flag from. * @param bitFlag the bitPosition to get the value from. * * @return true if the number at bitPos is '1' * * @deprecated use {@link #getFlag(COSDictionary, COSName, int)} using COSName constants instead */ public static final boolean getFlag(COSDictionary dic, String field, int bitFlag) { return getFlag(dic, COSName.getPDFName(field), bitFlag); } /** * Gets the boolean value from the flags at the given bit * position. * * @param dic The dictionary to get the field from. * @param field The COSName of the field to get the flag from. * @param bitFlag the bitPosition to get the value from. * * @return true if the number at bitPos is '1' */ public static final boolean getFlag(COSDictionary dic, COSName field, int bitFlag) { int ff = dic.getInt( field, 0 ); return (ff & bitFlag) == bitFlag; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java0000644000000000000000000006065512645757432025560 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.Stack; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.exceptions.WrappedIOException; import org.apache.pdfbox.pdfparser.PDFStreamParser; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDMatrix; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFontFactory; import org.apache.pdfbox.pdmodel.font.PDType3Font; import org.apache.pdfbox.pdmodel.graphics.PDExtendedGraphicsState; import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.apache.pdfbox.util.operator.OperatorProcessor; /** * This class will run through a PDF content stream and execute certain operations * and provide a callback interface for clients that want to do things with the stream. * See the PDFTextStripper class for an example of how to use this class. * * @author Ben Litchfield * @version $Revision: 1.38 $ */ public class PDFStreamEngine { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFStreamEngine.class); /** * The PDF operators that are ignored by this engine. */ private final Set unsupportedOperators = new HashSet(); private PDGraphicsState graphicsState = null; private Matrix textMatrix = null; private Matrix textLineMatrix = null; private Stack graphicsStack = new Stack(); private Map operators = new HashMap(); private Stack streamResourcesStack = new Stack(); private PDPage page; private int validCharCnt; private int totalCharCnt; /** * Flag to skip malformed or otherwise unparseable input where possible. */ private boolean forceParsing = false; /** * Constructor. */ public PDFStreamEngine() { //default constructor validCharCnt = 0; totalCharCnt = 0; } /** * Constructor with engine properties. The property keys are all * PDF operators, the values are class names used to execute those * operators. An empty value means that the operator will be silently * ignored. * * @param properties The engine properties. * * @throws IOException If there is an error setting the engine properties. */ public PDFStreamEngine( Properties properties ) throws IOException { if( properties == null ) { throw new NullPointerException( "properties cannot be null" ); } Enumeration names = properties.propertyNames(); for ( Object name : Collections.list( names ) ) { String operator = name.toString(); String processorClassName = properties.getProperty( operator ); if( "".equals( processorClassName ) ) { unsupportedOperators.add( operator ); } else { try { Class klass = Class.forName( processorClassName ); OperatorProcessor processor = (OperatorProcessor) klass.newInstance(); registerOperatorProcessor( operator, processor ); } catch( Exception e ) { throw new WrappedIOException( "OperatorProcessor class " + processorClassName + " could not be instantiated", e ); } } } validCharCnt = 0; totalCharCnt = 0; } /** * Indicates if force parsing is activated. * * @return true if force parsing is active */ public boolean isForceParsing() { return forceParsing; } /** * Enable/Disable force parsing. * * @param forceParsingValue true activates force parsing */ public void setForceParsing(boolean forceParsingValue) { forceParsing = forceParsingValue; } /** * Register a custom operator processor with the engine. * * @param operator The operator as a string. * @param op Processor instance. */ public void registerOperatorProcessor( String operator, OperatorProcessor op ) { op.setContext( this ); operators.put( operator, op ); } /** * This method must be called between processing documents. The * PDFStreamEngine caches information for the document between pages * and this will release the cached information. This only needs * to be called if processing a new document. * */ public void resetEngine() { validCharCnt = 0; totalCharCnt = 0; } /** * This will process the contents of the stream. * * @param aPage The page. * @param resources The location to retrieve resources. * @param cosStream the Stream to execute. * * * @throws IOException if there is an error accessing the stream. */ public void processStream( PDPage aPage, PDResources resources, COSStream cosStream ) throws IOException { graphicsState = new PDGraphicsState(aPage.findCropBox()); textMatrix = null; textLineMatrix = null; graphicsStack.clear(); streamResourcesStack.clear(); processSubStream( aPage, resources, cosStream ); } /** * Process a sub stream of the current stream. * * @param aPage The page used for drawing. * @param resources The resources used when processing the stream. * @param cosStream The stream to process. * * @throws IOException If there is an exception while processing the stream. */ public void processSubStream(PDPage aPage, PDResources resources, COSStream cosStream) throws IOException { page = aPage; if (resources != null) { streamResourcesStack.push(resources); try { processSubStream(cosStream); } finally { streamResourcesStack.pop().clear(); } } else { processSubStream(cosStream); } } private void processSubStream(COSStream cosStream) throws IOException { List arguments = new ArrayList(); PDFStreamParser parser = new PDFStreamParser(cosStream, forceParsing); try { Iterator iter = parser.getTokenIterator(); while (iter.hasNext()) { Object next = iter.next(); if (LOG.isDebugEnabled()) { LOG.debug("processing substream token: " + next); } if (next instanceof COSObject) { arguments.add(((COSObject) next).getObject()); } else if (next instanceof PDFOperator) { processOperator((PDFOperator) next, arguments); arguments = new ArrayList(); } else { arguments.add((COSBase) next); } } } finally { parser.close(); } } /** * A method provided as an event interface to allow a subclass to perform * some specific functionality when text needs to be processed. * * @param text The text to be processed. */ protected void processTextPosition( TextPosition text ) { //subclasses can override to provide specific functionality. } /** * A method provided as an event interface to allow a subclass to perform * some specific functionality on the string encoded by a glyph. * * @param str The string to be processed. */ protected String inspectFontEncoding( String str ) { return str; } /** * Process encoded text from the PDF Stream. * You should override this method if you want to perform an action when * encoded text is being processed. * * @param string The encoded text * * @throws IOException If there is an error processing the string */ public void processEncodedText( byte[] string ) throws IOException { /* Note on variable names. There are three different units being used * in this code. Character sizes are given in glyph units, text locations * are initially given in text units, and we want to save the data in * display units. The variable names should end with Text or Disp to * represent if the values are in text or disp units (no glyph units are saved). */ final float fontSizeText = graphicsState.getTextState().getFontSize(); final float horizontalScalingText = graphicsState.getTextState().getHorizontalScalingPercent()/100f; //float verticalScalingText = horizontalScaling;//not sure if this is right but what else to do??? final float riseText = graphicsState.getTextState().getRise(); final float wordSpacingText = graphicsState.getTextState().getWordSpacing(); final float characterSpacingText = graphicsState.getTextState().getCharacterSpacing(); //We won't know the actual number of characters until //we process the byte data(could be two bytes each) but //it won't ever be more than string.length*2(there are some cases //were a single byte will result in two output characters "fi" PDFont font = graphicsState.getTextState().getFont(); if (font == null) { LOG.warn("No current font, will use default"); font = PDFontFactory.createDefaultFont(); } // all fonts are providing the width/height of a character in thousandths of a unit of text space float fontMatrixXScaling = 1/1000f; float fontMatrixYScaling = 1/1000f; float glyphSpaceToTextSpaceFactor = 1/1000f; // except Type3 fonts, those are providing the width of a character in glyph space units if (font instanceof PDType3Font) { PDMatrix fontMatrix = font.getFontMatrix(); fontMatrixXScaling = fontMatrix.getValue(0, 0); fontMatrixYScaling = fontMatrix.getValue(1, 1); glyphSpaceToTextSpaceFactor = fontMatrix.getValue( 0, 0 ); } float spaceWidthText=0; try { // to avoid crash as described in PDFBOX-614 // lets see what the space displacement should be spaceWidthText = (font.getSpaceWidth() * glyphSpaceToTextSpaceFactor); } catch (Throwable exception) { LOG.warn(exception, exception); } if (spaceWidthText == 0) { spaceWidthText = (font.getAverageFontWidth() * glyphSpaceToTextSpaceFactor); // The average space width appears to be higher than necessary // so lets make it a little bit smaller. spaceWidthText *= .80f; } if (spaceWidthText == 0) { spaceWidthText = 1.0f; // if could not find font, use a generic value } float maxVerticalDisplacementText = 0; Matrix textStateParameters = new Matrix(); textStateParameters.setValue(0,0, fontSizeText*horizontalScalingText); textStateParameters.setValue(1,1, fontSizeText); textStateParameters.setValue(2,1, riseText); int pageRotation = page.findRotation(); float pageHeight = page.findCropBox().getHeight(); float pageWidth = page.findCropBox().getWidth(); Matrix ctm = getGraphicsState().getCurrentTransformationMatrix(); Matrix textXctm = new Matrix(); Matrix textMatrixEnd = new Matrix(); Matrix td = new Matrix(); Matrix tempMatrix = new Matrix(); int codeLength = 1; for( int i=0; i arguments ) throws IOException { try { PDFOperator oper = PDFOperator.getOperator( operation ); processOperator( oper, arguments ); } catch (IOException e) { LOG.warn(e, e); } } /** * This is used to handle an operation. * * @param operator The operation to perform. * @param arguments The list of arguments. * * @throws IOException If there is an error processing the operation. */ protected void processOperator( PDFOperator operator, List arguments ) throws IOException { try { String operation = operator.getOperation(); OperatorProcessor processor = (OperatorProcessor)operators.get( operation ); if( processor != null ) { processor.setContext(this); processor.process( operator, arguments ); } else { if (!unsupportedOperators.contains(operation)) { LOG.info("unsupported/disabled operation: " + operation); unsupportedOperators.add(operation); } } } catch (Exception e) { LOG.warn(e, e); } } /** * @return Returns the colorSpaces. */ public Map getColorSpaces() { return streamResourcesStack.peek().getColorSpaces(); } /** * @return Returns the colorSpaces. */ public Map getXObjects() { return streamResourcesStack.peek().getXObjects(); } /** * @param value The colorSpaces to set. */ public void setColorSpaces(Map value) { streamResourcesStack.peek().setColorSpaces(value); } /** * @return Returns the fonts. */ public Map getFonts() { if ( streamResourcesStack.isEmpty() ) { return Collections.emptyMap(); } return streamResourcesStack.peek().getFonts(); } /** * @param value The fonts to set. */ public void setFonts(Map value) { streamResourcesStack.peek().setFonts(value); } /** * @return Returns the graphicsStack. */ public Stack getGraphicsStack() { return graphicsStack; } /** * @param value The graphicsStack to set. */ public void setGraphicsStack(Stack value) { graphicsStack = value; } /** * @return Returns the graphicsState. */ public PDGraphicsState getGraphicsState() { return graphicsState; } /** * @param value The graphicsState to set. */ public void setGraphicsState(PDGraphicsState value) { graphicsState = value; } /** * @return Returns the graphicsStates. */ public Map getGraphicsStates() { return streamResourcesStack.peek().getGraphicsStates(); } /** * @param value The graphicsStates to set. */ public void setGraphicsStates(Map value) { streamResourcesStack.peek().setGraphicsStates(value); } /** * @return Returns the textLineMatrix. */ public Matrix getTextLineMatrix() { return textLineMatrix; } /** * @param value The textLineMatrix to set. */ public void setTextLineMatrix(Matrix value) { textLineMatrix = value; } /** * @return Returns the textMatrix. */ public Matrix getTextMatrix() { return textMatrix; } /** * @param value The textMatrix to set. */ public void setTextMatrix(Matrix value) { textMatrix = value; } /** * @return Returns the resources. */ public PDResources getResources() { return streamResourcesStack.peek(); } /** * Get the current page that is being processed. * * @return The page being processed. */ public PDPage getCurrentPage() { return page; } /** * Get the total number of valid characters in the doc * that could be decoded in processEncodedText(). * @return The number of valid characters. */ public int getValidCharCnt() { return validCharCnt; } /** * Get the total number of characters in the doc * (including ones that could not be mapped). * @return The number of characters. */ public int getTotalCharCnt() { return totalCharCnt; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/ICU4JImpl.java0000644000000000000000000001310512645757432024271 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import com.ibm.icu.text.Bidi; import com.ibm.icu.text.Normalizer; /** * This class is an implementation the the ICU4J class. TextNormalize * will call this only if the ICU4J library exists in the classpath. * @author Brian Carrier * @version $Revision: 1.0 $ * * @deprecated will be removed in 2.0.0 */ public class ICU4JImpl { Bidi bidi; /** * Constructor. */ public ICU4JImpl() { bidi = new Bidi(); /* We do not use bidi.setInverse() because that uses * Bidi.REORDER_INVERSE_NUMBERS_AS_L, which caused problems * in some test files. For example, a file had a line of: * 0 1 / ARABIC * and the 0 and 1 were reversed in the end result. * REORDER_INVERSE_LIKE_DIRECT is the inverse Bidi mode * that more closely reflects the Unicode spec. */ bidi.setReorderingMode(Bidi.REORDER_INVERSE_LIKE_DIRECT); } /** * Takes a line of text in presentation order and converts it to logical order. * @see TextNormalize#makeLineLogicalOrder(String, boolean) * * @param str String to convert * @param isRtlDominant RTL (right-to-left) will be the dominant text direction * @return The converted string */ public String makeLineLogicalOrder(String str, boolean isRtlDominant) { bidi.setPara(str, isRtlDominant?Bidi.RTL:Bidi.LTR, null); /* Set the mirror flag so that parentheses and other mirror symbols * are properly reversed, when needed. With this removed, lines * such as (CBA) in the PDF file will come out like )ABC( in logical * order. */ return bidi.writeReordered(Bidi.DO_MIRRORING); } /** * Normalize presentation forms of characters to the separate parts. * @see TextNormalize#normalizePres(String) * * @param str String to normalize * @return Normalized form */ public String normalizePres(String str) { StringBuilder builder = null; int p = 0; int q = 0; int strLength = str.length(); for (; q < strLength; q++) { // We only normalize if the codepoint is in a given range. // Otherwise, NFKC converts too many things that would cause // confusion. For example, it converts the micro symbol in // extended Latin to the value in the Greek script. We normalize // the Unicode Alphabetic and Arabic A&B Presentation forms. char c = str.charAt(q); if ((0xFB00 <= c && c <= 0xFDFF) || (0xFE70 <= c && c <= 0xFEFF)) { if (builder == null) { builder = new StringBuilder(strLength * 2); } builder.append(str.substring(p, q)); // Some fonts map U+FDF2 differently than the Unicode spec. // They add an extra U+0627 character to compensate. // This removes the extra character for those fonts. if(c == 0xFDF2 && q > 0 && (str.charAt(q-1) == 0x0627 || str.charAt(q-1) == 0xFE8D)) { builder.append("\u0644\u0644\u0647"); } else { // Trim because some decompositions have an extra space, // such as U+FC5E builder.append( Normalizer.normalize(c, Normalizer.NFKC).trim()); } p = q + 1; } } if (builder == null) { return str; } else { builder.append(str.substring(p, q)); return builder.toString(); } } /** * Decomposes Diacritic characters to their combining forms. * * @param str String to be Normalized * @return A Normalized String */ public String normalizeDiac(String str) { StringBuilder retStr = new StringBuilder(); int strLength = str.length(); for (int i = 0; i < strLength; i++) { char c = str.charAt(i); int type = Character.getType(c); if(type == Character.NON_SPACING_MARK || type == Character.MODIFIER_SYMBOL || type == Character.MODIFIER_LETTER) { /* * Trim because some decompositions have an extra space, such as * U+00B4 */ retStr.append(Normalizer.normalize(c, Normalizer.NFKC).trim()); } else { retStr.append(str.charAt(i)); } } return retStr.toString(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStripperByArea.java0000644000000000000000000001520212645757432026724 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Vector; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDStream; /** * This will extract text from a specified region in the PDF. * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class PDFTextStripperByArea extends PDFTextStripper { private List regions = new ArrayList(); private Map regionArea = new HashMap(); private Map>> regionCharacterList = new HashMap>>(); private Map regionText = new HashMap(); /** * Constructor. * @throws IOException If there is an error loading properties. */ public PDFTextStripperByArea() throws IOException { super(); setPageSeparator( "" ); } /** * Instantiate a new PDFTextStripperArea object. Loading all of the operator * mappings from the properties object that is passed in. Does not convert * the text to more encoding-specific output. * * @param props * The properties containing the mapping of operators to * PDFOperator classes. * * @throws IOException * If there is an error reading the properties. */ public PDFTextStripperByArea(Properties props) throws IOException { super(props); setPageSeparator(""); } /** * Instantiate a new PDFTextStripperArea object. This object will load * properties from PDFTextStripper.properties and will apply * encoding-specific conversions to the output text. * * @param encoding * The encoding that the output will be written in. * @throws IOException * If there is an error reading the properties. */ public PDFTextStripperByArea(String encoding) throws IOException { super(encoding); setPageSeparator(""); } /** * Add a new region to group text by. * * @param regionName The name of the region. * @param rect The rectangle area to retrieve the text from. */ public void addRegion( String regionName, Rectangle2D rect ) { regions.add( regionName ); regionArea.put( regionName, rect ); } /** * Delete a region to group text by. If the region does not exist, this method does nothing. * * @param regionName The name of the region to delete. */ public void removeRegion(String regionName) { regions.remove(regionName); regionArea.remove(regionName); } /** * Get the list of regions that have been setup. * * @return A list of java.lang.String objects to identify the region names. */ public List getRegions() { return regions; } /** * Get the text for the region, this should be called after extractRegions(). * * @param regionName The name of the region to get the text from. * @return The text that was identified in that region. */ public String getTextForRegion( String regionName ) { StringWriter text = regionText.get( regionName ); return text.toString(); } /** * Process the page to extract the region text. * * @param page The page to extract the regions from. * @throws IOException If there is an error while extracting text. */ public void extractRegions( PDPage page ) throws IOException { Iterator regionIter = regions.iterator(); while( regionIter.hasNext() ) { setStartPage(getCurrentPageNo()); setEndPage(getCurrentPageNo()); //reset the stored text for the region so this class //can be reused. String regionName = regionIter.next(); Vector> regionCharactersByArticle = new Vector>(); regionCharactersByArticle.add( new ArrayList() ); regionCharacterList.put( regionName, regionCharactersByArticle ); regionText.put( regionName, new StringWriter() ); } PDStream contentStream = page.getContents(); if( contentStream != null ) { COSStream contents = contentStream.getStream(); processPage( page, contents ); } } /** * {@inheritDoc} */ protected void processTextPosition( TextPosition text ) { Iterator regionIter = regionArea.keySet().iterator(); while( regionIter.hasNext() ) { String region = regionIter.next(); Rectangle2D rect = regionArea.get( region ); if( rect.contains( text.getX(), text.getY() ) ) { charactersByArticle = (Vector)regionCharacterList.get( region ); super.processTextPosition( text ); } } } /** * This will print the processed page text to the output stream. * * @throws IOException If there is an error writing the text. */ protected void writePage() throws IOException { Iterator regionIter = regionArea.keySet().iterator(); while( regionIter.hasNext() ) { String region = regionIter.next(); charactersByArticle = (Vector)regionCharacterList.get( region ); output = regionText.get( region ); super.writePage(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/StringUtil.java0000644000000000000000000000251612645757432024741 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.UnsupportedEncodingException; public class StringUtil { /** * Converts a string to it ISO-8859-1 byte sequence * * It is an workaround for variable initialisations outside of functions. */ public static byte[] getBytes(String s) { try { return s.getBytes("ISO-8859-1"); } catch(UnsupportedEncodingException e) { throw new RuntimeException("Unsupported Encoding", e); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMarkedContentExtractor.java0000644000000000000000000002377712645757432027635 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Stack; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDMarkedContent; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; /** * This is an stream engine to extract the marked content of a pdf. * @author koch * @version $Revision$ */ public class PDFMarkedContentExtractor extends PDFStreamEngine { private boolean suppressDuplicateOverlappingText = true; private List markedContents = new ArrayList(); private Stack currentMarkedContents = new Stack(); private Map> characterListMapping = new HashMap>(); /** * encoding that text will be written in (or null). */ protected String outputEncoding; /** * The normalizer is used to remove text ligatures/presentation forms * and to correct the direction of right to left text, such as Arabic and Hebrew. */ private TextNormalize normalize = null; /** * Instantiate a new PDFTextStripper object. This object will load * properties from PDFMarkedContentExtractor.properties and will not * do anything special to convert the text to a more encoding-specific * output. * * @throws IOException If there is an error loading the properties. */ public PDFMarkedContentExtractor() throws IOException { super( ResourceLoader.loadProperties( "org/apache/pdfbox/resources/PDFMarkedContentExtractor.properties", true ) ); this.outputEncoding = null; this.normalize = new TextNormalize(this.outputEncoding); } /** * Instantiate a new PDFTextStripper object. Loading all of the operator mappings * from the properties object that is passed in. Does not convert the text * to more encoding-specific output. * * @param props The properties containing the mapping of operators to PDFOperator * classes. * * @throws IOException If there is an error reading the properties. */ public PDFMarkedContentExtractor( Properties props ) throws IOException { super( props ); this.outputEncoding = null; this.normalize = new TextNormalize(this.outputEncoding); } /** * Instantiate a new PDFTextStripper object. This object will load * properties from PDFMarkedContentExtractor.properties and will apply * encoding-specific conversions to the output text. * * @param encoding The encoding that the output will be written in. * @throws IOException If there is an error reading the properties. */ public PDFMarkedContentExtractor( String encoding ) throws IOException { super( ResourceLoader.loadProperties( "org/apache/pdfbox/resources/PDFMarkedContentExtractor.properties", true )); this.outputEncoding = encoding; this.normalize = new TextNormalize(this.outputEncoding); } /** * This will determine of two floating point numbers are within a specified variance. * * @param first The first number to compare to. * @param second The second number to compare to. * @param variance The allowed variance. */ private boolean within( float first, float second, float variance ) { return second > first - variance && second < first + variance; } public void beginMarkedContentSequence(COSName tag, COSDictionary properties) { PDMarkedContent markedContent = PDMarkedContent.create(tag, properties); if (this.currentMarkedContents.isEmpty()) { this.markedContents.add(markedContent); } else { PDMarkedContent currentMarkedContent = this.currentMarkedContents.peek(); if (currentMarkedContent != null) { currentMarkedContent.addMarkedContent(markedContent); } } this.currentMarkedContents.push(markedContent); } public void endMarkedContentSequence() { if (!this.currentMarkedContents.isEmpty()) { this.currentMarkedContents.pop(); } } public void xobject(PDXObject xobject) { if (!this.currentMarkedContents.isEmpty()) { this.currentMarkedContents.peek().addXObject(xobject); } } /** * This will process a TextPosition object and add the * text to the list of characters on a page. It takes care of * overlapping text. * * @param text The text to process. */ protected void processTextPosition( TextPosition text ) { boolean showCharacter = true; if( this.suppressDuplicateOverlappingText ) { showCharacter = false; String textCharacter = text.getCharacter(); float textX = text.getX(); float textY = text.getY(); List sameTextCharacters = this.characterListMapping.get( textCharacter ); if( sameTextCharacters == null ) { sameTextCharacters = new ArrayList(); this.characterListMapping.put( textCharacter, sameTextCharacters ); } // RDD - Here we compute the value that represents the end of the rendered // text. This value is used to determine whether subsequent text rendered // on the same line overwrites the current text. // // We subtract any positive padding to handle cases where extreme amounts // of padding are applied, then backed off (not sure why this is done, but there // are cases where the padding is on the order of 10x the character width, and // the TJ just backs up to compensate after each character). Also, we subtract // an amount to allow for kerning (a percentage of the width of the last // character). // boolean suppressCharacter = false; float tolerance = (text.getWidth()/textCharacter.length())/3.0f; for( int i=0; i textList = new ArrayList(); /* In the wild, some PDF encoded documents put diacritics (accents on * top of characters) into a separate Tj element. When displaying them * graphically, the two chunks get overlayed. With text output though, * we need to do the overlay. This code recombines the diacritic with * its associated character if the two are consecutive. */ if(textList.isEmpty()) { textList.add(text); } else { /* test if we overlap the previous entry. * Note that we are making an assumption that we need to only look back * one TextPosition to find what we are overlapping. * This may not always be true. */ TextPosition previousTextPosition = (TextPosition)textList.get(textList.size()-1); if(text.isDiacritic() && previousTextPosition.contains(text)) { previousTextPosition.mergeDiacritic(text, this.normalize); } /* If the previous TextPosition was the diacritic, merge it into this * one and remove it from the list. */ else if(previousTextPosition.isDiacritic() && text.contains(previousTextPosition)) { text.mergeDiacritic(previousTextPosition, this.normalize); textList.remove(textList.size()-1); textList.add(text); } else { textList.add(text); } } if (!this.currentMarkedContents.isEmpty()) { this.currentMarkedContents.peek().addText(text); } } } public List getMarkedContents() { return this.markedContents; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/TextPosition.java0000644000000000000000000006370612645757432025316 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.font.PDFont; /** * This represents a string and a position on the screen of those characters. * * @author Ben Litchfield * @version $Revision: 1.12 $ */ public class TextPosition { private static final Log LOG = LogFactory.getLog(TextPosition.class); /* TextMatrix for the start of the text object. Coordinates * are in display units and have not been adjusted. */ private Matrix textPos; // ending X and Y coordinates in display units private float endX; private float endY; private float maxTextHeight; // maximum height of text, in display units private int rot; // 0, 90, 180, 270 degrees of page rotation private float x = Float.NEGATIVE_INFINITY; private float y = Float.NEGATIVE_INFINITY; private float pageHeight; private float pageWidth; private float[] widths; private float widthOfSpace; // width of a space, in display units private String str; private int[] unicodeCP; private PDFont font; private float fontSize; private int fontSizePt; // TODO remove unused value private float wordSpacing; // word spacing value, in display units /** * Constructor. */ protected TextPosition() { } /** * Constructor. * * @param page Page that the text is located in * @param textPositionSt TextMatrix for start of text (in display units) * @param textPositionEnd TextMatrix for end of text (in display units) * @param maxFontH Maximum height of text (in display units) * @param individualWidths The width of each individual character. (in ? units) * @param spaceWidth The width of the space character. (in display units) * @param string The character to be displayed. * @param currentFont The current for for this text position. * @param fontSizeValue The new font size. * @param fontSizeInPt The font size in pt units. * @param ws The word spacing parameter (in display units) */ public TextPosition( PDPage page, Matrix textPositionSt, Matrix textPositionEnd, float maxFontH, float[] individualWidths, float spaceWidth, String string, PDFont currentFont, float fontSizeValue, int fontSizeInPt, float ws ) { this.textPos = textPositionSt; this.endX = textPositionEnd.getXPosition(); this.endY = textPositionEnd.getYPosition(); this.rot = page.findRotation(); // make sure it is 0 to 270 and no negative numbers if(this.rot < 0) { rot += 360; } else if (rot >= 360) { rot -= 360; } this.maxTextHeight = maxFontH; this.pageHeight = page.findMediaBox().getHeight(); this.pageWidth = page.findMediaBox().getWidth(); this.widths = individualWidths; this.widthOfSpace = spaceWidth; this.str = string; this.font = currentFont; this.fontSize = fontSizeValue; this.fontSizePt = fontSizeInPt; this.wordSpacing = ws; } /** * Constructor. * * @param pageRotation rotation of the page that the text is located in * @param pageWidthValue rotation of the page that the text is located in * @param pageHeightValue rotation of the page that the text is located in * @param textPositionSt TextMatrix for start of text (in display units) * @param textPositionEnd TextMatrix for end of text (in display units) * @param maxFontH Maximum height of text (in display units) * @param individualWidth The width of the given character/string. (in ? units) * @param spaceWidth The width of the space character. (in display units) * @param string The character to be displayed. * @param currentFont The current for for this text position. * @param fontSizeValue The new font size. * @param fontSizeInPt The font size in pt units. * * @deprecated Use {@link #TextPosition(int, float, float, Matrix, float, float, float, float, float, * String, PDFont, float, int)} instead. */ public TextPosition( int pageRotation, float pageWidthValue, float pageHeightValue, Matrix textPositionSt, Matrix textPositionEnd, float maxFontH, float individualWidth, float spaceWidth, String string, PDFont currentFont, float fontSizeValue, int fontSizeInPt ) { this(pageRotation, pageWidthValue, pageHeightValue, textPositionSt, textPositionEnd.getXPosition(), textPositionEnd.getYPosition(), maxFontH, individualWidth, spaceWidth, string, null, currentFont, fontSizeValue, fontSizeInPt); } /** * Constructor. * * @param pageRotation rotation of the page that the text is located in * @param pageWidthValue rotation of the page that the text is located in * @param pageHeightValue rotation of the page that the text is located in * @param textPositionSt TextMatrix for start of text (in display units) * @param endXValue x coordinate of the end position * @param endYValue y coordinate of the end position * @param maxFontH Maximum height of text (in display units) * @param individualWidth The width of the given character/string. (in ? units) * @param spaceWidth The width of the space character. (in display units) * @param string The character to be displayed. * @param currentFont The current for for this text position. * @param fontSizeValue The new font size. * @param fontSizeInPt The font size in pt units. * * @deprecated use {@link #TextPosition(int, float, float, Matrix, float, float, float, float, float, * String, int[], PDFont, float, int)} insetad */ public TextPosition( int pageRotation, float pageWidthValue, float pageHeightValue, Matrix textPositionSt, float endXValue, float endYValue, float maxFontH, float individualWidth, float spaceWidth, String string, PDFont currentFont, float fontSizeValue, int fontSizeInPt ) { this(pageRotation, pageWidthValue, pageHeightValue, textPositionSt, endXValue, endYValue, maxFontH, individualWidth, spaceWidth, string, null, currentFont, fontSizeValue, fontSizeInPt); } /** * Constructor. * * @param pageRotation rotation of the page that the text is located in * @param pageWidthValue rotation of the page that the text is located in * @param pageHeightValue rotation of the page that the text is located in * @param textPositionSt TextMatrix for start of text (in display units) * @param endXValue x coordinate of the end position * @param endYValue y coordinate of the end position * @param maxFontH Maximum height of text (in display units) * @param individualWidth The width of the given character/string. (in ? units) * @param spaceWidth The width of the space character. (in display units) * @param string The character to be displayed. * @param codePoints An array containing the codepoints of the given string. * @param currentFont The current font for this text position. * @param fontSizeValue The new font size. * @param fontSizeInPt The font size in pt units. */ public TextPosition( int pageRotation, float pageWidthValue, float pageHeightValue, Matrix textPositionSt, float endXValue, float endYValue, float maxFontH, float individualWidth, float spaceWidth, String string, int[] codePoints, PDFont currentFont, float fontSizeValue, int fontSizeInPt ) { this.textPos = textPositionSt; this.endX = endXValue; this.endY = endYValue; // normalize the rotation angle while (pageRotation < 0) { pageRotation += 360; } while (pageRotation >= 360) { pageRotation -= 360; } this.rot = pageRotation; this.maxTextHeight = maxFontH; this.pageHeight = pageHeightValue; this.pageWidth = pageWidthValue; this.widths = new float[]{individualWidth}; this.widthOfSpace = spaceWidth; this.str = string; this.unicodeCP = codePoints; this.font = currentFont; this.fontSize = fontSizeValue; this.fontSizePt = fontSizeInPt; } /** * Return the string of characters stored in this object. * * @return The string on the screen. */ public String getCharacter() { return str; } /** * Return the codepoints of the characters stored in this object. * * @return an array containing all codepoints. */ public int[] getCodePoints() { return unicodeCP; } /** * Return the Matrix textPos stored in this object. * * @return The Matrix containing all infos of the starting textposition */ public Matrix getTextPos() { return textPos; } /** * Return the direction/orientation of the string in this object * based on its text matrix. * @return The direction of the text (0, 90, 180, or 270) */ public float getDir() { float a = textPos.getValue(0,0); float b = textPos.getValue(0,1); float c = textPos.getValue(1,0); float d = textPos.getValue(1,1); // 12 0 left to right // 0 12 if ((a > 0) && (Math.abs(b) < d) && (Math.abs(c) < a) && (d > 0)) { return 0; } // -12 0 right to left (upside down) // 0 -12 else if ((a < 0) && (Math.abs(b) < Math.abs(d)) && (Math.abs(c) < Math.abs(a)) && (d < 0)) { return 180; } // 0 12 up // -12 0 else if ((Math.abs(a) < Math.abs(c)) && (b > 0) && (c < 0) && (Math.abs(d) < b)) { return 90; } // 0 -12 down // 12 0 else if ((Math.abs(a) < c) && (b < 0) && (c > 0) && (Math.abs(d) < Math.abs(b))) { return 270; } return 0; } /** * Return the X starting coordinate of the text, adjusted by * the given rotation amount. The rotation adjusts where the 0,0 * location is relative to the text. * * @param rotation Rotation to apply (0, 90, 180, or 270). 0 will perform no adjustments. * @return X coordinate */ private float getXRot(float rotation) { if (rotation == 0) { return textPos.getValue(2,0); } else if (rotation == 90) { return textPos.getValue(2,1); } else if (rotation == 180) { return pageWidth - textPos.getValue(2,0); } else if (rotation == 270) { return pageHeight - textPos.getValue(2,1); } return 0; } /** * This will get the page rotation adjusted x position of the character. * This is adjusted based on page rotation so that the upper * left is 0,0. * * @return The x coordinate of the character. */ public float getX() { if (x == Float.NEGATIVE_INFINITY) { x = getXRot(rot); } return x; } /** * This will get the text direction adjusted x position of the character. * This is adjusted based on text direction so that the first character * in that direction is in the upper left at 0,0. * * @return The x coordinate of the text. */ public float getXDirAdj() { return getXRot(getDir()); } /** * This will get the y position of the character with 0,0 in lower left. * This will be adjusted by the given rotation. * @param rotation Rotation to apply to text to adjust the 0,0 location (0,90,180,270) * * @return The y coordinate of the text */ private float getYLowerLeftRot(float rotation) { if (rotation == 0) { return textPos.getValue(2,1); } else if (rotation == 90) { return pageWidth - textPos.getValue(2,0); } else if (rotation == 180) { return pageHeight - textPos.getValue(2,1); } else if (rotation == 270) { return textPos.getValue(2,0); } return 0; } /** * This will get the y position of the text, adjusted so that 0,0 is upper left and * it is adjusted based on the page rotation. * * @return The adjusted y coordinate of the character. */ public float getY() { if (y == Float.NEGATIVE_INFINITY) { if ((rot == 0) || (rot == 180)) { y = pageHeight - getYLowerLeftRot(rot); } else { y = pageWidth - getYLowerLeftRot(rot); } } return y; } /** * This will get the y position of the text, adjusted so that 0,0 is upper left and * it is adjusted based on the text direction. * * @return The adjusted y coordinate of the character. */ public float getYDirAdj() { float dir = getDir(); // some PDFBox code assumes that the 0,0 point is in upper left, not lower left if ((dir == 0) || (dir == 180)) { return pageHeight - getYLowerLeftRot(dir); } else { return pageWidth - getYLowerLeftRot(dir); } } /** * Get the length or width of the text, based on a given rotation. * * @param rotation Rotation that was used to determine coordinates (0,90,180,270) * @return Width of text in display units */ private float getWidthRot(float rotation) { if ((rotation == 90) || (rotation == 270)) { return Math.abs(endY - textPos.getYPosition()); } else { return Math.abs(endX - textPos.getXPosition()); } } /** * This will get the width of the string when page rotation adjusted coordinates are used. * * @return The width of the text in display units. */ public float getWidth() { return getWidthRot(rot); } /** * This will get the width of the string when text direction adjusted coordinates are used. * * @return The width of the text in display units. */ public float getWidthDirAdj() { return getWidthRot(getDir()); } /** * This will get the maximum height of all characters in this string. * * @return The maximum height of all characters in this string. */ public float getHeight() { return maxTextHeight; } /** * This will get the maximum height of all characters in this string. * * @return The maximum height of all characters in this string. */ public float getHeightDir() { // this is not really a rotation-dependent calculation, but this is defined for symmetry. return maxTextHeight; } /** * This will get the font size that this object is * suppose to be drawn at. * * @return The font size. */ public float getFontSize() { return fontSize; } /** * This will get the font size in pt. * To get this size we have to multiply the pdf-fontsize and the scaling from the textmatrix * * @return The font size in pt. */ public float getFontSizeInPt() { return fontSizePt; } /** * This will get the font for the text being drawn. * * @return The font size. */ public PDFont getFont() { return font; } /** * This will get the current word spacing. * * @return The current word spacing. */ @Deprecated public float getWordSpacing() { return wordSpacing; } /** * This will get the width of a space character. This is useful for some * algorithms such as the text stripper, that need to know the width of a * space character. * * @return The width of a space character. */ public float getWidthOfSpace() { return widthOfSpace; } /** * @return Returns the xScale. */ public float getXScale() { return textPos.getXScale(); } /** * @return Returns the yScale. */ public float getYScale() { return textPos.getYScale(); } /** * Get the widths of each individual character. * * @return An array that is the same length as the length of the string. */ public float[] getIndividualWidths() { return widths; } /** * Show the string data for this text position. * * @return A human readable form of this object. */ public String toString() { return getCharacter(); } /** * Determine if this TextPosition logically contains * another (i.e. they overlap and should be rendered on top * of each other). * @param tp2 The other TestPosition to compare against * * @return True if tp2 is contained in the bounding box of this text. */ public boolean contains( TextPosition tp2) { double thisXstart = getXDirAdj(); double thisXend = getXDirAdj() + getWidthDirAdj(); double tp2Xstart = tp2.getXDirAdj(); double tp2Xend = tp2.getXDirAdj() + tp2.getWidthDirAdj(); /* * No X overlap at all so return as soon as possible. */ if(tp2Xend <= thisXstart || tp2Xstart >= thisXend) { return false; } /* * No Y overlap at all so return as soon as possible. * Note: 0.0 is in the upper left and y-coordinate is * top of TextPosition */ if((tp2.getYDirAdj() + tp2.getHeightDir() < getYDirAdj()) || (tp2.getYDirAdj() > getYDirAdj() + getHeightDir())) { return false; } /* We're going to calculate the percentage of overlap. If its less * than a 15% x-coordinate overlap then we'll return false because its negligible. * .15 was determined by trial and error in the regression test files. */ else if((tp2Xstart > thisXstart) && (tp2Xend > thisXend)) { double overlap = thisXend - tp2Xstart; double overlapPercent = overlap/getWidthDirAdj(); return (overlapPercent > .15); } else if((tp2Xstart < thisXstart) && (tp2Xend < thisXend)) { double overlap = tp2Xend - thisXstart; double overlapPercent = overlap/getWidthDirAdj(); return (overlapPercent > .15); } return true; } /** * Merge a single character TextPosition into the current object. * This is to be used only for cases where we have a diacritic that * overlaps an existing TextPosition. In a graphical display, we could * overlay them, but for text extraction we need to merge them. Use the * contains() method to test if two objects overlap. * * @param diacritic TextPosition to merge into the current TextPosition. * @param normalize Instance of TextNormalize class to be used to normalize diacritic */ public void mergeDiacritic(TextPosition diacritic, TextNormalize normalize) { if (diacritic.getCharacter().length() > 1) { return; } float diacXStart = diacritic.getXDirAdj(); float diacXEnd = diacXStart + diacritic.widths[0]; float currCharXStart = getXDirAdj(); int strLen = str.length(); boolean wasAdded = false; for (int i = 0; i < strLen && !wasAdded; i++) { if (i >= widths.length) { LOG.info("diacritic " + diacritic.getCharacter() + " on ligature " + getCharacter() + " is not supported yet and is ignored (PDFBOX-2831)"); break; } float currCharXEnd = currCharXStart + widths[i]; /* * This is the case where there is an overlap of the diacritic character with * the current character and the previous character. If no previous character, * just append the diacritic after the current one. */ if(diacXStart < currCharXStart && diacXEnd <= currCharXEnd) { if(i == 0) { insertDiacritic(i, diacritic, normalize); } else { float distanceOverlapping1 = diacXEnd - currCharXStart; float percentage1 = distanceOverlapping1/widths[i]; float distanceOverlapping2 = currCharXStart - diacXStart; float percentage2 = distanceOverlapping2/widths[i-1]; if(percentage1 >= percentage2) { insertDiacritic(i, diacritic, normalize); } else { insertDiacritic(i-1, diacritic, normalize); } } wasAdded = true; } //diacritic completely covers this character and therefore we assume that //this is the character the diacritic belongs to else if(diacXStart < currCharXStart && diacXEnd > currCharXEnd) { insertDiacritic(i, diacritic, normalize); wasAdded = true; } //Otherwise, The diacritic modifies this character because its completely //contained by the character width else if(diacXStart >= currCharXStart && diacXEnd <= currCharXEnd) { insertDiacritic(i, diacritic, normalize); wasAdded = true; } /* * Last character in the TextPosition so we add diacritic to the end */ else if(diacXStart >= currCharXStart && diacXEnd > currCharXEnd && i == (strLen - 1)) { insertDiacritic(i, diacritic, normalize); wasAdded = true; } /* * Couldn't find anything useful so we go to the next character in the * TextPosition */ currCharXStart += widths[i]; } } /** * Inserts the diacritic TextPosition to the str of this TextPosition * and updates the widths array to include the extra character width. * @param i current character * @param diacritic The diacritic TextPosition * @param normalize Instance of TextNormalize class to be used to normalize diacritic */ private void insertDiacritic(int i, TextPosition diacritic, TextNormalize normalize) { /* we add the diacritic to the right or left of the character * depending on the direction of the character. Note that this * is only required because the text is currently stored in * presentation order and not in logical order. */ int dir = Character.getDirectionality(str.charAt(i)); StringBuffer buf = new StringBuffer(); buf.append(str.substring(0,i)); float[] widths2 = new float[widths.length+1]; System.arraycopy(widths, 0, widths2, 0, i); if ((dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT) || (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) || (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING) || (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE)) { buf.append(normalize.normalizeDiac(diacritic.getCharacter())); widths2[i] = 0; buf.append(str.charAt(i)); widths2[i+1] = widths[i]; } else { buf.append(str.charAt(i)); widths2[i] = widths[i]; buf.append(normalize.normalizeDiac(diacritic.getCharacter())); widths2[i+1] = 0; } // Get the rest of the string buf.append(str.substring(i+1, str.length())); System.arraycopy(widths, i+1, widths2, i+2, widths.length-i-1); str = buf.toString(); widths = widths2; } /** * * @return True if the current character is a diacritic char. */ public boolean isDiacritic() { final String cText = this.getCharacter(); if (cText.length() != 1) { return false; } final int type = Character.getType(cText.charAt(0)); return (type == Character.NON_SPACING_MARK || type == Character.MODIFIER_SYMBOL || type == Character.MODIFIER_LETTER); } }pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/TextPositionComparator.java0000644000000000000000000000555712645757432027346 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.util.Comparator; /** * This class is a comparator for TextPosition operators. It handles * pages with text in different directions by grouping the text based * on direction and sorting in that direction. This allows continuous text * in a given direction to be more easily grouped together. * * @author Ben Litchfield * @version $Revision: 1.7 $ */ public class TextPositionComparator implements Comparator { /** * {@inheritDoc} */ public int compare(Object o1, Object o2) { int retval = 0; TextPosition pos1 = (TextPosition)o1; TextPosition pos2 = (TextPosition)o2; /* Only compare text that is in the same direction. */ if (pos1.getDir() < pos2.getDir()) { return -1; } else if (pos1.getDir() > pos2.getDir()) { return 1; } // Get the text direction adjusted coordinates float x1 = pos1.getXDirAdj(); float x2 = pos2.getXDirAdj(); float pos1YBottom = pos1.getYDirAdj(); float pos2YBottom = pos2.getYDirAdj(); // note that the coordinates have been adjusted so 0,0 is in upper left float pos1YTop = pos1YBottom - pos1.getHeightDir(); float pos2YTop = pos2YBottom - pos2.getHeightDir(); float yDifference = Math.abs( pos1YBottom-pos2YBottom); //we will do a simple tolerance comparison. if( yDifference < .1 || (pos2YBottom >= pos1YTop && pos2YBottom <= pos1YBottom) || (pos1YBottom >= pos2YTop && pos1YBottom <= pos2YBottom)) { if( x1 < x2 ) { retval = -1; } else if( x1 > x2 ) { retval = 1; } else { retval = 0; } } else if( pos1YBottom < pos2YBottom ) { retval = -1; } else { return 1; } return retval; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java0000644000000000000000000010434112645757432025401 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.io.IOException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.SimpleTimeZone; import java.util.TimeZone; import org.apache.pdfbox.cos.COSString; /** * Date format is described in PDF Reference 1.7 section 3.8.2 * (www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf) * and also in PDF 32000-1:2008 * (http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf)) * although the latter inexplicably omits the trailing apostrophe. * * The interpretation of dates without timezones is unclear. * The code below assumes that such dates are in UTC+00 (aka GMT). * This is in keeping with the PDF Reference's assertion that: * numerical fields default to zero values. * However, the Reference does go on to make the cryptic remark: * If no UT information is specified, the relationship of the specified * time to UT is considered to be unknown. Whether or not the time * zone is known, the rest of the date should be specified in local time. * I understand this to refer to _creating_ a pdf date value. That is, * code that can get the wall clock time and cannot get the timezone * should write the wall clock time with a time zone of zero. * When _parsing_ a PDF date, the statement talks about "the rest of the date" * being local time, thus explicitly excluding the use of the local time * for the time zone. */ /** * This class is used to convert dates to strings and back using the PDF * date standard in section 3.8.2 of PDF Reference 1.7. * * @author Ben Litchfield * @author Fred Hansen * * TODO Move members of this class elsewhere for shared use in pdfbox, xmpbox, and jempbox. */ public class DateConverter { // milliseconds/1000 = seconds; seconds / 60 = minutes; minutes/60 = hours private static final int MINUTES_PER_HOUR = 60; private static final int SECONDS_PER_MINUTE = 60; private static final int MILLIS_PER_MINUTE = SECONDS_PER_MINUTE*1000; private static final int MILLIS_PER_HOUR = MINUTES_PER_HOUR * MILLIS_PER_MINUTE; private static final int HALF_DAY = 12 * MINUTES_PER_HOUR * MILLIS_PER_MINUTE, DAY = 2*HALF_DAY; /** * Error value if date is invalid. Parsing is done with * GregorianCalendar.setLenient(false), so every date field value * must be within bounds. If an attempt is made to parse an invalid date * field, toCalendar(String, String[]) returns Jan 1 in year INVALID_YEAR. */ public static final int INVALID_YEAR = 999; /** * The Date format is supposed to be the PDF_DATE_FORMAT, but other * forms appear. These lists offer alternatives to be tried * if parseBigEndianDate fails. * * The time zone offset generally trails the date string, so it is processed * separately with parseTZoffset. (This does not preclude having time * zones in the elements below; one does.) * * Alas, SimpleDateFormat is badly non-reentrant -- it modifies its * calendar field (PDFBox-402), so these lists are strings to create * SimpleDate format as needed. * * Some past entries have been elided because they duplicate existing * entries. See the API for SimpleDateFormat, which says * "For parsing, the number of pattern letters is ignored * unless it's needed to separate two adjacent fields." * * toCalendar(String, String[]) tests to see that the entire input text * has been consumed. Therefore the ordering of formats is important. * If one format begins with the entirety of another, the longer * must precede the other in the list. * * HH is for 0-23 hours and hh for 1-12 hours; an "a" field must follow "hh" * Where year is yy, four digit years are accepted * and two digit years are converted to four digits in the range * [thisyear-79...thisyear+20] */ private static final String[] ALPHA_START_FORMATS = { "EEEE, dd MMM yy hh:mm:ss a", "EEEE, MMM dd, yy hh:mm:ss a", "EEEE, MMM dd, yy 'at' hh:mma", // Acrobat Net Distiller 1.0 for Windows "EEEE, MMM dd, yy", // Acrobat Distiller 1.0.2 for Macintosh && PDFBOX-465 "EEEE MMM dd, yy HH:mm:ss", // ECMP5 "EEEE MMM dd HH:mm:ss z yy", // GNU Ghostscript 7.0.7 "EEEE MMM dd HH:mm:ss yy", // GNU Ghostscript 7.0.7 variant }; private static final String[] DIGIT_START_FORMATS = { "dd MMM yy HH:mm:ss", // for 26 May 2000 11:25:00 "dd MMM yy HH:mm", // for 26 May 2000 11:25 "yyyy MMM d", // ambiguity resolved only by omitting time "yyyymmddhh:mm:ss", // test case "200712172:2:3" "H:m M/d/yy", // test case "9:47 5/12/2008" "M/d/yy HH:mm:ss", "M/d/yy HH:mm", "M/d/yy", // proposed rule that is unreachable due to "dd MMM yy HH:mm:ss" // "yyyy MMM d HH:mm:ss", // rules made unreachable by "M/d/yy HH:mm:ss" "M/d/yy HH:mm" "M/d/yy", // (incoming digit strings do not mark themselves as y, m, or d!) // "d/MM/yyyy HH:mm:ss", // PDFBOX-164 and PDFBOX-170 // "M/dd/yyyy hh:mm:ss", // "MM/d/yyyy hh:mm:ss", // "M/d/yyyy HH:mm:ss", // "M/dd/yyyy", // "MM/d/yyyy", // "M/d/yyyy", // "M/d/yyyy HH:mm:ss", // "M/d/yy HH:mm:ss", // subsumed by big-endian parse // "yyyy-MM-dd'T'HH:mm:ss", // "yyyy-MM-dd'T'HH:mm:ss", // "yyyymmdd hh:mm:ss", // "yyyymmdd", // "yyyymmddX''00''", // covers 24 cases // (orignally the above ended with '+00''00'''; // the first apostrophe quoted the plus, // '' mapped to a single ', and the ''' was invalid) }; private DateConverter() { //utility class should not be constructed. } //////////////////////////////////////////// // C o n v e r t t o S t r i n g Methods /** * Get all know formats. * * @return an array containig all known formats */ public static String[] getFormats() { String[] val = new String[ALPHA_START_FORMATS.length+DIGIT_START_FORMATS.length]; System.arraycopy(ALPHA_START_FORMATS, 0, val, 0, ALPHA_START_FORMATS.length); System.arraycopy(DIGIT_START_FORMATS, 0, val,ALPHA_START_FORMATS.length, DIGIT_START_FORMATS.length); return val; } /** * Converts a Calendar to a string formatted as: * D:yyyyMMddHHmmss#hh'mm' where # is Z, +, or -. * * @param cal The date to convert to a string. May be null. * The DST_OFFSET is included when computing the output time zone. * * @return The date as a String to be used in a PDF document, * or null if the cal value is null */ public static String toString(Calendar cal) { if (cal == null) { return null; } String offset = formatTZoffset(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET), "'"); return String.format("D:" + "%1$4tY%1$2tm%1$2td" // yyyyMMdd + "%1$2tH%1$2tM%1$2tS" // HHmmss + "%2$s" // time zone + "'", // trailing apostrophe cal, offset); } /** * Converts the date to ISO 8601 string format: * yyyy-mm-ddThh:MM:ss#hh:mm (where '#" is '+' or '-'). * * @param cal The date to convert. Must not be null. * The DST_OFFSET is included in the output value. * * @return The date represented as an ISO 8601 string. */ public static String toISO8601(Calendar cal) { String offset = formatTZoffset(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET), ":"); return String.format( "%1$4tY" // yyyy + "-%1$2tm" // -mm (%tm adds one to cal month value) + "-%1$2td" // -dd (%tm adds one to cal month value) + "T" // T + "%1$2tH:%1$2tM:%1$2tS" // HHmmss + "%2$s", // time zone cal, offset); } /** * Constrain a timezone offset to the range [-11:59 thru +11:59]. * @param proposedOffset A value intended to be a timezone offset. * @return The corresponding value reduced to the above noted range * by adding or subtracting multiples of a full day. */ public static int restrainTZoffset(long proposedOffset) { proposedOffset = ((proposedOffset+HALF_DAY)%DAY+DAY)%DAY; // 0 <= proposedOffset < DAY proposedOffset = (proposedOffset-HALF_DAY)%HALF_DAY; // -HALF_DAY < proposedOffset < HALF_DAY return (int)proposedOffset; } /** * Formats a time zone offset as #hh^mm * where # is + or -, hh is hours, ^ is a separator, and mm is minutes. * Any separator may be specified by the second argument; * the usual values are ":" (ISO 8601), "" (RFC 822), and "'" (PDF). * The returned value is constrained to the range -11:59 ... 11:59. * For offset of 0 millis, the String returned is "+00^00", never "Z". * To get a "general" offset in form GMT#hh:mm, write * "GMT"+DateConverter.formatTZoffset(offset, ":"); *

* Take thought in choosing the source for the millis value. * It can come from calendarValue.getTimeZone() or from * calendarValue.get(Calendar.ZONE_OFFSET). If a TimeZone was created * from a valid time zone ID, then it may have a daylight savings rule. * (As of July 4, 2013, the data base at http://www.iana.org/time-zones * recognized 629 time zone regions. But a TimeZone created as * new SimpleTimeZone(millisOffset, "ID"), * will not have a daylight savings rule. (Not even if there is a * known time zone with the given ID. To get the TimeZone named "xDT" * with its DST rule, use an ID of EST5EDT, CST6CDT, MST7MDT, or PST8PDT. *

* When parsing PDF dates, the incoming values DOES NOT have a TIMEZONE value. * At most it has an OFFSET value like -04'00'. It is generally impossible to * determine what TIMEZONE corresponds to a given OFFSET. If the date is * in the summer when daylight savings is in effect, an offset of -0400 * might correspond to any one of the 38 regions (of 53) with standard time * offset -0400 and no daylight saving. Or it might correspond to * any one of the 31 regions (out of 43) that observe daylight savings * and have standard time offset of -0500. *

* If a Calendar has not been assigned a TimeZone with setTimeZone(), * it will have by default the local TIMEZONE, not just the OFFSET. In the * USA, this TimeZone will have a daylight savings rule. *

* The offset assigned with calVal.set(Calendar.ZONE_OFFSET) differs * from the offset in the TimeZone set by Calendar.setTimeZone(). Example: * Suppose my local TimeZone is America/New_York. It has an offset of -05'00'. * And suppose I set a GregorianCalendar's ZONE_OFFSET to -07'00' * calVal = new GregorianCalendar(); // TimeZone is the local default * calVal.set(Calendar.ZONE_OFFSET, -7* MILLIS_PER_HOUR); * Four different offsets can be computed from calVal: * calVal.get(Calendar.ZONE_OFFSET) => -07:00 * calVal.get(Calendar.ZONE_OFFSET) + calVal.get(Calendar.DST_OFFSET) => -06:00 * calVal.getTimeZone().getRawOffset() => -05:00 * calVal.getTimeZone().getOffset(calVal.getTimeInMillis()) => -04:00 *

* Which is correct??? I dunno, though setTimeZone() does seem to affect * ZONE_OFFSET, and not vice versa. One cannot even test whether TimeZone * or ZONE_OFFSET has been set; both have been set by initialization code. * TimeZone is initialized to the local default time zone * and ZONE_OFFSET is set from it. * * My choice in this DateConverter class has been to set the * initial TimeZone of a GregorianCalendar to GMT. Thereafter * the TimeZone is modified with {@link #adjustTimeZoneNicely}. * * @param millis a time zone offset expressed in milliseconds * Any value is accepted; it is normalized to [-11:59 ... +11:59] * @param sep a String to insert between hh and mm. May be empty. * @return the formatted String for the offset */ public static String formatTZoffset(long millis, String sep) { SimpleDateFormat sdf = new SimpleDateFormat("Z"); // #hhmm sdf.setTimeZone(new SimpleTimeZone(restrainTZoffset(millis),"unknown")); String tz = sdf.format(new Date()); return tz.substring(0,3)+sep+tz.substring(3); } ////////////////////////////////////////////// // P A R S E Methods /** * Parses an integer from a string, starting at and advancing a ParsePosition. * * @param text The string being parsed. If null, the remedy value is returned. * @param where The ParsePosition to start the search. This value * will be incremented by the number of digits found, but no * more than maxlen. That is, the ParsePosition will * advance across at most maxlen initial digits in text. * The error index is ignored and unchanged. * @param maxlen The maximum length of the integer to parse. * Usually 2, but 4 for year fields. * If the field of length maxlen begins with a digit, * but contains a non-digit, no error is signaled * and the integer value is returned. * @param remedy Value to be assigned if no digit is found at the * initial parse position; that is, if the field is empty. * @return The integer that was at the given parse position. Or * the remedy value if no digits were found. */ public static int parseTimeField(String text, ParsePosition where, int maxlen, int remedy) { if (text == null) { return remedy; } // (it would seem that DecimalFormat.parse() would be simpler; // but that class blithely ignores setMaximumIntegerDigits) int retval = 0; int index = where.getIndex(); int limit = index + Math.min(maxlen, text.length()-index); for (; index < limit; index++) { int cval = text.charAt(index) - '0'; // convert digit to integer if (cval <0 || cval > 9) // test to see if we got a digit { break; // no digit at index } retval = retval*10 + cval; // append the digit to the return value } if (index == where.getIndex()) { return remedy; } where.setIndex(index); return retval; } /** * Advances the ParsePosition past any and all the characters * that match those in the optionals list. * In particular, a space will skip all spaces. * @param text The text to examine * @param where index to start looking. * The value is incremented by the number of optionals found. * The error index is ignored and unchanged. * @param optionals A String listing all the optional characters * to be skipped. * @return The last non-space character passed over. * Returns a space if no non-space character was found * (even if space is not in the optionals list.) */ public static char skipOptionals(String text, ParsePosition where, String optionals) { char retval = ' ', currch; while (text != null && where.getIndex() < text.length() && optionals.indexOf( (currch=text.charAt(where.getIndex())) ) >= 0) { retval = (currch != ' ') ? currch : retval; where.setIndex(where.getIndex() + 1); } return retval; } /** * If the victim string is at the given position in the text, * this method advances the position past that string. * * @param text The text to examine * @param victim The string to look for * @param where The initial position to look at. After return, this will * have been incremented by the length of the victim if it was found. * The error index is ignored and unchanged. * @return true if victim was found; otherwise false. */ public static boolean skipString(String text, String victim, ParsePosition where) { if (text.startsWith(victim, where.getIndex())) { where.setIndex(where.getIndex()+victim.length()); return true; } return false; } /** * Construct a new GregorianCalendar and set defaults. * Locale is ENGLISH. * TimeZone is "UTC" (zero offset and no DST). * Parsing is NOT lenient. Milliseconds are zero. * * @return a new gregorian calendar */ public static GregorianCalendar newGreg() { GregorianCalendar retCal = new GregorianCalendar(Locale.ENGLISH); retCal.setTimeZone(new SimpleTimeZone(0, "UTC")); retCal.setLenient(false); retCal.set(Calendar.MILLISECOND, 0); return retCal; } /** * Install a TimeZone on a GregorianCalendar without changing the * hours value. A plain GregorianCalendat.setTimeZone() * adjusts the Calendar.HOUR value to compensate. This is *BAD* * (not to say *EVIL*) when we have already set the time. * @param cal The GregorianCalendar whose TimeZone to change. * @param tz The new TimeZone. */ public static void adjustTimeZoneNicely(GregorianCalendar cal, TimeZone tz) { cal.setTimeZone(tz); int offset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / MILLIS_PER_MINUTE; cal.add(Calendar.MINUTE, -offset); } /** * Parses the end of a date string for a time zone and, if one is found, * sets the time zone of the GregorianCalendar. Otherwise the calendar * time zone is unchanged. * * The text is parsed as * (Z|GMT|UTC)? [+- ]* h [': ]? m '? * where the leading String is optional, h is two digits by default, * but may be a single digit if followed by one of space, apostrophe, * colon, or the end of string. Similarly, m is one or two digits. * This scheme accepts the format of PDF, RFC 822, and ISO8601. * If none of these applies (as for a time zone name), we try * TimeZone.getTimeZone(). * * @param text The text expected to begin with a time zone value, * possibly with leading or trailing spaces. * @param cal The Calendar whose TimeZone to set. * @param initialWhere where Scanning begins at where.index. After success, the returned * index is that of the next character after the recognized string. * The error index is ignored and unchanged. * @return true if parsed a time zone value; otherwise the * time zone is unchanged and the return value is false. */ public static boolean parseTZoffset(String text, GregorianCalendar cal, ParsePosition initialWhere) { ParsePosition where = new ParsePosition(initialWhere.getIndex()); TimeZone tz = new SimpleTimeZone(0, "GMT"); int tzHours, tzMin; char sign = skipOptionals(text, where, "Z+- "); boolean hadGMT = (sign == 'Z' || skipString(text, "GMT", where) || skipString(text, "UTC", where)); sign = ( ! hadGMT) ? sign : skipOptionals(text, where, "+- "); tzHours = parseTimeField(text, where, 2, -999); skipOptionals(text, where, "\': "); tzMin = parseTimeField(text, where, 2, 0); skipOptionals(text, where, "\' "); if (tzHours != -999) { // we parsed a time zone in default format int hrSign = (sign == '-' ? -1 :+1); tz.setRawOffset(restrainTZoffset(hrSign*(tzHours*MILLIS_PER_HOUR + tzMin*MILLIS_PER_MINUTE))); tz.setID("unknown"); } else if ( ! hadGMT) { // try to process as a name; "GMT" or "UTC" has already been processed String tzText = text.substring(initialWhere.getIndex()).trim(); tz = TimeZone.getTimeZone(tzText); // getTimeZone returns "GMT" for unknown ids if ("GMT".equals(tz.getID())) { // no timezone in text // cal amd initialWhere are unchanged return false; } else { // we got a tz by name; use it where.setIndex(text.length()); } } adjustTimeZoneNicely(cal, tz); initialWhere.setIndex(where.getIndex()); return true; } /** * Parses a big-endian date: year month day hour min sec. * The year must be four digits. Other fields may be adjacent * and delimited by length or they may follow appropriate delimiters. * year [ -/]* month [ -/]* dayofmonth [ T]* hour [:] min [:] sec [.secFraction] * If any numeric field is omitted, all following fields must also be omitted. * No time zone is processed. * * Ambiguous dates can produce unexpected results. For example: * 1970 12 23:08 will parse as 1970 December 23 00:08:00 * * @param text The string to parse. * * @param initialWhere Where to begin the parse. On return the index * is advanced to just beyond the last character processed. * The error index is ignored and unchanged. * * @return a GregorianCalendar representing the parsed date. * Or null if the text did not begin with at least four digits. */ public static GregorianCalendar parseBigEndianDate(String text, ParsePosition initialWhere) { ParsePosition where = new ParsePosition(initialWhere.getIndex()); int year = parseTimeField(text, where, 4, 0); if (where.getIndex() != 4 + initialWhere.getIndex()) { return null; } skipOptionals(text, where, "/- "); int month = parseTimeField(text, where, 2, 1) - 1; // Calendar months are 0...11 skipOptionals(text, where, "/- "); int day = parseTimeField(text, where, 2, 1); skipOptionals(text, where, " T"); int hour = parseTimeField(text, where, 2, 0); skipOptionals(text, where, ": "); int minute = parseTimeField(text, where, 2, 0); skipOptionals(text, where, ": "); int second = parseTimeField(text, where, 2, 0); char nextC = skipOptionals(text, where, "."); if (nextC == '.') { // fractions of a second: skip upto 19 digits parseTimeField(text, where, 19, 0); } GregorianCalendar dest = newGreg(); try { dest.set(year, month, day, hour, minute, second); dest.getTimeInMillis(); // trigger limit tests } catch (IllegalArgumentException ill) { return null; } initialWhere.setIndex(where.getIndex()); skipOptionals(text, initialWhere, " "); return dest; // dest has at least a year value } /** * See if text can be parsed as a date according to any of a list of * formats. The time zone may be included as part of the format, or * omitted in favor of later testing for a trailing time zone. * * @param text The text to be parsed. * * @param fmts A list of formats to be tried. The syntax is that for * {@link java.text.SimpleDateFormat} * * @param initialWhere At start this is the position to begin * examining the text. Upon return it will have been * incremented to refer to the next non-space character after the date. * If no date was found, the value is unchanged. * The error index is ignored and unchanged. * * @return null for failure to find a date, or the GregorianCalendar * for the date that was found. Unless a time zone was * part of the format, the time zone will be GMT+0 */ public static GregorianCalendar parseSimpleDate(String text, String[] fmts, ParsePosition initialWhere) { for(String fmt : fmts) { ParsePosition where = new ParsePosition(initialWhere.getIndex()); SimpleDateFormat sdf = new SimpleDateFormat(fmt, Locale.ENGLISH); GregorianCalendar retCal = newGreg(); sdf.setCalendar(retCal); if (sdf.parse(text, where) != null) { initialWhere.setIndex(where.getIndex()); skipOptionals(text, initialWhere, " "); return retCal; } } return null; } /** * Parses a String to see if it begins with a date, and if so, * returns that date. The date must be strictly correct--no * field may exceed the appropriate limit. * (That is, the Calendar has setLenient(false).) * Skips initial spaces, but does NOT check for "D:" * * The scan first tries parseBigEndianDate and parseTZoffset * and then tries parseSimpleDate with appropriate formats, * again followed by parseTZoffset. If at any stage the entire * text is consumed, that date value is returned immediately. * Otherwise the date that consumes the longest initial part * of the text is returned. * * - PDF format dates are among those recognized by parseBigEndianDate. * - The formats tried are alphaStartFormats or digitStartFormat and * any listed in the value of moreFmts. * * @param text The String that may begin with a date. Must not be null. * Initial spaces and "D:" are skipped over. * @param moreFmts Additional formats to be tried after trying the * built-in formats. * @param initialWhere where Parsing begins at the given position in text. If the * parse succeeds, the index of where is advanced to point * to the first unrecognized character. * The error index is ignored and unchanged. * @return A GregorianCalendar for the date. If no date is found, * returns null. The time zone will be GMT+0 unless parsing * succeeded with a format containing a time zone. (Only one * builtin format contains a time zone.) * */ public static Calendar parseDate(String text, String[] moreFmts, ParsePosition initialWhere) { // place to remember longestr date string int longestLen = -999999; // theorem: this value will never be used // proof: longestLen is only used if longestDate is not null GregorianCalendar longestDate = null; // null says no date found yet int whereLen; // tempcopy of where.getIndex() ParsePosition where = new ParsePosition(initialWhere.getIndex()); // check for null (throws exception) and trim off surrounding spaces skipOptionals(text, where, " "); int startPosition = where.getIndex(); // try big-endian parse GregorianCalendar retCal = parseBigEndianDate(text, where); // check for success and a timezone if (retCal != null && (where.getIndex() == text.length() || parseTZoffset(text, retCal, where))) { // if text is fully consumed, return the date // else remember it and its length whereLen = where.getIndex(); if (whereLen == text.length()) { initialWhere.setIndex(whereLen); return retCal; } longestLen = whereLen; longestDate = retCal; } if (startPosition >= text.length()) { return null; } // try one of the sets of standard formats where.setIndex(startPosition); String [] formats = Character.isDigit(text.charAt(startPosition)) ? DIGIT_START_FORMATS : ALPHA_START_FORMATS; retCal = parseSimpleDate(text, formats, where); // check for success and a timezone if (retCal != null && (where.getIndex() == text.length() || parseTZoffset(text, retCal, where))) { // if text is fully consumed, return the date // else remember it and its length whereLen = where.getIndex(); if (whereLen == text.length()) { initialWhere.setIndex(whereLen); return retCal; } if (whereLen > longestLen) { longestLen = whereLen; longestDate = retCal; } } // try the supplied formats if (moreFmts != null) { where.setIndex(startPosition); retCal = parseSimpleDate(text, moreFmts, where); if (retCal != null && (where.getIndex() == text.length() || parseTZoffset(text, retCal, where))) { whereLen = where.getIndex(); // if text is fully consumed, return the date // else remember it and its length if (whereLen == text.length() || (longestDate != null && whereLen > longestLen)) { initialWhere.setIndex(whereLen); return retCal; } } } if (longestDate != null) { initialWhere.setIndex(longestLen); return longestDate; } return retCal; } /** * Converts a string to a Calendar by parsing the String for a date. * @see #toCalendar(String). * * The returned value will have 0 for DST_OFFSET. * * @param text The COSString representation of a date. * @return The Calendar that the text string represents. * Or null if text was null. * @throws IOException If the date string is not in the correct format. * @deprecated This method throws an IOException for failure. Replace * calls to it with {@link #toCalendar(String, String[])} * and test for failure with * (value == null || value.get(Calendar.YEAR) == INVALID_YEAR) */ public static Calendar toCalendar(COSString text) throws IOException { if (text == null) { return null; } return toCalendar(text.getString()); } /** * Converts a string date to a Calendar date value; equivalent to * {@link #toCalendar(String, String[])} using

null
for the second parameter, * but throws an IOException for failure. * * The returned value will have 0 for DST_OFFSET. * * @param text The string representation of the calendar. * @return The Calendar that this string represents * or null if the incoming text is null. * @throws IOException If the date string is non-null * and not a parseable date. * @deprecated This method throws an IOException for failure. Replace * calls to it with {@link #toCalendar(String, String[])} * using
null
for the second parameter * and test for failure with * (value == null || value.get(Calendar.YEAR) == INVALID_YEAR) */ public static Calendar toCalendar(String text) throws IOException { if (text == null || "".equals(text)) { return null; } Calendar val = toCalendar(text, null); if (val != null && val.get(Calendar.YEAR) == INVALID_YEAR) { throw new IOException("Error converting date: '" + text + "'"); } return val; } /** * Converts a string to a calendar. The entire string must be consumed. * The date must be strictly correct; that is, no field may exceed * the appropriate limit. Uses {@link #parseDate} to do the actual parsing. * * The returned value will have 0 for DST_OFFSET. * * @param text The text to parse. Initial spaces and "D:" are skipped over. * @param moreFmts An Array of formats (as Strings) to try * in addition to the standard list. * @return the Calendar value corresponding to the date text. * If text does not represent a valid date, * the value is January 1 on year INVALID_YEAR at 0:0:0 GMT. * */ public static Calendar toCalendar(String text, String[] moreFmts) { ParsePosition where = new ParsePosition(0); skipOptionals(text, where, " "); skipString(text, "D:", where); Calendar retCal = parseDate(text, moreFmts, where); // PARSE THE TEXT if (retCal == null || where.getIndex() != text.length()) { // the date string is invalid for all formats we tried, retCal = newGreg(); retCal.set(INVALID_YEAR, 0, 1, 0, 0, 0); } return retCal; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/QuickSort.java0000644000000000000000000000663412645757432024566 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.util.Comparator; import java.util.List; import java.util.Stack; /** * see http://de.wikipedia.org/wiki/Quicksort. * * @author Uwe Pachler * @author Manuel Aristaran */ public final class QuickSort { private QuickSort() { } private static final Comparator OBJCOMP = new Comparator() { public int compare(Comparable object1, Comparable object2) { return object1.compareTo(object2); } }; /** * Sorts the given list using the given comparator. * * @param list list to be sorted * @param cmp comparator used to compare the object swithin the list */ public static void sort(List list, Comparator cmp) { int size = list.size(); if (size < 2) { return; } quicksort(list, cmp); } /** * Sorts the given list using compareTo as comparator. * * @param list list to be sorted */ public static void sort(List list) { sort(list, (Comparator) OBJCOMP); } private static void quicksort(List list, Comparator cmp) { Stack stack = new Stack(); stack.push(0); stack.push(list.size()); while (!stack.isEmpty()) { int right = stack.pop(); int left = stack.pop(); if (right - left < 2) { continue; } int p = left + ((right - left) / 2); p = partition(list, cmp, p, left, right); stack.push(p + 1); stack.push(right); stack.push(left); stack.push(p); } } private static int partition(List list, Comparator cmp, int p, int start, int end) { int l = start; int h = end - 2; T piv = list.get(p); swap(list, p, end - 1); while (l < h) { if (cmp.compare(list.get(l), piv) <= 0) { l++; } else if (cmp.compare(piv, list.get(h)) <= 0) { h--; } else { swap(list, l, h); } } int idx = h; if (cmp.compare(list.get(h), piv) < 0) { idx++; } swap(list, end - 1, idx); return idx; } private static void swap(List list, int i, int j) { T tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/Splitter.java0000644000000000000000000002202312645757432024436 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionGoTo; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Split a document into several other documents. * * @author Mario Ivankovits (mario@ops.co.at) * @author Ben Litchfield * @version $Revision: 1.7 $ */ public class Splitter { /** * The source PDF document. */ protected PDDocument pdfDocument; /** * The current PDF document that contains the splitted page. */ protected PDDocument currentDocument = null; private int splitAtPage = 1; private int startPage = Integer.MIN_VALUE; private int endPage = Integer.MAX_VALUE; private List newDocuments = null; /** * The current page number that we are processing, zero based. */ protected int pageNumber = 0; /** * This will take a document and split into several other documents. * * @param document The document to split. * * @return A list of all the split documents. * * @throws IOException If there is an IOError */ public List split( PDDocument document ) throws IOException { newDocuments = new ArrayList(); pdfDocument = document; List pages = pdfDocument.getDocumentCatalog().getAllPages(); processPages(pages); return newDocuments; } /** * This will tell the splitting algorithm where to split the pages. The default * is 1, so every page will become a new document. If it was to then each document would * contain 2 pages. So it the source document had 5 pages it would split into * 3 new documents, 2 documents containing 2 pages and 1 document containing one * page. * * @param split The number of pages each split document should contain. */ public void setSplitAtPage( int split ) { if( split <= 0 ) { throw new RuntimeException( "Error split must be at least one page." ); } splitAtPage = split; } /** * This will return how many pages each split document will contain. * * @return The split parameter. */ public int getSplitAtPage() { return splitAtPage; } /** * This will set the start page. * * @param start the start page */ public void setStartPage( int start ) { if( start <= 0 ) { throw new RuntimeException( "Error split must be at least one page." ); } startPage = start; } /** * This will return the start page. * * @return The start page. */ public int getStartPage() { return startPage; } /** * This will set the end page. * * @param end the end page */ public void setEndPage( int end ) { if( end <= 0 ) { throw new RuntimeException( "Error split must be at least one page." ); } endPage = end; } /** * This will return the end page. * * @return The end page. */ public int getEndPage() { return endPage; } /** * Interface method to handle the start of the page processing. * * @param pages The list of pages from the source document. * * @throws IOException If an IO error occurs. */ protected void processPages(List pages) throws IOException { Iterator iter = pages.iterator(); while( iter.hasNext() ) { PDPage page = (PDPage)iter.next(); if (pageNumber+1 >= startPage && pageNumber+1 <= endPage) { processNextPage( page ); } else { if (pageNumber > endPage) { break; } else { pageNumber++; } } } } /** * Interface method, you can control where a document gets split by implementing * this method. By default a split occurs at every page. If you wanted to split * based on some complex logic then you could override this method. For example. * * protected void createNewDocumentIfNecessary() * { * if( isPrime( pageNumber ) ) * { * super.createNewDocumentIfNecessary(); * } * } * * * @throws IOException If there is an error creating the new document. */ protected void createNewDocumentIfNecessary() throws IOException { if (isNewDocNecessary()) { createNewDocument(); } } /** * Check if it is necessary to create a new document. * * @return true If a new document should be created. */ protected boolean isNewDocNecessary() { return pageNumber % splitAtPage == 0 || currentDocument == null; } /** * Create a new document to write the splitted contents to. * * @throws IOException If there is an problem creating the new document. */ protected void createNewDocument() throws IOException { currentDocument = new PDDocument(); currentDocument.setDocumentInformation(pdfDocument.getDocumentInformation()); PDDocumentCatalog catalog = pdfDocument.getDocumentCatalog(); PDDocumentCatalog currentCatalog = currentDocument.getDocumentCatalog(); currentCatalog.setViewerPreferences(catalog.getViewerPreferences()); // copy global resources to the new pdf document currentCatalog.getPages().setResources(catalog.getPages().getResources()); newDocuments.add(currentDocument); } /** * Interface to start processing a new page. * * @param page The page that is about to get processed. * * @throws IOException If there is an error creating the new document. */ protected void processNextPage( PDPage page ) throws IOException { createNewDocumentIfNecessary(); PDPage imported = currentDocument.importPage( page ); imported.setCropBox( page.findCropBox() ); imported.setMediaBox( page.findMediaBox() ); // only the resources of the page will be copied imported.setResources( page.getResources() ); imported.setRotation( page.findRotation() ); // remove page links to avoid copying not needed resources processAnnotations(imported); pageNumber++; } private void processAnnotations(PDPage imported) throws IOException { List annotations = imported.getAnnotations(); for (PDAnnotation annotation : annotations) { if (annotation instanceof PDAnnotationLink) { PDAnnotationLink link = (PDAnnotationLink)annotation; PDDestination destination = link.getDestination(); if (destination == null && link.getAction() != null) { PDAction action = link.getAction(); if (action instanceof PDActionGoTo) { destination = ((PDActionGoTo)action).getDestination(); } } if (destination instanceof PDPageDestination) { // TODO preserve links to pages within the splitted result ((PDPageDestination) destination).setPage(null); } } // TODO preserve links to pages within the splitted result annotation.setPage(null); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java0000644000000000000000000003120612645757432024077 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.awt.geom.AffineTransform; /** * This class will be used for matrix manipulation. * * @author Ben Litchfield * @version $Revision: 1.14 $ */ public class Matrix implements Cloneable { static final float[] DEFAULT_SINGLE = { 1,0,0, 0,1,0, 0,0,1 }; private float[] single; /** * Constructor. */ public Matrix() { single = new float[DEFAULT_SINGLE.length]; reset(); } /** * This method resets the numbers in this Matrix to the original values, which are * the values that a newly constructed Matrix would have. */ public void reset() { System.arraycopy(DEFAULT_SINGLE, 0, single, 0, DEFAULT_SINGLE.length); } /** * Create an affine transform from this matrix's values. * * @return An affine transform with this matrix's values. */ public AffineTransform createAffineTransform() { AffineTransform retval = new AffineTransform( single[0], single[1], single[3], single[4], single[6], single[7] ); return retval; } /** * Set the values of the matrix from the AffineTransform. * * @param af The transform to get the values from. */ public void setFromAffineTransform( AffineTransform af ) { single[0] = (float)af.getScaleX(); single[1] = (float)af.getShearY(); single[3] = (float)af.getShearX(); single[4] = (float)af.getScaleY(); single[6] = (float)af.getTranslateX(); single[7] = (float)af.getTranslateY(); } /** * This will get a matrix value at some point. * * @param row The row to get the value from. * @param column The column to get the value from. * * @return The value at the row/column position. */ public float getValue( int row, int column ) { return single[row*3+column]; } /** * This will set a value at a position. * * @param row The row to set the value at. * @param column the column to set the value at. * @param value The value to set at the position. */ public void setValue( int row, int column, float value ) { single[row*3+column] = value; } /** * Return a single dimension array of all values in the matrix. * * @return The values ot this matrix. */ public float[][] getValues() { float[][] retval = new float[3][3]; retval[0][0] = single[0]; retval[0][1] = single[1]; retval[0][2] = single[2]; retval[1][0] = single[3]; retval[1][1] = single[4]; retval[1][2] = single[5]; retval[2][0] = single[6]; retval[2][1] = single[7]; retval[2][2] = single[8]; return retval; } /** * Return a single dimension array of all values in the matrix. * * @return The values ot this matrix. */ public double[][] getValuesAsDouble() { double[][] retval = new double[3][3]; retval[0][0] = single[0]; retval[0][1] = single[1]; retval[0][2] = single[2]; retval[1][0] = single[3]; retval[1][1] = single[4]; retval[1][2] = single[5]; retval[2][0] = single[6]; retval[2][1] = single[7]; retval[2][2] = single[8]; return retval; } /** * This will take the current matrix and multipy it with a matrix that is passed in. * * @param b The matrix to multiply by. * * @return The result of the two multiplied matrices. */ public Matrix multiply( Matrix b ) { return this.multiply(b, new Matrix()); } /** * This method multiplies this Matrix with the specified other Matrix, storing the product in the specified * result Matrix. By reusing Matrix instances like this, multiplication chains can be executed without having * to create many temporary Matrix objects. *

* It is allowed to have (other == this) or (result == this) or indeed (other == result) but if this is done, * the backing float[] matrix values may be copied in order to ensure a correct product. * * @param other the second operand Matrix in the multiplication * @param result the Matrix instance into which the result should be stored. If result is null, a new Matrix * instance is created. * @return the product of the two matrices. */ public Matrix multiply( Matrix other, Matrix result ) { if (result == null) { result = new Matrix(); } if (other != null && other.single != null) { // the operands float[] thisOperand = this.single; float[] otherOperand = other.single; // We're multiplying 2 sets of floats together to produce a third, but we allow // any of these float[] instances to be the same objects. // There is the possibility then to overwrite one of the operands with result values // and therefore corrupt the result. // If either of these operands are the same float[] instance as the result, then // they need to be copied. if (this == result) { final float[] thisOrigVals = new float[this.single.length]; System.arraycopy(this.single, 0, thisOrigVals, 0, this.single.length); thisOperand = thisOrigVals; } if (other == result) { final float[] otherOrigVals = new float[other.single.length]; System.arraycopy(other.single, 0, otherOrigVals, 0, other.single.length); otherOperand = otherOrigVals; } result.single[0] = thisOperand[0] * otherOperand[0] + thisOperand[1] * otherOperand[3] + thisOperand[2] * otherOperand[6]; result.single[1] = thisOperand[0] * otherOperand[1] + thisOperand[1] * otherOperand[4] + thisOperand[2] * otherOperand[7]; result.single[2] = thisOperand[0] * otherOperand[2] + thisOperand[1] * otherOperand[5] + thisOperand[2] * otherOperand[8]; result.single[3] = thisOperand[3] * otherOperand[0] + thisOperand[4] * otherOperand[3] + thisOperand[5] * otherOperand[6]; result.single[4] = thisOperand[3] * otherOperand[1] + thisOperand[4] * otherOperand[4] + thisOperand[5] * otherOperand[7]; result.single[5] = thisOperand[3] * otherOperand[2] + thisOperand[4] * otherOperand[5] + thisOperand[5] * otherOperand[8]; result.single[6] = thisOperand[6] * otherOperand[0] + thisOperand[7] * otherOperand[3] + thisOperand[8] * otherOperand[6]; result.single[7] = thisOperand[6] * otherOperand[1] + thisOperand[7] * otherOperand[4] + thisOperand[8] * otherOperand[7]; result.single[8] = thisOperand[6] * otherOperand[2] + thisOperand[7] * otherOperand[5] + thisOperand[8] * otherOperand[8]; } return result; } /** * Create a new matrix with just the scaling operators. * * @return A new matrix with just the scaling operators. */ public Matrix extractScaling() { Matrix retval = new Matrix(); retval.single[0] = this.single[0]; retval.single[4] = this.single[4]; return retval; } /** * Convenience method to create a scaled instance. * * @param x The xscale operator. * @param y The yscale operator. * @return A new matrix with just the x/y scaling */ public static Matrix getScaleInstance( float x, float y) { Matrix retval = new Matrix(); retval.single[0] = x; retval.single[4] = y; return retval; } /** * Create a new matrix with just the translating operators. * * @return A new matrix with just the translating operators. */ public Matrix extractTranslating() { Matrix retval = new Matrix(); retval.single[6] = this.single[6]; retval.single[7] = this.single[7]; return retval; } /** * Convenience method to create a translating instance. * * @param x The x translating operator. * @param y The y translating operator. * @return A new matrix with just the x/y translating. */ public static Matrix getTranslatingInstance( float x, float y) { Matrix retval = new Matrix(); retval.single[6] = x; retval.single[7] = y; return retval; } /** * Clones this object. * @return cloned matrix as an object. */ public Object clone() { Matrix clone = new Matrix(); System.arraycopy( single, 0, clone.single, 0, 9 ); return clone; } /** * This will copy the text matrix data. * * @return a matrix that matches this one. */ public Matrix copy() { return (Matrix) clone(); } /** * This will return a string representation of the matrix. * * @return The matrix as a string. */ public String toString() { StringBuffer result = new StringBuffer( "" ); result.append( "[[" ); result.append( single[0] + "," ); result.append( single[1] + "," ); result.append( single[2] + "]["); result.append( single[3] + "," ); result.append( single[4] + "," ); result.append( single[5] + "]["); result.append( single[6] + "," ); result.append( single[7] + "," ); result.append( single[8] + "]]"); return result.toString(); } /** * Get the xscaling factor of this matrix. * @return The x-scale. */ public float getXScale() { float xScale = single[0]; /** * BM: if the trm is rotated, the calculation is a little more complicated * * The rotation matrix multiplied with the scaling matrix is: * ( x 0 0) ( cos sin 0) ( x*cos x*sin 0) * ( 0 y 0) * (-sin cos 0) = (-y*sin y*cos 0) * ( 0 0 1) ( 0 0 1) ( 0 0 1) * * So, if you want to deduce x from the matrix you take * M(0,0) = x*cos and M(0,1) = x*sin and use the theorem of Pythagoras * * sqrt(M(0,0)^2+M(0,1)^2) = * sqrt(x2*cos2+x2*sin2) = * sqrt(x2*(cos2+sin2)) = <- here is the trick cos2+sin2 is one * sqrt(x2) = * abs(x) */ if( !(single[1]==0.0f && single[3]==0.0f) ) { xScale = (float)Math.sqrt(Math.pow(single[0], 2)+ Math.pow(single[1], 2)); } return xScale; } /** * Get the y scaling factor of this matrix. * @return The y-scale factor. */ public float getYScale() { float yScale = single[4]; if( !(single[1]==0.0f && single[3]==0.0f) ) { yScale = (float)Math.sqrt(Math.pow(single[3], 2)+ Math.pow(single[4], 2)); } return yScale; } /** * Get the x position in the matrix. * @return The x-position. */ public float getXPosition() { return single[6]; } /** * Get the y position. * @return The y position. */ public float getYPosition() { return single[7]; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/PDFOperator.java0000644000000000000000000001030112645757432024751 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.util.concurrent.ConcurrentHashMap; /** * This class represents an Operator in the content stream. * * @author Ben Litchfield * @version $Revision: 1.14 $ */ public class PDFOperator { private String theOperator; private byte[] imageData; private ImageParameters imageParameters; /** map for singleton operator objects; use {@link ConcurrentHashMap} for better scalability with multiple threads */ private final static ConcurrentHashMap operators = new ConcurrentHashMap(); /** * Constructor. * * @param aOperator The operator that this object will represent. */ private PDFOperator( String aOperator ) { theOperator = aOperator; if( aOperator.startsWith( "/" ) ) { throw new RuntimeException( "Operators are not allowed to start with / '" + aOperator + "'" ); } } /** * This is used to create/cache operators in the system. * * @param operator The operator for the system. * * @return The operator that matches the operator keyword. */ public static PDFOperator getOperator( String operator ) { PDFOperator operation = null; if( operator.equals( "ID" ) || operator.equals( "BI" ) ) { //we can't cache the ID operators. operation = new PDFOperator( operator ); } else { operation = operators.get( operator ); if( operation == null ) { // another thread may has already added an operator of this kind // make sure that we get the same operator operation = operators.putIfAbsent( operator, new PDFOperator( operator ) ); if ( operation == null ) { operation = operators.get( operator ); } } } return operation; } /** * This will get the operation that this operator represents. * * @return The string representation of the operation. */ public String getOperation() { return theOperator; } /** * This will print a string rep of this class. * * @return A string rep of this class. */ public String toString() { return "PDFOperator{" + theOperator + "}"; } /** * This is the special case for the ID operator where there are just random * bytes inlined the stream. * * @return Value of property imageData. */ public byte[] getImageData() { return this.imageData; } /** * This will set the image data, this is only used for the ID operator. * * @param imageDataArray New value of property imageData. */ public void setImageData(byte[] imageDataArray) { imageData = imageDataArray; } /** * This will get the image parameters, this is only valid for BI operators. * * @return The image parameters. */ public ImageParameters getImageParameters() { return imageParameters; } /** * This will set the image parameters, this is only valid for BI operators. * * @param params The image parameters. */ public void setImageParameters( ImageParameters params) { imageParameters = params; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/util/MapUtil.java0000644000000000000000000000315412645757432024207 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.util; import java.util.Map; /** * This class with handle some simple Map operations. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class MapUtil { private MapUtil() { //utility class } /** * Generate a unique key for the map based on a prefix. * * @param map The map to look for existing keys. * @param prefix The prefix to use when generating the key. * @return The new unique key that does not currently exist in the map. */ public static final String getNextUniqueKey( Map map, String prefix ) { int counter = 0; while( map != null && map.get( prefix+counter ) != null ) { counter++; } return prefix+counter; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/0000755000000000000000000000000012645757432022435 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDJavascriptNameTreeNode.java0000644000000000000000000000453512645757432030070 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel; import java.io.IOException; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; import org.apache.pdfbox.pdmodel.common.PDTextStream; import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionJavaScript; /** * This class holds all of the name trees that are available at the document level. * * @author Ben Litchfield * @version $Revision: 1.1 $ */ public class PDJavascriptNameTreeNode extends PDNameTreeNode { /** * Constructor. */ public PDJavascriptNameTreeNode() { super( PDTextStream.class ); } /** * Constructor. * * @param dic The COS dictionary. */ public PDJavascriptNameTreeNode( COSDictionary dic ) { super( dic, PDTextStream.class ); } /** * {@inheritDoc} */ protected COSObjectable convertCOSToPD( COSBase base ) throws IOException { if (!(base instanceof COSDictionary)) { throw new IOException( "Error creating Javascript object, expected a COSDictionary and not " + base); } return (PDActionJavaScript)PDActionFactory.createAction((COSDictionary) base); } /** * {@inheritDoc} */ protected PDNameTreeNode createChildNode( COSDictionary dic ) { return new PDJavascriptNameTreeNode(dic); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageNode.java0000644000000000000000000003256712645757432025223 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; /** * This represents a page node in a pdf document. * * @author Ben Litchfield * @version $Revision: 1.8 $ */ public class PDPageNode implements COSObjectable { private COSDictionary page; /** * Log instance. */ private static final Log log = LogFactory.getLog(PDPageNode.class); /** * Creates a new instance of PDPage. */ public PDPageNode() { page = new COSDictionary(); page.setItem( COSName.TYPE, COSName.PAGES ); page.setItem( COSName.KIDS, new COSArray() ); page.setItem( COSName.COUNT, COSInteger.ZERO ); } /** * Creates a new instance of PDPage. * * @param pages The dictionary pages. */ public PDPageNode( COSDictionary pages ) { page = pages; } /** * This will update the count attribute of the page node. This only needs to * be called if you add or remove pages. The PDDocument will call this for you * when you use the PDDocumnet persistence methods. So, basically most clients * will never need to call this. * * @return The update count for this node. */ public long updateCount() { long totalCount = 0; List kids = getKids(); Iterator kidIter = kids.iterator(); while( kidIter.hasNext() ) { Object next = kidIter.next(); if( next instanceof PDPage ) { totalCount++; } else { PDPageNode node = (PDPageNode)next; totalCount += node.updateCount(); } } page.setLong( COSName.COUNT, totalCount ); return totalCount; } /** * This will get the count of descendent page objects. * * @return The total number of descendent page objects. */ public long getCount() { if(page == null) { return 0L; } COSBase num = page.getDictionaryObject(COSName.COUNT); if(num == null) { return 0L; } return ((COSNumber) num).intValue(); } /** * This will get the underlying dictionary that this class acts on. * * @return The underlying dictionary for this class. */ public COSDictionary getDictionary() { return page; } /** * This is the parent page node. * * @return The parent to this page. */ public PDPageNode getParent() { PDPageNode parent = null; COSDictionary parentDic = (COSDictionary)page.getDictionaryObject(COSName.PARENT, COSName.P); if( parentDic != null ) { parent = new PDPageNode( parentDic ); } return parent; } /** * This will set the parent of this page. * * @param parent The parent to this page node. */ public void setParent( PDPageNode parent ) { page.setItem( COSName.PARENT, parent.getDictionary() ); } /** * {@inheritDoc} */ public COSBase getCOSObject() { return page; } /** * This will return all kids of this node, either PDPageNode or PDPage. * * @return All direct descendents of this node. */ public List getKids() { List actuals = new ArrayList(); COSArray kids = getAllKids(actuals, page, false); return new COSArrayList( actuals, kids ); } /** * This will return all kids of this node as PDPage. * * @param result All direct and indirect descendents of this node are added to this list. */ public void getAllKids(List result) { getAllKids(result, page, true); } /** * This will return all kids of the given page node as PDPage. * * @param result All direct and optionally indirect descendents of this node are added to this list. * @param page Page dictionary of a page node. * @param recurse if true indirect descendents are processed recursively */ private static COSArray getAllKids(List result, COSDictionary page, boolean recurse) { if(page == null) return null; COSArray kids = (COSArray)page.getDictionaryObject( COSName.KIDS ); if ( kids == null) { log.error("No Kids found in getAllKids(). Probably a malformed pdf."); return null; } HashSet seen = new HashSet(); for( int i=0; iBen Litchfield * @version $Revision: 1.3 $ */ public class PDEmbeddedFilesNameTreeNode extends PDNameTreeNode { /** * Constructor. */ public PDEmbeddedFilesNameTreeNode() { super( PDComplexFileSpecification.class ); } /** * Constructor. * * @param dic The COS dictionary. */ public PDEmbeddedFilesNameTreeNode( COSDictionary dic ) { super( dic, PDComplexFileSpecification.class ); } /** * {@inheritDoc} */ protected COSObjectable convertCOSToPD( COSBase base ) throws IOException { return new PDComplexFileSpecification( (COSDictionary)base ); } /** * {@inheritDoc} */ protected PDNameTreeNode createChildNode( COSDictionary dic ) { return new PDEmbeddedFilesNameTreeNode(dic); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ConformingPDDocument.java0000644000000000000000000000747312645757432027337 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.pdfparser.ConformingPDFParser; import org.apache.pdfbox.persistence.util.COSObjectKey; /** * * @author adam */ public class ConformingPDDocument extends PDDocument { /** * Maps ObjectKeys to a COSObject. Note that references to these objects * are also stored in COSDictionary objects that map a name to a specific object. */ private final Map objectPool = new HashMap(); private ConformingPDFParser parser = null; public ConformingPDDocument() throws IOException { super(); } public ConformingPDDocument(COSDocument doc) throws IOException { super(doc); } /** * This will load a document from an input stream. * @param input The File which contains the document. * @return The document that was loaded. * @throws IOException If there is an error reading from the stream. */ public static PDDocument load(File input) throws IOException { ConformingPDFParser parser = new ConformingPDFParser(input); parser.parse(); return parser.getPDDocument(); } /** * This will get an object from the pool. * @param key The object key. * @return The object in the pool or a new one if it has not been parsed yet. * @throws IOException If there is an error getting the proxy object. */ public COSBase getObjectFromPool(COSObjectKey key) throws IOException { return objectPool.get(key); } /** * This will get list of object keys from the pool. * @return The list of object keys in the pool. * @throws IOException If there is an error getting keys. */ public List getObjectKeysFromPool() throws IOException { List keys = new ArrayList(); for(COSObjectKey key : objectPool.keySet()) keys.add(key); return keys; } /** * This will get an object from the pool. * @param number the object number * @param generation the generation of this object you wish to load * @return The object in the pool * @throws IOException If there is an error getting the proxy object. */ public COSBase getObjectFromPool(long number, long generation) throws IOException { return objectPool.get(new COSObjectKey(number, generation)); } public void putObjectInPool(COSBase object, long number, long generation) { objectPool.put(new COSObjectKey(number, generation), object); } /** * @return the parser */ public ConformingPDFParser getParser() { return parser; } /** * @param parser the parser to set */ public void setParser(ConformingPDFParser parser) { this.parser = parser; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/0000755000000000000000000000000012645757432023403 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0Font.java0000644000000000000000000000550412645757432027475 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.io.IOException; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This is implementation of the CIDFontType0 Font. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class PDCIDFontType0Font extends PDCIDFont { /** * Constructor. */ public PDCIDFontType0Font() { super(); font.setItem( COSName.SUBTYPE, COSName.CID_FONT_TYPE0 ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDCIDFontType0Font( COSDictionary fontDictionary ) { super( fontDictionary ); } /** * Returns the AWT font that corresponds with this CIDFontType0 font. * By default we try to look up a system font with the same name. If that * fails and the font file is embedded in the PDF document, we try to * generate the AWT font using the {@link PDType1CFont} class. Ideally * the embedded font would be used always if available, but since the * code doesn't work correctly for all fonts yet we opt to use the * system font by default. * * @return AWT font, or null if not available */ public Font getawtFont() throws IOException { PDFontDescriptor fd = getFontDescriptor(); Font awtFont = null; if (fd.getFontName() != null) { awtFont = FontManager.getAwtFont(fd.getFontName()); } if (awtFont == null && fd instanceof PDFontDescriptorDictionary) { PDFontDescriptorDictionary fdd = (PDFontDescriptorDictionary) fd; if (fdd.getFontFile3() != null) { // Create a font with the embedded data // TODO: This still doesn't work right for // some embedded fonts awtFont = new PDType1CFont(font).getawtFont(); } } return awtFont; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java0000644000000000000000000004724412645757432026336 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.awt.FontFormatException; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.afm.FontMetric; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.encoding.AFMEncoding; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.encoding.EncodingManager; import org.apache.pdfbox.encoding.Type1Encoding; import org.apache.pdfbox.encoding.WinAnsiEncoding; import org.apache.pdfbox.pdmodel.common.PDMatrix; import org.apache.pdfbox.pdmodel.common.PDStream; /** * This is implementation of the Type1 Font. * * @author Ben Litchfield * @version $Revision: 1.11 $ */ public class PDType1Font extends PDSimpleFont { /** * Log instance. */ private static final Log log = LogFactory.getLog(PDType1Font.class); private PDType1CFont type1CFont = null; /** * Standard Base 14 Font. */ public static final PDType1Font TIMES_ROMAN = new PDType1Font( "Times-Roman" ); /** * Standard Base 14 Font. */ public static final PDType1Font TIMES_BOLD = new PDType1Font( "Times-Bold" ); /** * Standard Base 14 Font. */ public static final PDType1Font TIMES_ITALIC = new PDType1Font( "Times-Italic" ); /** * Standard Base 14 Font. */ public static final PDType1Font TIMES_BOLD_ITALIC = new PDType1Font( "Times-BoldItalic" ); /** * Standard Base 14 Font. */ public static final PDType1Font HELVETICA = new PDType1Font( "Helvetica" ); /** * Standard Base 14 Font. */ public static final PDType1Font HELVETICA_BOLD = new PDType1Font( "Helvetica-Bold" ); /** * Standard Base 14 Font. */ public static final PDType1Font HELVETICA_OBLIQUE = new PDType1Font( "Helvetica-Oblique" ); /** * Standard Base 14 Font. */ public static final PDType1Font HELVETICA_BOLD_OBLIQUE = new PDType1Font( "Helvetica-BoldOblique" ); /** * Standard Base 14 Font. */ public static final PDType1Font COURIER = new PDType1Font( "Courier" ); /** * Standard Base 14 Font. */ public static final PDType1Font COURIER_BOLD = new PDType1Font( "Courier-Bold" ); /** * Standard Base 14 Font. */ public static final PDType1Font COURIER_OBLIQUE = new PDType1Font( "Courier-Oblique" ); /** * Standard Base 14 Font. */ public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font( "Courier-BoldOblique" ); /** * Standard Base 14 Font. */ public static final PDType1Font SYMBOL = new PDType1Font( "Symbol" ); /** * Standard Base 14 Font. */ public static final PDType1Font ZAPF_DINGBATS = new PDType1Font( "ZapfDingbats" ); private static final Map STANDARD_14 = new HashMap(); static { STANDARD_14.put( TIMES_ROMAN.getBaseFont(), TIMES_ROMAN ); STANDARD_14.put( TIMES_BOLD.getBaseFont(), TIMES_BOLD ); STANDARD_14.put( TIMES_ITALIC.getBaseFont(), TIMES_ITALIC ); STANDARD_14.put( TIMES_BOLD_ITALIC.getBaseFont(), TIMES_BOLD_ITALIC ); STANDARD_14.put( HELVETICA.getBaseFont(), HELVETICA ); STANDARD_14.put( HELVETICA_BOLD.getBaseFont(), HELVETICA_BOLD ); STANDARD_14.put( HELVETICA_OBLIQUE.getBaseFont(), HELVETICA_OBLIQUE ); STANDARD_14.put( HELVETICA_BOLD_OBLIQUE.getBaseFont(), HELVETICA_BOLD_OBLIQUE ); STANDARD_14.put( COURIER.getBaseFont(), COURIER ); STANDARD_14.put( COURIER_BOLD.getBaseFont(), COURIER_BOLD ); STANDARD_14.put( COURIER_OBLIQUE.getBaseFont(), COURIER_OBLIQUE ); STANDARD_14.put( COURIER_BOLD_OBLIQUE.getBaseFont(), COURIER_BOLD_OBLIQUE ); STANDARD_14.put( SYMBOL.getBaseFont(), SYMBOL ); STANDARD_14.put( ZAPF_DINGBATS.getBaseFont(), ZAPF_DINGBATS ); } private Font awtFont = null; /** * Constructor. */ public PDType1Font() { super(); font.setItem( COSName.SUBTYPE, COSName.TYPE1 ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDType1Font( COSDictionary fontDictionary ) { super( fontDictionary ); PDFontDescriptor fd = getFontDescriptor(); if (fd != null && fd instanceof PDFontDescriptorDictionary) { // a Type1 font may contain a Type1C font PDStream fontFile3 = ((PDFontDescriptorDictionary)fd).getFontFile3(); if (fontFile3 != null) { try { type1CFont = new PDType1CFont( super.font ); } catch (IOException exception) { log.info("Can't read the embedded type1C font " + fd.getFontName() ); } } } } /** * Constructor. * * @param baseFont The base font for this font. */ public PDType1Font( String baseFont ) { this(); setBaseFont( baseFont ); setFontEncoding(new WinAnsiEncoding()); setEncoding(COSName.WIN_ANSI_ENCODING); } /** * A convenience method to get one of the standard 14 font from name. * * @param name The name of the font to get. * * @return The font that matches the name or null if it does not exist. */ public static PDType1Font getStandardFont( String name ) { return (PDType1Font)STANDARD_14.get( name ); } /** * This will get the names of the standard 14 fonts. * * @return An array of the names of the standard 14 fonts. */ public static String[] getStandard14Names() { return (String[])STANDARD_14.keySet().toArray( new String[14] ); } /** * {@inheritDoc} */ public Font getawtFont() throws IOException { if( awtFont == null ) { if (type1CFont != null) { awtFont = type1CFont.getawtFont(); } else { String baseFont = getBaseFont(); PDFontDescriptor fd = getFontDescriptor(); if (fd != null && fd instanceof PDFontDescriptorDictionary) { PDFontDescriptorDictionary fdDictionary = (PDFontDescriptorDictionary)fd; if( fdDictionary.getFontFile() != null ) { try { // create a type1 font with the embedded data awtFont = Font.createFont( Font.TYPE1_FONT, fdDictionary.getFontFile().createInputStream() ); } catch (FontFormatException e) { log.info("Can't read the embedded type1 font " + fd.getFontName() ); } } if (awtFont == null) { // check if the font is part of our environment if (fd.getFontName() != null) { awtFont = FontManager.getAwtFont(fd.getFontName()); } if (awtFont == null) { log.info("Can't find the specified font " + fd.getFontName() ); } } } else { // check if the font is part of our environment awtFont = FontManager.getAwtFont(baseFont); if (awtFont == null) { log.info("Can't find the specified basefont " + baseFont ); } } } if (awtFont == null) { // we can't find anything, so we have to use the standard font awtFont = FontManager.getStandardFont(); log.info("Using font "+awtFont.getName()+ " instead"); } } return awtFont; } protected void determineEncoding() { super.determineEncoding(); Encoding fontEncoding = getFontEncoding(); if(fontEncoding == null) { FontMetric metric = getAFM(); if (metric != null) { fontEncoding = new AFMEncoding( metric ); } setFontEncoding(fontEncoding); } getEncodingFromFont(getFontEncoding() == null); } /** * Tries to get the encoding for the type1 font. * */ private void getEncodingFromFont(boolean extractEncoding) { // This whole section of code needs to be replaced with an actual type1 font parser!! // Get the font program from the embedded type font. PDFontDescriptor fontDescriptor = getFontDescriptor(); if( fontDescriptor != null && fontDescriptor instanceof PDFontDescriptorDictionary) { PDStream fontFile = ((PDFontDescriptorDictionary)fontDescriptor).getFontFile(); if( fontFile != null ) { BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(fontFile.createInputStream(), "ISO-8859-1")); // this section parses the font program stream searching for a /Encoding entry // if it contains an array of values a Type1Encoding will be returned // if it encoding contains an encoding name the corresponding Encoding will be returned String line = ""; Type1Encoding encoding = null; while( (line = in.readLine()) != null) { if (extractEncoding) { if (line.startsWith("currentdict end")) { if (encoding != null) setFontEncoding(encoding); break; } if (line.startsWith("/Encoding")) { if(line.contains("array")) { StringTokenizer st = new StringTokenizer(line); // ignore the first token st.nextElement(); int arraySize = Integer.parseInt(st.nextToken()); encoding = new Type1Encoding(arraySize); } // if there is already an encoding, we don't need to // assign another one else if (getFontEncoding() == null) { StringTokenizer st = new StringTokenizer(line); // ignore the first token st.nextElement(); String type1Encoding = st.nextToken(); setFontEncoding( EncodingManager.INSTANCE.getEncoding( COSName.getPDFName(type1Encoding))); break; } } else if (line.startsWith("dup")) { StringTokenizer st = new StringTokenizer(line.replaceAll("/"," /")); // ignore the first token st.nextElement(); try { int index = Integer.parseInt(st.nextToken()); String name = st.nextToken(); if(encoding == null) { log.warn("Unable to get character encoding. " + "Encoding definition found without /Encoding line."); } else { encoding.addCharacterEncoding(index, name.replace("/", "")); } } catch(NumberFormatException exception) { // there are (tex?)-some fonts containing postscript code like the following, // which has to be ignored, see PDFBOX-1481 // dup dup 161 10 getinterval 0 exch putinterval .... log.debug("Malformed encoding definition ignored (line="+line+")"); } continue; } } // according to the pdf reference, all font matrices should be same, except for type 3 fonts. // but obviously there are some type1 fonts with different matrix values, see pdf sample // attached to PDFBOX-935 if (line.startsWith("/FontMatrix")) { // most likely all matrix values are in the same line than the keyword if (line.indexOf("[") > -1) { String matrixValues = line.substring(line.indexOf("[")+1,line.lastIndexOf("]")); StringTokenizer st = new StringTokenizer(matrixValues); COSArray array = new COSArray(); if (st.countTokens() >= 6) { try { for (int i=0;i<6;i++) { COSFloat floatValue = new COSFloat(Float.parseFloat(st.nextToken())); array.add(floatValue); } } catch (NumberFormatException exception) { log.error("Can't read the fontmatrix from embedded font file!"); } fontMatrix = new PDMatrix(array); } } else { // there are fonts where all values are on a separate line, see PDFBOX-1611 COSArray array = new COSArray(); while((line = in.readLine()) != null) { if (line.startsWith("[")) { continue; } if (line.endsWith("]")) { break; } try { COSFloat floatValue = new COSFloat(Float.parseFloat(line)); array.add(floatValue); } catch (NumberFormatException exception) { log.error("Can't read the fontmatrix from embedded font file!"); } } if (array.size() == 6) { fontMatrix = new PDMatrix(array); } else { log.error("Can't read the fontmatrix from embedded font file, not enough values!"); } } } } } catch(IOException exception) { log.error("Error: Could not extract the encoding from the embedded type1 font."); } finally { if (in != null) { try { in.close(); } catch(IOException exception) { log.error("An error occurs while closing the stream used to read the embedded type1 font."); } } } } } } /** * {@inheritDoc} */ @Override public String encode(byte[] c, int offset, int length) throws IOException { if (type1CFont != null && getFontEncoding() == null) { String character = type1CFont.encode(c, offset, length); if (character != null) { return character; } } return super.encode(c, offset, length); } /** * {@inheritDoc} */ @Override public int encodeToCID( byte[] c, int offset, int length ) throws IOException { if (type1CFont != null && getFontEncoding() == null) { return type1CFont.encodeToCID(c, offset, length); } else { return super.encodeToCID(c, offset, length); } } /** * {@inheritDoc} */ @Override public PDMatrix getFontMatrix() { if (type1CFont != null) { return type1CFont.getFontMatrix(); } else { return super.getFontMatrix(); } } @Override public void clear() { super.clear(); if (type1CFont != null) { type1CFont.clear(); type1CFont = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java0000644000000000000000000000277212645757432026565 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This is implementation of the Multiple Master Type1 Font. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDMMType1Font extends PDType1Font { /** * Constructor. */ public PDMMType1Font() { super(); font.setItem( COSName.SUBTYPE, COSName.MM_TYPE1 ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDMMType1Font( COSDictionary fontDictionary ) { super( fontDictionary ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptor.java0000644000000000000000000003131712645757432027444 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.io.IOException; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * This class represents an interface to the font description. This will depend * on the font type for the actual implementation. If it is a AFM/cmap/or embedded font. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public abstract class PDFontDescriptor { /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_FIXED_PITCH = 1; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_SERIF = 2; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_SYMBOLIC = 4; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_SCRIPT = 8; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_NON_SYMBOLIC = 32; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_ITALIC = 64; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_ALL_CAP = 65536; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_SMALL_CAP = 131072; /** * A font descriptor flag. See PDF Reference for description. */ private static final int FLAG_FORCE_BOLD = 262144; /** * Get the font name. * * @return The name of the font. */ public abstract String getFontName(); /** * This will set the font name. * * @param fontName The new name for the font. */ public abstract void setFontName( String fontName ); /** * A string representing the preferred font family. * * @return The font family. */ public abstract String getFontFamily(); /** * This will set the font family. * * @param fontFamily The font family. */ public abstract void setFontFamily( String fontFamily ); /** * A string representing the preferred font stretch. * According to the PDF Spec: * The font stretch value; it must be one of the following (ordered from * narrowest to widest): UltraCondensed, ExtraCondensed, Condensed, SemiCondensed, * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded. * * @return The font stretch. */ public abstract String getFontStretch(); /** * This will set the font stretch. * * @param fontStretch The font stretch */ public abstract void setFontStretch( String fontStretch ); /** * The weight of the font. According to the PDF spec "possible values are * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is * more weight and appears to be more bold. * * @return The font weight. */ public abstract float getFontWeight(); /** * Set the weight of the font. * * @param fontWeight The new weight of the font. */ public abstract void setFontWeight( float fontWeight ); /** * This will get the font flags. * * @return The font flags. */ public abstract int getFlags(); /** * This will set the font flags. * * @param flags The new font flags. */ public abstract void setFlags( int flags ); /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isFixedPitch() { return isFlagBitOn( FLAG_FIXED_PITCH ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setFixedPitch( boolean flag ) { setFlagBit( FLAG_FIXED_PITCH, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isSerif() { return isFlagBitOn( FLAG_SERIF ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setSerif( boolean flag ) { setFlagBit( FLAG_SERIF, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isSymbolic() { return isFlagBitOn( FLAG_SYMBOLIC ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setSymbolic( boolean flag ) { setFlagBit( FLAG_SYMBOLIC, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isScript() { return isFlagBitOn( FLAG_SCRIPT ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setScript( boolean flag ) { setFlagBit( FLAG_SCRIPT, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isNonSymbolic() { return isFlagBitOn( FLAG_NON_SYMBOLIC ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setNonSymbolic( boolean flag ) { setFlagBit( FLAG_NON_SYMBOLIC, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isItalic() { return isFlagBitOn( FLAG_ITALIC ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setItalic( boolean flag ) { setFlagBit( FLAG_ITALIC, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isAllCap() { return isFlagBitOn( FLAG_ALL_CAP); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setAllCap( boolean flag ) { setFlagBit( FLAG_ALL_CAP, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isSmallCap() { return isFlagBitOn( FLAG_SMALL_CAP ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setSmallCap( boolean flag ) { setFlagBit( FLAG_SMALL_CAP, flag ); } /** * A convenience method that checks the flag bit. * * @return The flag value. */ public boolean isForceBold() { return isFlagBitOn( FLAG_FORCE_BOLD ); } /** * A convenience method that sets the flag bit. * * @param flag The flag value. */ public void setForceBold( boolean flag ) { setFlagBit( FLAG_FORCE_BOLD, flag ); } private boolean isFlagBitOn( int bit ) { return (getFlags() & bit) != 0; } private void setFlagBit( int bit, boolean value ) { int flags = getFlags(); if( value ) { flags = flags | bit; } else { flags = flags & (0xFFFFFFFF ^ bit); } setFlags( flags ); } /** * This will get the fonts bouding box. * * @return The fonts bouding box. */ public abstract PDRectangle getFontBoundingBox(); /** * Set the fonts bounding box. * * @param rect The new bouding box. */ public abstract void setFontBoundingBox( PDRectangle rect ); /** * This will get the italic angle for the font. * * @return The italic angle. */ public abstract float getItalicAngle(); /** * This will set the italic angle for the font. * * @param angle The new italic angle for the font. */ public abstract void setItalicAngle( float angle ); /** * This will get the ascent for the font. * * @return The ascent. */ public abstract float getAscent(); /** * This will set the ascent for the font. * * @param ascent The new ascent for the font. */ public abstract void setAscent( float ascent ); /** * This will get the descent for the font. * * @return The descent. */ public abstract float getDescent(); /** * This will set the descent for the font. * * @param descent The new descent for the font. */ public abstract void setDescent( float descent ); /** * This will get the leading for the font. * * @return The leading. */ public abstract float getLeading(); /** * This will set the leading for the font. * * @param leading The new leading for the font. */ public abstract void setLeading( float leading ); /** * This will get the CapHeight for the font. * * @return The cap height. */ public abstract float getCapHeight(); /** * This will set the cap height for the font. * * @param capHeight The new cap height for the font. */ public abstract void setCapHeight( float capHeight ); /** * This will get the x height for the font. * * @return The x height. */ public abstract float getXHeight(); /** * This will set the x height for the font. * * @param xHeight The new x height for the font. */ public abstract void setXHeight( float xHeight ); /** * This will get the stemV for the font. * * @return The stem v value. */ public abstract float getStemV(); /** * This will set the stem V for the font. * * @param stemV The new stem v for the font. */ public abstract void setStemV( float stemV ); /** * This will get the stemH for the font. * * @return The stem h value. */ public abstract float getStemH(); /** * This will set the stem H for the font. * * @param stemH The new stem h for the font. */ public abstract void setStemH( float stemH ); /** * This will get the average width for the font. This is part of the * definition in the font description. If it is not present then PDFBox * will make an attempt to calculate it. * * @return The average width value. * * @throws IOException If there is an error calculating the average width. */ public abstract float getAverageWidth() throws IOException; /** * This will set the average width for the font. * * @param averageWidth The new average width for the font. */ public abstract void setAverageWidth( float averageWidth ); /** * This will get the max width for the font. * * @return The max width value. */ public abstract float getMaxWidth(); /** * This will set the max width for the font. * * @param maxWidth The new max width for the font. */ public abstract void setMaxWidth( float maxWidth ); /** * This will get the character set for the font. * * @return The character set value. */ public abstract String getCharSet(); /** * This will set the character set for the font. * * @param charSet The new character set for the font. */ public abstract void setCharacterSet( String charSet ); /** * This will get the missing width for the font. * * @return The missing width value. */ public abstract float getMissingWidth(); /** * This will set the missing width for the font. * * @param missingWidth The new missing width for the font. */ public abstract void setMissingWidth( float missingWidth ); } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontManager.java0000644000000000000000000002554012645757432026455 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.util.ResourceLoader; /** * This class is used as font manager. * @author Andreas Lehmkühler * @version $Revision: 1.0 $ */ public class FontManager { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(FontManager.class); // HashMap with all known fonts private static HashMap envFonts = new HashMap(); // the standard font private final static String standardFont = "helvetica"; private static Properties fontMapping = new Properties(); static { try { ResourceLoader.loadProperties( "org/apache/pdfbox/resources/FontMapping.properties", fontMapping ); } catch( IOException io ) { LOG.error(io,io); throw new RuntimeException( "Error loading font mapping" ); } loadFonts(); loadBasefontMapping(); loadFontMapping(); } private FontManager() { } /** * Get the standard font from the environment, usually Arial or Times New Roman. * * @return The standard font * */ public static java.awt.Font getStandardFont() { Font awtFont = getAwtFont(standardFont); if (awtFont == null) { // PDFBOX-1069 LOG.error("Standard font '" + standardFont + "' is not part of the environment"); LOG.error("Available fonts:"); for (Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) { LOG.error("\t" + font.getFontName()); } } return awtFont; } /** * Get the font for the given fontname. * * @param font The name of the font. * * @return The font we are looking for or a similar font or null if nothing is found. * */ public static java.awt.Font getAwtFont(String font) { String fontname = normalizeFontname(font); if (envFonts.containsKey(fontname)) { return envFonts.get(fontname); } return null; } /** * Load all available fonts from the environment. */ private static void loadFonts() { for (Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) { String family = normalizeFontname(font.getFamily()); String psname = normalizeFontname(font.getPSName()); if (isBoldItalic(font)) { envFonts.put(family+"bolditalic", font); } else if (isBold(font)) { envFonts.put(family+"bold", font); } else if (isItalic(font)) { envFonts.put(family+"italic", font); } else { envFonts.put(family, font); } if (!family.equals(psname)) { envFonts.put(normalizeFontname(font.getPSName()),font); } } } /** * Normalize the fontname. * * @param fontname The name of the font. * * @return The normalized name of the font. * */ private static String normalizeFontname(String fontname) { // Terminate all whitespaces, commas and hyphens String normalizedFontname = fontname.toLowerCase().replaceAll(" ","").replaceAll(",","").replaceAll("-",""); // Terminate trailing characters up to the "+". // As far as I know, these characters are used in names of embedded fonts // If the embedded font can't be read, we'll try to find it here if (normalizedFontname.indexOf("+") > -1) { normalizedFontname = normalizedFontname.substring(normalizedFontname.indexOf("+")+1); } // normalize all kinds of fonttypes. There are several possible version which have to be normalized // e.g. Arial,Bold Arial-BoldMT Helevtica-oblique ... boolean isBold = normalizedFontname.indexOf("bold") > -1; boolean isItalic = normalizedFontname.indexOf("italic") > -1 || normalizedFontname.indexOf("oblique") > -1; normalizedFontname = normalizedFontname.toLowerCase().replaceAll("bold" , "") .replaceAll("italic" , "").replaceAll("oblique" , ""); if (isBold) { normalizedFontname += "bold"; } if (isItalic) { normalizedFontname += "italic"; } return normalizedFontname; } /** * Add a font-mapping. * * @param font The name of the font. * * @param mappedName The name of the mapped font. * */ private static boolean addFontMapping(String font, String mappedName) { String fontname = normalizeFontname(font); // is there already a font mapping ? if (envFonts.containsKey(fontname)) { return false; } String mappedFontname = normalizeFontname(mappedName); // is the mapped font available ? if (!envFonts.containsKey(mappedFontname)) { return false; } envFonts.put(fontname, envFonts.get(mappedFontname)); return true; } /** * Load the mapping for the well knwon font-substitutions. * */ private static void loadFontMapping() { boolean addedMapping = true; // There could be some recursive mappings in the fontmapping, so that we have to // read the list until no more additional mapping is added to it while (addedMapping) { int counter = 0; Enumeration keys = fontMapping.keys(); while (keys.hasMoreElements()) { String key = (String)keys.nextElement(); if (addFontMapping(key,(String)fontMapping.get(key))) { counter++; } } if (counter == 0) { addedMapping = false; } } } /** * Mapping for the basefonts. */ private static void loadBasefontMapping() { // use well known substitutions if the environments doesn't provide native fonts for the 14 standard fonts // Times-Roman -> Serif if (!addFontMapping("Times-Roman","TimesNewRoman")) { addFontMapping("Times-Roman","Serif"); } if (!addFontMapping("Times-Bold","TimesNewRoman,Bold")) { addFontMapping("Times-Bold","Serif.bold"); } if (!addFontMapping("Times-Italic","TimesNewRoman,Italic")) { addFontMapping("Times-Italic","Serif.italic"); } if (!addFontMapping("Times-BoldItalic","TimesNewRoman,Bold,Italic")) { addFontMapping("Times-BoldItalic","Serif.bolditalic"); } // Helvetica -> SansSerif if (!addFontMapping("Helvetica","Helvetica")) { addFontMapping("Helvetica","SansSerif"); } if (!addFontMapping("Helvetica-Bold","Helvetica,Bold")) { addFontMapping("Helvetica-Bold","SansSerif.bold"); } if (!addFontMapping("Helvetica-Oblique","Helvetica,Italic")) { addFontMapping("Helvetica-Oblique","SansSerif.italic"); } if (!addFontMapping("Helvetica-BoldOblique","Helvetica,Bold,Italic")) { addFontMapping("Helvetica-BoldOblique","SansSerif.bolditalic"); } // Courier -> Monospaced if (!addFontMapping("Courier","Courier")) { addFontMapping("Courier","Monospaced"); } if (!addFontMapping("Courier-Bold","Courier,Bold")) { addFontMapping("Courier-Bold","Monospaced.bold"); } if (!addFontMapping("Courier-Oblique","Courier,Italic")) { addFontMapping("Courier-Oblique","Monospaced.italic"); } if (!addFontMapping("Courier-BoldOblique","Courier,Bold,Italic")) { addFontMapping("Courier-BoldOblique","Monospaced.bolditalic"); } // some well known (??) substitutions found on fedora linux addFontMapping("Symbol","StandardSymbolsL"); addFontMapping("ZapfDingbats","Dingbats"); } /** * Try to determine if the font has both a BOLD and an ITALIC-type. * * @param name The font. * * @return font has BOLD and ITALIC-type or not */ private static boolean isBoldItalic(java.awt.Font font) { return isBold(font) && isItalic(font); } /** * Try to determine if the font has a BOLD-type. * * @param name The font. * * @return font has BOLD-type or not */ private static boolean isBold(java.awt.Font font) { String name = font.getName().toLowerCase(); if (name.indexOf("bold") > -1) { return true; } String psname = font.getPSName().toLowerCase(); if (psname.indexOf("bold") > -1) { return true; } return false; } /** * Try to determine if the font has an ITALIC-type. * * @param name The font. * * @return font has ITALIC-type or not */ private static boolean isItalic(java.awt.Font font) { String name = font.getName().toLowerCase(); // oblique is the same as italic if (name.indexOf("italic") > -1 || name.indexOf("oblique") > -1) { return true; } String psname = font.getPSName().toLowerCase(); if (psname.indexOf("italic") > -1 || psname.indexOf("oblique") > -1) { return true; } return false; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Font.java0000644000000000000000000001236112645757432027476 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.awt.FontFormatException; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.common.PDStream; /** * This is implementation of the CIDFontType2 Font. * * @author Ben Litchfield * */ public class PDCIDFontType2Font extends PDCIDFont { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDCIDFontType2Font.class); private Boolean hasCIDToGIDMap = null; private int[] cid2gid = null; /** * Constructor. */ public PDCIDFontType2Font() { super(); font.setItem( COSName.SUBTYPE, COSName.CID_FONT_TYPE2 ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDCIDFontType2Font( COSDictionary fontDictionary ) { super( fontDictionary ); } /** * {@inheritDoc} */ public Font getawtFont() throws IOException { Font awtFont = null; PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary)getFontDescriptor(); PDStream ff2Stream = fd.getFontFile2(); if( ff2Stream != null ) { try { // create a font with the embedded data awtFont = Font.createFont( Font.TRUETYPE_FONT, ff2Stream.createInputStream() ); } catch( FontFormatException f ) { LOG.info("Can't read the embedded font " + fd.getFontName() ); } if (awtFont == null) { if (fd.getFontName() != null) { awtFont = FontManager.getAwtFont(fd.getFontName()); } if (awtFont != null) { LOG.info("Using font "+awtFont.getName()+ " instead"); } setIsFontSubstituted(true); } } return awtFont; } /** * read the CIDToGID map. */ private void readCIDToGIDMapping() { COSBase map = font.getDictionaryObject(COSName.CID_TO_GID_MAP); if (map instanceof COSStream) { COSStream stream = (COSStream)map; try { InputStream is = stream.getUnfilteredStream(); byte[] mapAsBytes = IOUtils.toByteArray(is); IOUtils.closeQuietly(is); int numberOfInts = mapAsBytes.length / 2; cid2gid = new int[numberOfInts]; int offset = 0; for(int index = 0;index < numberOfInts;index++) { cid2gid[index] = getCodeFromArray(mapAsBytes, offset, 2); offset+=2; } } catch(IOException exception) { LOG.error("Can't read the CIDToGIDMap", exception); } } } /** * Indicates if this font has a CIDToGIDMap. * * @return returns true if the font has a CIDToGIDMap. */ public boolean hasCIDToGIDMap() { if (hasCIDToGIDMap == null) { COSBase map = font.getDictionaryObject(COSName.CID_TO_GID_MAP); if (map != null && map instanceof COSStream) { hasCIDToGIDMap = Boolean.TRUE; } else { hasCIDToGIDMap = Boolean.FALSE; } } return hasCIDToGIDMap.booleanValue(); } /** * Maps the given CID to the correspondent GID. * * @param cid the given CID * @return the mapped GID, or -1 if something went wrong. */ public int mapCIDToGID(int cid) { if (hasCIDToGIDMap()) { if (cid2gid == null) { readCIDToGIDMapping(); } if (cid2gid != null && cid < cid2gid.length) { return cid2gid[cid]; } return -1; } else { // identity is the default value return cid; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Type3StreamParser.java0000644000000000000000000005250212645757432027607 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Image; import java.io.IOException; import java.util.List; import org.apache.fontbox.util.BoundingBox; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.graphics.xobject.PDInlinedImage; import org.apache.pdfbox.util.ImageParameters; import org.apache.pdfbox.util.PDFOperator; import org.apache.pdfbox.util.PDFStreamEngine; /** * This class will handle creating an image for a type 3 glyph. * * @author Ben Litchfield * @version $Revision: 1.10 $ */ public class Type3StreamParser extends PDFStreamEngine { private PDInlinedImage image = null; private BoundingBox box = null; /** * This will parse a type3 stream and create an image from it. * * @param type3Stream The stream containing the operators to draw the image. * * @return The image that was created. * * @throws IOException If there is an error processing the stream. */ public Image createImage( COSStream type3Stream ) throws IOException { processStream( null, null, type3Stream ); return image.createImage(); } /** * This is used to handle an operation. * * @param operator The operation to perform. * @param arguments The list of arguments. * * @throws IOException If there is an error processing the operation. */ protected void processOperator( PDFOperator operator, List arguments ) throws IOException { super.processOperator( operator, arguments ); String operation = operator.getOperation(); /** if( operation.equals( "b" ) ) { //Close, fill, and stroke path using nonzero winding number rule } else if( operation.equals( "B" ) ) { //Fill and stroke path using nonzero winding number rule } else if( operation.equals( "b*" ) ) { //Close, fill, and stroke path using even-odd rule } else if( operation.equals( "B*" ) ) { //Fill and stroke path using even-odd rule } else if( operation.equals( "BDC" ) ) { //(PDF 1.2) Begin marked-content sequence with property list } else **/if( operation.equals( "BI" ) ) { ImageParameters params = operator.getImageParameters(); image = new PDInlinedImage(); image.setImageParameters( params ); image.setImageData( operator.getImageData() ); //begin inline image object }/** else if( operation.equals( "BMC" ) ) { //(PDF 1.2) Begin marked-content sequence } else if( operation.equals( "BT" ) ) { log.debug( "" ); textMatrix = new Matrix(); textLineMatrix = new Matrix(); } else if( operation.equals( "BX" ) ) { //(PDF 1.1) Begin compatibility section } else if( operation.equals( "c" ) ) { //Append curved segment to path (three control points) } else if( operation.equals( "cm" ) ) { } else if( operation.equals( "cs" ) ) { } else if( operation.equals( "CS" ) ) { } else if( operation.equals( "d" ) ) { //Set the line dash pattern in the graphics state } else */if( operation.equals( "d0" ) ) { //set glyph with for a type3 font //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 ); //COSNumber verticalWidth = (COSNumber)arguments.get( 1 ); //width = horizontalWidth.intValue(); //height = verticalWidth.intValue(); } else if( operation.equals( "d1" ) ) { //set glyph with and bounding box for type 3 font //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 ); //COSNumber verticalWidth = (COSNumber)arguments.get( 1 ); COSNumber llx = (COSNumber)arguments.get( 2 ); COSNumber lly = (COSNumber)arguments.get( 3 ); COSNumber urx = (COSNumber)arguments.get( 4 ); COSNumber ury = (COSNumber)arguments.get( 5 ); //width = horizontalWidth.intValue(); //height = verticalWidth.intValue(); box = new BoundingBox(); box.setLowerLeftX( llx.floatValue() ); box.setLowerLeftY( lly.floatValue() ); box.setUpperRightX( urx.floatValue() ); box.setUpperRightY( ury.floatValue() ); }/* else if( operation.equals( "Do" ) ) { //invoke named object. } else if( operation.equals( "DP" ) ) { //(PDF 1.2) De.ne marked-content point with property list } else if( operation.equals( "EI" ) ) { //end inline image object } else if( operation.equals( "EMC" ) ) { //End inline image object } else if( operation.equals( "ET" ) ) { log.debug( "" ); textMatrix = null; textLineMatrix = null; } else if( operation.equals( "EX" ) ) { //(PDF 1.1) End compatibility section } else if( operation.equals( "f" ) ) { //Fill the path, using the nonzero winding number rule to determine the region to .ll } else if( operation.equals( "F" ) ) { } else if( operation.equals( "f*" ) ) { //Fill path using even-odd rule } else if( operation.equals( "g" ) ) { } else if( operation.equals( "G" ) ) { } else if( operation.equals( "gs" ) ) { } else if( operation.equals( "h" ) ) { //close subpath } else if( operation.equals( "i" ) ) { //set flatness tolerance, not sure what this does } else if( operation.equals( "ID" ) ) { //begin inline image data } else if( operation.equals( "j" ) ) { //Set the line join style in the graphics state //System.out.println( "" ); } else if( operation.equals( "J" ) ) { //Set the line cap style in the graphics state //System.out.println( "" ); } else if( operation.equals( "k" ) ) { //Set CMYK color for nonstroking operations } else if( operation.equals( "K" ) ) { //Set CMYK color for stroking operations } else if( operation.equals( "l" ) ) { //append straight line segment from the current point to the point. COSNumber x = (COSNumber)arguments.get( 0 ); COSNumber y = (COSNumber)arguments.get( 1 ); linePath.lineTo( x.floatValue(), pageSize.getHeight()-y.floatValue() ); } else if( operation.equals( "m" ) ) { COSNumber x = (COSNumber)arguments.get( 0 ); COSNumber y = (COSNumber)arguments.get( 1 ); linePath.reset(); linePath.moveTo( x.floatValue(), pageSize.getHeight()-y.floatValue() ); //System.out.println( "" ); } else if( operation.equals( "M" ) ) { //System.out.println( "" ); } else if( operation.equals( "MP" ) ) { //(PDF 1.2) Define marked-content point } else if( operation.equals( "n" ) ) { //End path without .lling or stroking //System.out.println( "" ); } else if( operation.equals( "q" ) ) { //save graphics state if( log.isDebugEnabled() ) { log.debug( "<" + operation + "> - save state" ); } graphicsStack.push(graphicsState.clone()); } else if( operation.equals( "Q" ) ) { //restore graphics state if( log.isDebugEnabled() ) { log.debug( "<" + operation + "> - restore state" ); } graphicsState = (PDGraphicsState)graphicsStack.pop(); } else if( operation.equals( "re" ) ) { } else if( operation.equals( "rg" ) ) { //Set RGB color for nonstroking operations } else if( operation.equals( "RG" ) ) { //Set RGB color for stroking operations } else if( operation.equals( "ri" ) ) { //Set color rendering intent } else if( operation.equals( "s" ) ) { //Close and stroke path } else if( operation.equals( "S" ) ) { graphics.draw( linePath ); } else if( operation.equals( "sc" ) ) { //set color for nonstroking operations //System.out.println( "" ); } else if( operation.equals( "SC" ) ) { //set color for stroking operations //System.out.println( "" ); } else if( operation.equals( "scn" ) ) { //set color for nonstroking operations special } else if( operation.equals( "SCN" ) ) { //set color for stroking operations special } else if( operation.equals( "sh" ) ) { //(PDF 1.3) Paint area de.ned by shading pattern } else if( operation.equals( "T*" ) ) { if (log.isDebugEnabled()) { log.debug(""); } //move to start of next text line if( graphicsState.getTextState().getLeading() == 0 ) { graphicsState.getTextState().setLeading( -.01f ); } Matrix td = new Matrix(); td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1)); textLineMatrix = textLineMatrix.multiply( td ); textMatrix = textLineMatrix.copy(); } else if( operation.equals( "Tc" ) ) { //set character spacing COSNumber characterSpacing = (COSNumber)arguments.get( 0 ); if (log.isDebugEnabled()) { log.debug(""); } graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() ); } else if( operation.equals( "Td" ) ) { COSNumber x = (COSNumber)arguments.get( 0 ); COSNumber y = (COSNumber)arguments.get( 1 ); if (log.isDebugEnabled()) { log.debug(""); } Matrix td = new Matrix(); td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) ); td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) ); //log.debug( "textLineMatrix before " + textLineMatrix ); textLineMatrix = textLineMatrix.multiply( td ); //log.debug( "textLineMatrix after " + textLineMatrix ); textMatrix = textLineMatrix.copy(); } else if( operation.equals( "TD" ) ) { //move text position and set leading COSNumber x = (COSNumber)arguments.get( 0 ); COSNumber y = (COSNumber)arguments.get( 1 ); if (log.isDebugEnabled()) { log.debug(""); } graphicsState.getTextState().setLeading( -1 * y.floatValue() ); Matrix td = new Matrix(); td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) ); td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) ); //log.debug( "textLineMatrix before " + textLineMatrix ); textLineMatrix = textLineMatrix.multiply( td ); //log.debug( "textLineMatrix after " + textLineMatrix ); textMatrix = textLineMatrix.copy(); } else if( operation.equals( "Tf" ) ) { //set font and size COSName fontName = (COSName)arguments.get( 0 ); graphicsState.getTextState().setFontSize( ((COSNumber)arguments.get( 1 ) ).floatValue() ); if (log.isDebugEnabled()) { log.debug(""); } //old way //graphicsState.getTextState().getFont() = (COSObject)stream.getDictionaryObject( fontName ); //if( graphicsState.getTextState().getFont() == null ) //{ // graphicsState.getTextState().getFont() = (COSObject)graphicsState.getTextState().getFont() // Dictionary.getItem( fontName ); //} graphicsState.getTextState().setFont( (PDFont)fonts.get( fontName.getName() ) ); if( graphicsState.getTextState().getFont() == null ) { throw new IOException( "Error: Could not find font(" + fontName + ") in map=" + fonts ); } //log.debug( "Font Resource=" + fontResource ); //log.debug( "Current Font=" + graphicsState.getTextState().getFont() ); //log.debug( "graphicsState.getTextState().getFontSize()=" + graphicsState.getTextState().getFontSize() ); } else if( operation.equals( "Tj" ) ) { COSString string = (COSString)arguments.get( 0 ); TextPosition pos = showString( string.getBytes() ); if (log.isDebugEnabled()) { log.debug(""); } } else if( operation.equals( "TJ" ) ) { Matrix td = new Matrix(); COSArray array = (COSArray)arguments.get( 0 ); for( int i=0; i" ); } td.setValue( 2, 0, value ); textMatrix = textMatrix.multiply( td ); } else if( next instanceof COSString ) { TextPosition pos = showString( ((COSString)next).getBytes() ); if (log.isDebugEnabled()) { log.debug(""); } } else { throw new IOException( "Unknown type in array for TJ operation:" + next ); } } } else if( operation.equals( "TL" ) ) { COSNumber leading = (COSNumber)arguments.get( 0 ); graphicsState.getTextState().setLeading( leading.floatValue() ); if (log.isDebugEnabled()) { log.debug(""); } } else if( operation.equals( "Tm" ) ) { //Set text matrix and text line matrix COSNumber a = (COSNumber)arguments.get( 0 ); COSNumber b = (COSNumber)arguments.get( 1 ); COSNumber c = (COSNumber)arguments.get( 2 ); COSNumber d = (COSNumber)arguments.get( 3 ); COSNumber e = (COSNumber)arguments.get( 4 ); COSNumber f = (COSNumber)arguments.get( 5 ); if (log.isDebugEnabled()) { log.debug(""); } textMatrix = new Matrix(); textMatrix.setValue( 0, 0, a.floatValue() ); textMatrix.setValue( 0, 1, b.floatValue() ); textMatrix.setValue( 1, 0, c.floatValue() ); textMatrix.setValue( 1, 1, d.floatValue() ); textMatrix.setValue( 2, 0, e.floatValue() ); textMatrix.setValue( 2, 1, f.floatValue() ); textLineMatrix = textMatrix.copy(); } else if( operation.equals( "Tr" ) ) { //Set text rendering mode //System.out.println( "" ); } else if( operation.equals( "Ts" ) ) { //Set text rise //System.out.println( "" ); } else if( operation.equals( "Tw" ) ) { //set word spacing COSNumber wordSpacing = (COSNumber)arguments.get( 0 ); if (log.isDebugEnabled()) { log.debug(""); } graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() ); } else if( operation.equals( "Tz" ) ) { //Set horizontal text scaling } else if( operation.equals( "v" ) ) { //Append curved segment to path (initial point replicated) } else if( operation.equals( "w" ) ) { //Set the line width in the graphics state //System.out.println( "" ); } else if( operation.equals( "W" ) ) { //Set clipping path using nonzero winding number rule //System.out.println( "" ); } else if( operation.equals( "W*" ) ) { //Set clipping path using even-odd rule } else if( operation.equals( "y" ) ) { //Append curved segment to path (final point replicated) } else if( operation.equals( "'" ) ) { // Move to start of next text line, and show text // COSString string = (COSString)arguments.get( 0 ); if (log.isDebugEnabled()) { log.debug("<' string=\"" + string.getString() + "\">"); } Matrix td = new Matrix(); td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1)); textLineMatrix = textLineMatrix.multiply( td ); textMatrix = textLineMatrix.copy(); showString( string.getBytes() ); } else if( operation.equals( "\"" ) ) { //Set word and character spacing, move to next line, and show text // COSNumber wordSpacing = (COSNumber)arguments.get( 0 ); COSNumber characterSpacing = (COSNumber)arguments.get( 1 ); COSString string = (COSString)arguments.get( 2 ); if (log.isDebugEnabled()) { log.debug("<\" wordSpacing=\"" + wordSpacing + "\", characterSpacing=\"" + characterSpacing + "\", string=\"" + string.getString() + "\">"); } graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() ); graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() ); Matrix td = new Matrix(); td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1)); textLineMatrix = textLineMatrix.multiply( td ); textMatrix = textLineMatrix.copy(); showString( string.getBytes() ); }*/ } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType3Font.java0000644000000000000000000000707312645757432026334 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.PDMatrix; import java.awt.Graphics; import java.awt.geom.AffineTransform; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; /** * This is implementation of the Type3 Font. * * @author Ben Litchfield * */ public class PDType3Font extends PDSimpleFont { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDType3Font.class); /** * cached height. */ private float type3Height = 0; /** * Constructor. */ public PDType3Font() { super(); font.setItem( COSName.SUBTYPE, COSName.TYPE3 ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDType3Font( COSDictionary fontDictionary ) { super( fontDictionary ); } /** * {@inheritDoc} */ public void drawString( String string, int[] codePoints, Graphics g, float fontSize, AffineTransform at, float x, float y ) throws IOException { LOG.info("Rendering of type3 fonts isn't supported in PDFBox 1.8.x. It will be available in the 2.0 version!"); } /** * Set the font matrix for this type3 font. * * @param matrix The font matrix for this type3 font. */ public void setFontMatrix( PDMatrix matrix ) { font.setItem( COSName.FONT_MATRIX, matrix ); } @Override public float getFontHeight(byte[] c, int offset, int length) throws IOException { // first try old behavior until & including 1.8.10 float height = super.getFontHeight(c, offset, length); // if that didn't work, use 1/2 of font bounding box if (height == 0) { if (type3Height != 0) { return type3Height; } COSBase bboxBase = font.getDictionaryObject(COSName.FONT_BBOX); if (bboxBase instanceof COSArray) { COSArray bboxArray = (COSArray) bboxBase; COSBase o1 = bboxArray.getObject(1); COSBase o3 = bboxArray.getObject(3); if (bboxArray.size() == 4 && o1 instanceof COSNumber && o3 instanceof COSNumber) { height = ((COSNumber) o3).floatValue() - ((COSNumber) o1).floatValue(); type3Height = height / 2; return type3Height; } } } return height; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java0000644000000000000000000007374412645757432027121 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.awt.FontFormatException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.ttf.CMAPEncodingEntry; import org.apache.fontbox.ttf.CMAPTable; import org.apache.fontbox.ttf.GlyphData; import org.apache.fontbox.ttf.GlyphTable; import org.apache.fontbox.ttf.HeaderTable; import org.apache.fontbox.ttf.HorizontalHeaderTable; import org.apache.fontbox.ttf.HorizontalMetricsTable; import org.apache.fontbox.ttf.NameRecord; import org.apache.fontbox.ttf.NamingTable; import org.apache.fontbox.ttf.OS2WindowsMetricsTable; import org.apache.fontbox.ttf.PostScriptTable; import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TTFSubFont; import org.apache.fontbox.ttf.TrueTypeFont; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.encoding.MacOSRomanEncoding; import org.apache.pdfbox.encoding.WinAnsiEncoding; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.util.ResourceLoader; /** * This is the TrueType implementation of fonts. * * @author Ben Litchfield * */ public class PDTrueTypeFont extends PDSimpleFont { /** * Log instance. */ private static final Log log = LogFactory.getLog(PDTrueTypeFont.class); /** * Start of coderanges. */ private static final int START_RANGE_F000 = 0xF000; private static final int START_RANGE_F100 = 0xF100; private static final int START_RANGE_F200 = 0xF200; private CMAPEncodingEntry cmapWinUnicode = null; private CMAPEncodingEntry cmapWinSymbol = null; private CMAPEncodingEntry cmapMacintoshSymbol = null; private boolean cmapInitialized = false; private TrueTypeFont trueTypeFont = null; private HashMap advanceWidths = new HashMap (); /** * This is the key to a property in the PDFBox_External_Fonts.properties * file to load a Font when a mapping does not exist for the current font. */ public static final String UNKNOWN_FONT = "UNKNOWN_FONT"; private Font awtFont = null; private static Properties externalFonts = new Properties(); private static Map loadedExternalFonts = new HashMap(); static { try { ResourceLoader.loadProperties( "org/apache/pdfbox/resources/PDFBox_External_Fonts.properties", externalFonts ); } catch( IOException io ) { throw new RuntimeException( "Error loading font resources", io ); } } /** * Constructor. */ public PDTrueTypeFont() { super(); font.setItem( COSName.SUBTYPE, COSName.TRUE_TYPE ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. * * @throws IOException exception if something went wrong when loading the font. */ public PDTrueTypeFont( COSDictionary fontDictionary ) throws IOException { super( fontDictionary ); ensureFontDescriptor(); } /** * This will load a TTF font from a font file. * * @param doc The PDF document that will hold the embedded font. * @param file The file on the filesystem that holds the font file. * @return A true type font. * @throws IOException If there is an error loading the file data. */ public static PDTrueTypeFont loadTTF( PDDocument doc, String file ) throws IOException { return loadTTF( doc, new File( file ) ); } /** * This will load a TTF to be embedded into a document. * * @param doc The PDF document that will hold the embedded font. * @param file a ttf file. * @return a PDTrueTypeFont instance. * @throws IOException If there is an error loading the data. */ public static PDTrueTypeFont loadTTF( PDDocument doc, File file ) throws IOException { return loadTTF( doc, new FileInputStream( file ) ); } /** * This will load a TTF to be embedded into a document. * * @param doc The PDF document that will hold the embedded font. * @param stream a ttf input stream. * @return a PDTrueTypeFont instance. * @throws IOException If there is an error loading the data. */ public static PDTrueTypeFont loadTTF( PDDocument doc, InputStream stream ) throws IOException { return PDTrueTypeFont.loadTTF(doc,stream,new WinAnsiEncoding()); } /** * This will load a TTF to be embedded into a document. * * @param doc The PDF document that will hold the embedded font. * @param stream a ttf input stream. * @param enc The font encoding. * @return a PDTrueTypeFont instance. * @throws IOException If there is an error loading the data. */ public static PDTrueTypeFont loadTTF( PDDocument doc, InputStream stream, Encoding enc ) throws IOException { PDStream fontStream = new PDStream(doc, stream, false ); fontStream.getStream().setInt( COSName.LENGTH1, fontStream.getByteArray().length ); fontStream.addCompression(); //only support winansi encoding right now, should really //just use Identity-H with unicode mapping return PDTrueTypeFont.loadTTF(fontStream,enc); } /** * This will load a TTF to be embedded into a document. * * @param fontStream a ttf input stream. * @param enc The font encoding. * @return a PDTrueTypeFont instance. * @throws IOException If there is an error loading the data. */ public static PDTrueTypeFont loadTTF( PDStream fontStream, Encoding enc ) throws IOException { PDTrueTypeFont retval = new PDTrueTypeFont(); retval.setFontEncoding( enc ); retval.setEncoding(enc.getCOSObject()); PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary(); retval.setFontDescriptor( fd ); fd.setFontFile2( fontStream ); // As the stream was close within the PDStream constructor, we have to recreate it InputStream stream = fontStream.createInputStream(); try { retval.loadDescriptorDictionary(fd, stream); } finally { stream.close(); } return retval; } private void ensureFontDescriptor() throws IOException { if( getFontDescriptor() == null ) { PDFontDescriptorDictionary fdd = new PDFontDescriptorDictionary(); setFontDescriptor(fdd); InputStream ttfData = getExternalTTFData(); if( ttfData != null ) { try { loadDescriptorDictionary(fdd, ttfData); } finally { ttfData.close(); } } } } private void loadDescriptorDictionary(PDFontDescriptorDictionary fd, InputStream ttfData) throws IOException { TrueTypeFont ttf = null; try { TTFParser parser = new TTFParser(); ttf = parser.parseTTF( ttfData ); NamingTable naming = ttf.getNaming(); List records = naming.getNameRecords(); for( int i=0; i 0 ); fd.setItalicAngle( ps.getItalicAngle() ); String[] names = ps.getGlyphNames(); if( names != null ) { for( int i=0; i codeToName = this.getFontEncoding().getCodeToNameMap(); int firstChar = Collections.min(codeToName.keySet()); int lastChar = Collections.max(codeToName.keySet()); HorizontalMetricsTable hMet = ttf.getHorizontalMetrics(); int[] widthValues = hMet.getAdvanceWidth(); // some monospaced fonts provide only one value for the width // instead of an array containing the same value for every glyphid boolean isMonospaced = fd.isFixedPitch() || widthValues.length == 1; int nWidths=lastChar-firstChar+1; List widths = new ArrayList(nWidths); // use the first width as default // proportional fonts -> width of the .notdef character // monospaced-fonts -> the first width int defaultWidth = Math.round(widthValues[0] * scaling); for (int i = 0; i < nWidths; i++) { widths.add((float)defaultWidth); } // Encoding singleton to have acces to the chglyph name to // unicode cpoint point mapping of Adobe's glyphlist.txt Encoding glyphlist = WinAnsiEncoding.INSTANCE; // A character code is mapped to a glyph name via the provided // font encoding. Afterwards, the glyph name is translated to a // glyph ID. // For details, see PDFReference16.pdf, Section 5.5.5, p.401 // for (Entry e : codeToName.entrySet()) { String name = e.getValue(); // pdf code to unicode by glyph list. String c = glyphlist.getCharacter(name); int charCode = c.codePointAt(0); int gid = uniMap.getGlyphId(charCode); if (gid != 0) { if (isMonospaced) { widths.set(e.getKey().intValue() - firstChar, (float)defaultWidth); } else { widths.set(e.getKey().intValue() - firstChar, (float)Math.round(widthValues[gid] * scaling)); } } } setWidths( widths ); setFirstChar( firstChar ); setLastChar( lastChar ); } finally { if( ttf != null ) { ttf.close(); } } } /** * {@inheritDoc} */ @Override public Font getawtFont() throws IOException { PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary)getFontDescriptor(); if( awtFont == null ) { PDStream ff2Stream = fd.getFontFile2(); if( ff2Stream != null ) { InputStream is = null; try { // create a font with the embedded data is = ff2Stream.createInputStream(); awtFont = Font.createFont(Font.TRUETYPE_FONT, is); } catch( FontFormatException f ) { try { // as a workaround we try to rebuild the embedded subsfont byte[] fontData = rebuildTTF(fd, ff2Stream.createInputStream()); if (fontData != null) { ByteArrayInputStream bais = new ByteArrayInputStream(fontData); awtFont = Font.createFont( Font.TRUETYPE_FONT,bais); } } catch (FontFormatException e) { log.info("Can't read the embedded font " + fd.getFontName() ); } } finally { IOUtils.closeQuietly(is); } if (awtFont == null) { if (fd.getFontName() != null) { awtFont = FontManager.getAwtFont(fd.getFontName()); } if (awtFont != null) { log.info("Using font "+awtFont.getName()+ " instead"); } setIsFontSubstituted(true); } } else { // check if the font is part of our environment if (fd.getFontName() != null) { awtFont = FontManager.getAwtFont(fd.getFontName()); } if (awtFont == null) { log.info("Can't find the specified font " + fd.getFontName() ); // check if there is a font mapping for an external font file TrueTypeFont ttf = getExternalFontFile2( fd ); if( ttf != null ) { try { awtFont = Font.createFont( Font.TRUETYPE_FONT, ttf.getOriginalData() ); } catch( FontFormatException f ) { log.info("Can't read the external fontfile " + fd.getFontName() ); } } } } if (awtFont == null) { // we can't find anything, so we have to use the standard font awtFont = FontManager.getStandardFont(); log.info("Using font "+awtFont.getName()+ " instead"); setIsFontSubstituted(true); } } return awtFont; } private byte[] rebuildTTF(PDFontDescriptorDictionary fd, InputStream inputStream) throws IOException { // this is one possible case of an incomplete subfont which leads to a font exception if (getFontEncoding() instanceof WinAnsiEncoding) { TTFParser ttfParser = new TTFParser(true); TrueTypeFont ttf = ttfParser.parseTTF(inputStream); TTFSubFont ttfSub = new TTFSubFont(ttf, "PDFBox-Rebuild"); for (int i=getFirstChar();i<=getLastChar();i++) { ttfSub.addCharCode(i); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ttfSub.writeToStream(baos); return baos.toByteArray(); } return null; } private InputStream getExternalTTFData() throws IOException { String ttfResource = externalFonts.getProperty( UNKNOWN_FONT ); String baseFont = getBaseFont(); if( baseFont != null && externalFonts.containsKey(baseFont) ) { ttfResource = externalFonts.getProperty( baseFont ); } return (ttfResource != null ? ResourceLoader.loadResource(ttfResource) : null); } /** * Permit to load an external TTF Font program file * * Created by Pascal Allain * Vertical7 Inc. * * @param fd The font descriptor currently used * @return A PDStream with the Font File program, null if fd is null * @throws IOException If the font is not found */ private TrueTypeFont getExternalFontFile2(PDFontDescriptorDictionary fd) throws IOException { TrueTypeFont retval = null; if ( fd != null ) { String baseFont = getBaseFont(); // search for a suitable font in the local environment retval = org.apache.fontbox.util.FontManager.findTTFont(baseFont); // can't find any font, use fall back mapping // NOTE: this fall back mechanism will be removed with PDFBox 2.0.0 if (retval == null) { String fontResource = externalFonts.getProperty( UNKNOWN_FONT ); if( (baseFont != null) && (externalFonts.containsKey(baseFont)) ) { fontResource = externalFonts.getProperty(baseFont); } if( fontResource != null ) { retval = (TrueTypeFont)loadedExternalFonts.get( baseFont ); if( retval == null ) { TTFParser ttfParser = new TTFParser(); InputStream fontStream = ResourceLoader.loadResource( fontResource ); if( fontStream == null ) { throw new IOException( "Error missing font resource '" + externalFonts.get(baseFont) + "'" ); } retval = ttfParser.parseTTF( fontStream ); loadedExternalFonts.put( baseFont, retval ); } } } } return retval; } /** * Return the TTF font as TrueTypeFont. * * @return the TTF font * @throws IOException If there is an error loading the data */ public TrueTypeFont getTTFFont() throws IOException { if (trueTypeFont == null) { PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary) getFontDescriptor(); if (fd != null) { PDStream ff2Stream = fd.getFontFile2(); if (ff2Stream != null) { TTFParser ttfParser = new TTFParser(true); trueTypeFont = ttfParser.parseTTF(ff2Stream.createInputStream()); } } if (trueTypeFont == null) { // check if there is a font mapping for an external font file trueTypeFont = org.apache.fontbox.util.FontManager.findTTFont(getBaseFont()); } } return trueTypeFont; } @Override public void clear() { super.clear(); cmapWinUnicode = null; cmapWinSymbol = null; cmapMacintoshSymbol = null; trueTypeFont = null; if (advanceWidths != null) { advanceWidths.clear(); } } @Override public float getFontWidth(int charCode) { float width = super.getFontWidth(charCode); if (width <= 0) { if (advanceWidths.containsKey(charCode)) { width = advanceWidths.get(charCode); } else { TrueTypeFont ttf = null; try { ttf = getTTFFont(); if (ttf != null) { int code = getGlyphcode(charCode); width = ttf.getAdvanceWidth(code); int unitsPerEM = ttf.getUnitsPerEm(); // do we have to scale the width if (unitsPerEM != 1000) { width *= 1000f/unitsPerEM; } } } catch (IOException exception) { width = 250; } advanceWidths.put(charCode, width); } } return width; } private int getGlyphcode(int code) { extractCMaps(); int result = 0; if (getFontEncoding() != null && !isSymbolicFont()) { try { String charactername = getFontEncoding().getName(code); if (charactername != null) { if (cmapWinUnicode != null) { String unicode = Encoding.getCharacterForName(charactername); if (unicode != null) { result = unicode.codePointAt(0); } result = cmapWinUnicode.getGlyphId(result); } else if (cmapMacintoshSymbol != null && MacOSRomanEncoding.INSTANCE.hasCodeForName(charactername)) { result = MacOSRomanEncoding.INSTANCE.getCode(charactername); result = cmapMacintoshSymbol.getGlyphId(result); } else if (cmapWinSymbol != null) { // fallback scenario if the glyph can't be found yet // maybe the 3,0 cmap provides a suitable mapping // see PDFBOX-2091 result = cmapWinSymbol.getGlyphId(code); } } } catch (IOException exception) { log.error("Caught an exception getGlyhcode: " + exception); } } else if (getFontEncoding() == null || isSymbolicFont()) { if (cmapWinSymbol != null) { result = cmapWinSymbol.getGlyphId(code); if (code >= 0 && code <= 0xFF) { // the CMap may use one of the following code ranges, // so that we have to add the high byte to get the // mapped value if (result == 0) { // F000 - F0FF result = cmapWinSymbol.getGlyphId(code + START_RANGE_F000); } if (result == 0) { // F100 - F1FF result = cmapWinSymbol.getGlyphId(code + START_RANGE_F100); } if (result == 0) { // F200 - F2FF result = cmapWinSymbol.getGlyphId(code + START_RANGE_F200); } } } else if (cmapMacintoshSymbol != null) { result = cmapMacintoshSymbol.getGlyphId(code); } } return result; } /** * extract all useful CMaps. */ private void extractCMaps() { if (!cmapInitialized) { try { getTTFFont(); } catch(IOException exception) { log.error("Can't read the true type font", exception); } CMAPTable cmapTable = trueTypeFont.getCMAP(); if (cmapTable != null) { // get all relevant CMaps CMAPEncodingEntry[] cmaps = cmapTable.getCmaps(); for (int i = 0; i < cmaps.length; i++) { if (cmaps[i] == null) { continue; } if (CMAPTable.PLATFORM_WINDOWS == cmaps[i].getPlatformId()) { if (CMAPTable.ENCODING_UNICODE == cmaps[i].getPlatformEncodingId()) { cmapWinUnicode = cmaps[i]; } else if (CMAPTable.ENCODING_SYMBOL == cmaps[i].getPlatformEncodingId()) { cmapWinSymbol = cmaps[i]; } } else if (CMAPTable.PLATFORM_MACINTOSH == cmaps[i].getPlatformId()) { if (CMAPTable.ENCODING_SYMBOL == cmaps[i].getPlatformEncodingId()) { cmapMacintoshSymbol = cmaps[i]; } } } } cmapInitialized = true; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/package.html0000644000000000000000000000171012645757432025663 0ustar rootroot Classes to deal with font functionality in a PDF Document. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1AfmPfbFont.java0000644000000000000000000002201212645757432027374 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.fontbox.afm.AFMParser; import org.apache.fontbox.afm.CharMetric; import org.apache.fontbox.afm.FontMetric; import org.apache.fontbox.pfb.PfbParser; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.encoding.AFMEncoding; import org.apache.pdfbox.encoding.DictionaryEncoding; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; /** * This is implementation of the Type1 Font with a afm and a pfb file. * * @author Michael Niedermair * @version $Revision: 1.5 $ */ public class PDType1AfmPfbFont extends PDType1Font { /** * the buffersize. */ private static final int BUFFERSIZE = 0xffff; /** * The font metric. */ private FontMetric metric; /** * Create a new object. * * @param doc The PDF document that will hold the embedded font. * @param afmname The font filename. * @throws IOException If there is an error loading the data. */ public PDType1AfmPfbFont(final PDDocument doc, final String afmname) throws IOException { super(); InputStream afmin = new BufferedInputStream(new FileInputStream(afmname), BUFFERSIZE); String pfbname = afmname.replaceAll(".AFM", "").replaceAll(".afm", "") + ".pfb"; InputStream pfbin = new BufferedInputStream(new FileInputStream(pfbname), BUFFERSIZE); load(doc, afmin, pfbin); } /** * Create a new object. * * @param doc The PDF document that will hold the embedded font. * @param afm The afm input. * @param pfb The pfb input. * @throws IOException If there is an error loading the data. */ public PDType1AfmPfbFont(final PDDocument doc, final InputStream afm, final InputStream pfb) throws IOException { super(); load(doc, afm, pfb); } /** * This will load a afm and pfb to be embedding into a document. * * @param doc The PDF document that will hold the embedded font. * @param afm The afm input. * @param pfb The pfb input. * @throws IOException If there is an error loading the data. */ private void load(final PDDocument doc, final InputStream afm, final InputStream pfb) throws IOException { PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary(); setFontDescriptor(fd); // read the pfb PfbParser pfbparser = new PfbParser(pfb); pfb.close(); PDStream fontStream = new PDStream(doc, pfbparser.getInputStream(), false); fontStream.getStream().setInt("Length", pfbparser.size()); for (int i = 0; i < pfbparser.getLengths().length; i++) { fontStream.getStream().setInt("Length" + (i + 1), pfbparser.getLengths()[i]); } fontStream.addCompression(); fd.setFontFile(fontStream); // read the afm AFMParser parser = new AFMParser(afm); parser.parse(); metric = parser.getResult(); setFontEncoding(afmToDictionary(new AFMEncoding(metric))); // set the values setBaseFont(metric.getFontName()); fd.setFontName(metric.getFontName()); fd.setFontFamily(metric.getFamilyName()); fd.setNonSymbolic(true); fd.setFontBoundingBox(new PDRectangle(metric.getFontBBox())); fd.setItalicAngle(metric.getItalicAngle()); fd.setAscent(metric.getAscender()); fd.setDescent(metric.getDescender()); fd.setCapHeight(metric.getCapHeight()); fd.setXHeight(metric.getXHeight()); fd.setAverageWidth(metric.getAverageCharacterWidth()); fd.setCharacterSet(metric.getCharacterSet()); // get firstchar, lastchar int firstchar = 255; int lastchar = 0; // widths List listmetric = metric.getCharMetrics(); Encoding encoding = getFontEncoding(); int maxWidths = 256; List widths = new ArrayList(maxWidths); int zero = 250; Iterator iter = listmetric.iterator(); for (int i = 0; i < maxWidths; i++) { widths.add((float)zero); } while (iter.hasNext()) { CharMetric m = iter.next(); int n = m.getCharacterCode(); if (n > 0) { firstchar = Math.min(firstchar, n); lastchar = Math.max(lastchar, n); if (m.getWx() > 0) { int width = Math.round(m.getWx()); widths.set(n, (float)width); // germandbls has 2 character codes !! Don't ask me why ..... // StandardEncoding = 0373 = 251 // WinANSIEncoding = 0337 = 223 if (m.getName().equals("germandbls") && n != 223) { widths.set(0337, (float)width); } } } else { // my AFMPFB-Fonts has no character-codes for german umlauts // so that I've to add them here by hand if (m.getName().equals("adieresis")) { widths.set(0344, widths.get(encoding.getCode("a"))); } else if (m.getName().equals("odieresis")) { widths.set(0366, widths.get(encoding.getCode("o"))); } else if (m.getName().equals("udieresis")) { widths.set(0374, widths.get(encoding.getCode("u"))); } else if (m.getName().equals("Adieresis")) { widths.set(0304, widths.get(encoding.getCode("A"))); } else if (m.getName().equals("Odieresis")) { widths.set(0326, widths.get(encoding.getCode("O"))); } else if (m.getName().equals("Udieresis")) { widths.set(0334, widths.get(encoding.getCode("U"))); } } } setFirstChar(0); setLastChar(255); setWidths(widths); } /* * This will generate a Encoding from the AFM-Encoding, because the AFM-Enconding isn't exported to the pdf and * consequently the StandardEncoding is used so that any special character is missing I've copied the code from the * pdfbox-forum posted by V0JT4 and made some additions concerning german umlauts see also * https://sourceforge.net/forum/message.php?msg_id=4705274 */ private DictionaryEncoding afmToDictionary(AFMEncoding encoding) throws java.io.IOException { COSArray array = new COSArray(); array.add(COSInteger.ZERO); for (int i = 0; i < 256; i++) { array.add(COSName.getPDFName(encoding.getName(i))); } // my AFMPFB-Fonts has no character-codes for german umlauts // so that I've to add them here by hand array.set(0337 + 1, COSName.getPDFName("germandbls")); array.set(0344 + 1, COSName.getPDFName("adieresis")); array.set(0366 + 1, COSName.getPDFName("odieresis")); array.set(0374 + 1, COSName.getPDFName("udieresis")); array.set(0304 + 1, COSName.getPDFName("Adieresis")); array.set(0326 + 1, COSName.getPDFName("Odieresis")); array.set(0334 + 1, COSName.getPDFName("Udieresis")); COSDictionary dictionary = new COSDictionary(); dictionary.setItem(COSName.NAME, COSName.ENCODING); dictionary.setItem(COSName.DIFFERENCES, array); dictionary.setItem(COSName.BASE_ENCODING, COSName.STANDARD_ENCODING); return new DictionaryEncoding(dictionary); } @Override public void clear() { super.clear(); metric = null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java0000644000000000000000000005133612645757432026436 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.awt.FontFormatException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.afm.AFMParser; import org.apache.fontbox.afm.FontMetric; import org.apache.fontbox.cff.AFMFormatter; import org.apache.fontbox.cff.CFFFont; import org.apache.fontbox.cff.CFFParser; import org.apache.fontbox.cff.Type1FontFormatter; import org.apache.fontbox.cff.charset.CFFCharset; import org.apache.fontbox.cff.encoding.CFFEncoding; import org.apache.fontbox.util.BoundingBox; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.encoding.EncodingManager; import org.apache.pdfbox.exceptions.WrappedIOException; import org.apache.pdfbox.pdmodel.common.PDMatrix; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; /** * This class represents a CFF/Type2 Font (aka Type1C Font). * @author Villu Ruusmann */ public class PDType1CFont extends PDSimpleFont { private CFFFont cffFont = null; private String fontname = null; private Map sidToName = new HashMap(); private Map codeToSID = new HashMap(); private Map sidToCharacter = new HashMap(); private Map characterToSID = new HashMap(); private FontMetric fontMetric = null; private Font awtFont = null; private Map glyphWidths = new HashMap(); private Map glyphHeights = new HashMap(); private Float avgWidth = null; private PDRectangle fontBBox = null; private static final Log log = LogFactory.getLog(PDType1CFont.class); private static final byte[] SPACE_BYTES = {(byte)32}; /** * Constructor. * @param fontDictionary the corresponding dictionary */ public PDType1CFont( COSDictionary fontDictionary ) throws IOException { super( fontDictionary ); load(); } /** * {@inheritDoc} */ @Override public String encode(byte[] bytes, int offset, int length) throws IOException { String character = getCharacter(bytes, offset, length); if (character == null) { log.debug("No character for code " + (bytes[offset] & 0xff) + " in " + fontname); return null; } return character; } private String getCharacter(byte[] bytes, int offset, int length) { String character = null; // the pdf doesn't provide any encoding or toUnicode mapping // we can use the font internal mapping, if a charset is defined // otherwise the internal mapping may produce trash only if (getFontDescriptor().getCharSet() != null) { int code = getCodeFromArray(bytes, offset, length); if (codeToSID.containsKey(code)) { code = codeToSID.get(code); } if (sidToCharacter.containsKey(code)) { character = sidToCharacter.get(code); } } else { // map the byte code to a character character = getStringFromArray(bytes, offset, length); } return character; } /** * {@inheritDoc} */ @Override public int encodeToCID(byte[] bytes, int offset, int length) { if (length > 2) { return -1; } int code = bytes[offset] & 0xff; if (length == 2) { code = code * 256 + bytes[offset + 1] & 0xff; } return code; } /** * {@inheritDoc} */ public float getFontWidth( byte[] bytes, int offset, int length ) throws IOException { String name = getName(bytes, offset, length); if ( name == null && !Arrays.equals(SPACE_BYTES, bytes) ) { log.debug("No name for code " + (bytes[offset] & 0xff) + " in " + this.cffFont.getName()); return 0; } Float width = (Float)this.glyphWidths.get(name); if( width == null ) { width = Float.valueOf(getFontMetric().getCharacterWidth(name)); this.glyphWidths.put(name, width); } return width.floatValue(); } /** * {@inheritDoc} */ public float getFontHeight( byte[] bytes, int offset, int length ) throws IOException { String name = getName(bytes, offset, length); if( name == null ) { log.debug("No name for code " + (bytes[offset] & 0xff) + " in " + this.cffFont.getName()); return 0; } Float height = (Float)this.glyphHeights.get(name); if( height == null ) { height = Float.valueOf(getFontMetric().getCharacterHeight(name)); this.glyphHeights.put(name, height); } return height.floatValue(); } private String getName( byte[] bytes, int offset, int length ) { if (length > 2) { return null; } int code = bytes[offset] & 0xff; if (length == 2) { code = code * 256 + bytes[offset+1] & 0xff; } return sidToName.get(code); } /** * {@inheritDoc} */ public float getStringWidth( String string ) throws IOException { float width = 0; for( int i = 0; i < string.length(); i++ ) { String character = string.substring(i, i + 1); Integer code = getCode(character); if( code == null ) { log.debug("No code for character " + character); return 0; } width += getFontWidth(new byte[]{(byte)code.intValue()}, 0, 1); } return width; } private Integer getCode( String character ) { return characterToSID.get(character); } /** * {@inheritDoc} */ public float getAverageFontWidth() throws IOException { if( this.avgWidth == null ) { this.avgWidth = Float.valueOf(getFontMetric().getAverageCharacterWidth()); } return this.avgWidth.floatValue(); } /** * {@inheritDoc} */ public PDRectangle getFontBoundingBox() throws IOException { if( this.fontBBox == null ) { this.fontBBox = new PDRectangle(getFontMetric().getFontBBox()); } return this.fontBBox; } /** * {@inheritDoc} */ public PDMatrix getFontMatrix() { if( fontMatrix == null ) { List numbers = (List)this.cffFont.getProperty("FontMatrix"); if( numbers != null && numbers.size() == 6 ) { COSArray array = new COSArray(); for(Number number : numbers) { array.add(new COSFloat(number.floatValue())); } fontMatrix = new PDMatrix(array); } else { super.getFontMatrix(); } } return fontMatrix; } /** * {@inheritDoc} */ public Font getawtFont() throws IOException { if (awtFont == null) { this.awtFont = prepareAwtFont(this.cffFont); } return awtFont; } private FontMetric getFontMetric() { if (fontMetric == null) { try { fontMetric = prepareFontMetric(cffFont); } catch (IOException exception) { log.error("An error occured while extracting the font metrics!", exception); } } return fontMetric; } private void load() throws IOException { byte[] cffBytes = loadBytes(); CFFParser cffParser = new CFFParser(); List fonts = cffParser.parse(cffBytes); String baseFontName = getBaseFont(); if (fonts.size() > 1 && baseFontName != null) { for (CFFFont font: fonts) { if (baseFontName.equals(font.getName())) { cffFont = font; break; } } } if (cffFont == null) { cffFont = (CFFFont)fonts.get(0); } // cache the font name fontname = cffFont.getName(); Number defaultWidthX = (Number) cffFont.getProperty("defaultWidthX"); this.glyphWidths.put(null, Float.valueOf(defaultWidthX.floatValue())); CFFEncoding encoding = cffFont.getEncoding(); PDFEncoding pdfEncoding = new PDFEncoding(encoding); CFFCharset charset = cffFont.getCharset(); PDFCharset pdfCharset = new PDFCharset(charset); Map charStringsDict = cffFont.getCharStringsDict(); Map pdfCharStringsDict = new LinkedHashMap(); pdfCharStringsDict.put(".notdef", charStringsDict.get(".notdef")); Map codeToNameMap = new LinkedHashMap(); Collection mappings = cffFont.getMappings(); for( Iterator it = mappings.iterator(); it.hasNext();) { CFFFont.Mapping mapping = it.next(); Integer code = Integer.valueOf(mapping.getCode()); String name = mapping.getName(); codeToNameMap.put(code, name); } Set knownNames = new HashSet(codeToNameMap.values()); Map codeToNameOverride = loadOverride(); for( Iterator> it = (codeToNameOverride.entrySet()).iterator(); it.hasNext();) { Map.Entry entry = it.next(); Integer code = (Integer)entry.getKey(); String name = (String)entry.getValue(); if(knownNames.contains(name)) { codeToNameMap.put(code, name); } } Map nameToCharacter; try { // TODO remove access by reflection Field nameToCharacterField = Encoding.class.getDeclaredField("NAME_TO_CHARACTER"); nameToCharacterField.setAccessible(true); nameToCharacter = (Map)nameToCharacterField.get(null); } catch( Exception e ) { throw new RuntimeException(e); } for( Iterator> it = (codeToNameMap.entrySet()).iterator(); it.hasNext();) { Map.Entry entry = it.next(); Integer code = (Integer)entry.getKey(); String name = (String)entry.getValue(); String uniName = "uni"; String character = (String)nameToCharacter.get(name); if( character != null ) { for( int j = 0; j < character.length(); j++ ) { uniName += hexString(character.charAt(j), 4); } } else { uniName += hexString(code.intValue(), 4); character = String.valueOf((char)code.intValue()); } pdfEncoding.register(code.intValue(), code.intValue()); pdfCharset.register(code.intValue(), uniName); pdfCharStringsDict.put(uniName, charStringsDict.get(name)); } cffFont.setEncoding(pdfEncoding); cffFont.setCharset(pdfCharset); charStringsDict.clear(); charStringsDict.putAll(pdfCharStringsDict); Encoding fontEncoding = getFontEncoding(); Map nameToCode = fontEncoding != null ? fontEncoding.getNameToCodeMap() : null; for (CFFFont.Mapping mapping : mappings) { int sid = mapping.getSID(); String name = mapping.getName(); String character = null; if (nameToCode != null && nameToCode.containsKey(name)) { sid = nameToCode.get(name); character = fontEncoding.getCharacter(name); } if (character == null) { character = Encoding.getCharacterForName(name); } sidToName.put(sid, name); codeToSID.put(mapping.getCode(), sid); if (character != null) { sidToCharacter.put(sid, character); characterToSID.put(character, sid); } } } private byte[] loadBytes() throws IOException { PDFontDescriptor fd = getFontDescriptor(); if( fd != null && fd instanceof PDFontDescriptorDictionary) { PDStream ff3Stream = ((PDFontDescriptorDictionary)fd).getFontFile3(); if( ff3Stream != null ) { ByteArrayOutputStream os = new ByteArrayOutputStream(); InputStream is = ff3Stream.createInputStream(); try { byte[] buf = new byte[512]; while(true) { int count = is.read(buf); if( count < 0 ) { break; } os.write(buf, 0, count); } } finally { is.close(); } return os.toByteArray(); } } throw new IOException(); } private static String hexString( int code, int length ) { String string = Integer.toHexString(code); while(string.length() < length) { string = ("0" + string); } return string; } private FontMetric prepareFontMetric( CFFFont font ) throws IOException { byte[] afmBytes = AFMFormatter.format(font); InputStream is = new ByteArrayInputStream(afmBytes); try { AFMParser afmParser = new AFMParser(is); afmParser.parse(); FontMetric result = afmParser.getResult(); // Replace default FontBBox value with a newly computed one BoundingBox bounds = result.getFontBBox(); List numbers = Arrays.asList( Integer.valueOf((int)bounds.getLowerLeftX()), Integer.valueOf((int)bounds.getLowerLeftY()), Integer.valueOf((int)bounds.getUpperRightX()), Integer.valueOf((int)bounds.getUpperRightY()) ); font.addValueToTopDict("FontBBox", numbers); return result; } finally { is.close(); } } private Map loadOverride() throws IOException { Map result = new LinkedHashMap(); COSBase encoding = getEncoding(); if( encoding instanceof COSName ) { COSName name = (COSName)encoding; result.putAll(loadEncoding(name)); } else if( encoding instanceof COSDictionary ) { COSDictionary encodingDic = (COSDictionary)encoding; COSName baseName = (COSName)encodingDic.getDictionaryObject(COSName.BASE_ENCODING); if( baseName != null ) { result.putAll(loadEncoding(baseName)); } COSArray differences = (COSArray)encodingDic.getDictionaryObject(COSName.DIFFERENCES); if( differences != null ) { result.putAll(loadDifferences(differences)); } } return result; } private Map loadEncoding(COSName name) throws IOException { Map result = new LinkedHashMap(); Encoding encoding = EncodingManager.INSTANCE.getEncoding(name); for( Iterator> it = (encoding.getCodeToNameMap().entrySet()).iterator(); it.hasNext();) { Map.Entry entry = it.next(); result.put(entry.getKey(), (entry.getValue())); } return result; } private Map loadDifferences(COSArray differences) { Map result = new LinkedHashMap(); Integer code = null; for( int i = 0; i < differences.size(); i++) { COSBase element = differences.get(i); if( element instanceof COSNumber ) { COSNumber number = (COSNumber)element; code = Integer.valueOf(number.intValue()); } else { if( element instanceof COSName ) { COSName name = (COSName)element; result.put(code, name.getName()); code = Integer.valueOf(code.intValue() + 1); } } } return result; } private static Font prepareAwtFont( CFFFont font ) throws IOException { byte[] type1Bytes = Type1FontFormatter.format(font); InputStream is = new ByteArrayInputStream(type1Bytes); try { return Font.createFont(Font.TYPE1_FONT, is); } catch( FontFormatException ffe ) { throw new WrappedIOException(ffe); } finally { is.close(); } } /** * This class represents a PDFEncoding. * */ private static class PDFEncoding extends CFFEncoding { private PDFEncoding( CFFEncoding parent ) { Iterator parentEntries = parent.getEntries().iterator(); while(parentEntries.hasNext()) { addEntry(parentEntries.next()); } } public boolean isFontSpecific() { return true; } } /** * This class represents a PDFCharset. * */ private static class PDFCharset extends CFFCharset { private PDFCharset( CFFCharset parent ) { Iterator parentEntries = parent.getEntries().iterator(); while(parentEntries.hasNext()) { addEntry(parentEntries.next()); } } public boolean isFontSpecific() { return true; } } @Override public void clear() { super.clear(); cffFont = null; fontMetric = null; fontBBox = null; if (characterToSID != null) { characterToSID.clear(); characterToSID = null; } if (codeToSID != null) { codeToSID.clear(); codeToSID = null; } if (glyphHeights != null) { glyphHeights.clear(); glyphHeights = null; } if (glyphWidths != null) { glyphWidths.clear(); glyphWidths = null; } if (sidToCharacter != null) { sidToCharacter.clear(); sidToCharacter = null; } if (sidToName != null) { sidToName.clear(); sidToName = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java0000644000000000000000000002451012645757432027765 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.io.IOException; import org.apache.fontbox.afm.FontMetric; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.fontbox.util.BoundingBox; /** * This class represents the font descriptor when the font information * is coming from an AFM file. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class PDFontDescriptorAFM extends PDFontDescriptor { private FontMetric afm; /** * Constructor. * * @param afmFile The AFM file. */ public PDFontDescriptorAFM( FontMetric afmFile ) { afm = afmFile; } /** * Get the font name. * * @return The name of the font. */ public String getFontName() { return afm.getFontName(); } /** * This will set the font name. * * @param fontName The new name for the font. */ public void setFontName( String fontName ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * A string representing the preferred font family. * * @return The font family. */ public String getFontFamily() { return afm.getFamilyName(); } /** * This will set the font family. * * @param fontFamily The font family. */ public void setFontFamily( String fontFamily ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * The weight of the font. According to the PDF spec "possible values are * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is * more weight and appears to be more bold. * * @return The font weight. */ public float getFontWeight() { String weight = afm.getWeight(); float retval = 500; if( weight != null && weight.equalsIgnoreCase( "bold" ) ) { retval = 900; } else if( weight != null && weight.equalsIgnoreCase( "light" ) ) { retval = 100; } return retval; } /** * Set the weight of the font. * * @param fontWeight The new weight of the font. */ public void setFontWeight( float fontWeight ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * A string representing the preferred font stretch. * * @return The font stretch. */ public String getFontStretch() { return null; } /** * This will set the font stretch. * * @param fontStretch The font stretch */ public void setFontStretch( String fontStretch ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the font flags. * * @return The font flags. */ public int getFlags() { //I believe that the only flag that AFM supports is the is fixed pitch return afm.isFixedPitch() ? 1 : 0; } /** * This will set the font flags. * * @param flags The new font flags. */ public void setFlags( int flags ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the fonts bouding box. * * @return The fonts bouding box. */ public PDRectangle getFontBoundingBox() { BoundingBox box = afm.getFontBBox(); PDRectangle retval = null; if( box != null ) { retval = new PDRectangle( box ); } return retval; } /** * Set the fonts bounding box. * * @param rect The new bouding box. */ public void setFontBoundingBox( PDRectangle rect ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the italic angle for the font. * * @return The italic angle. */ public float getItalicAngle() { return afm.getItalicAngle(); } /** * This will set the italic angle for the font. * * @param angle The new italic angle for the font. */ public void setItalicAngle( float angle ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the ascent for the font. * * @return The ascent. */ public float getAscent() { return afm.getAscender(); } /** * This will set the ascent for the font. * * @param ascent The new ascent for the font. */ public void setAscent( float ascent ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the descent for the font. * * @return The descent. */ public float getDescent() { return afm.getDescender(); } /** * This will set the descent for the font. * * @param descent The new descent for the font. */ public void setDescent( float descent ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the leading for the font. * * @return The leading. */ public float getLeading() { //AFM does not support setting the leading so we will just ignore it. return 0f; } /** * This will set the leading for the font. * * @param leading The new leading for the font. */ public void setLeading( float leading ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the CapHeight for the font. * * @return The cap height. */ public float getCapHeight() { return afm.getCapHeight(); } /** * This will set the cap height for the font. * * @param capHeight The new cap height for the font. */ public void setCapHeight( float capHeight ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the x height for the font. * * @return The x height. */ public float getXHeight() { return afm.getXHeight(); } /** * This will set the x height for the font. * * @param xHeight The new x height for the font. */ public void setXHeight( float xHeight ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the stemV for the font. * * @return The stem v value. */ public float getStemV() { //afm does not have a stem v return 0; } /** * This will set the stem V for the font. * * @param stemV The new stem v for the font. */ public void setStemV( float stemV ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the stemH for the font. * * @return The stem h value. */ public float getStemH() { //afm does not have a stem h return 0; } /** * This will set the stem H for the font. * * @param stemH The new stem h for the font. */ public void setStemH( float stemH ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the average width for the font. * * @return The average width value. * * @throws IOException If there is an error calculating the average width. */ public float getAverageWidth() throws IOException { return afm.getAverageCharacterWidth(); } /** * This will set the average width for the font. * * @param averageWidth The new average width for the font. */ public void setAverageWidth( float averageWidth ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the max width for the font. * * @return The max width value. */ public float getMaxWidth() { //afm does not support max width; return 0; } /** * This will set the max width for the font. * * @param maxWidth The new max width for the font. */ public void setMaxWidth( float maxWidth ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the missing width for the font. * * @return The missing width value. */ public float getMissingWidth() { return 0; } /** * This will set the missing width for the font. * * @param missingWidth The new missing width for the font. */ public void setMissingWidth( float missingWidth ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } /** * This will get the character set for the font. * * @return The character set value. */ public String getCharSet() { return afm.getCharacterSet(); } /** * This will set the character set for the font. * * @param charSet The new character set for the font. */ public void setCharacterSet( String charSet ) { throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java0000644000000000000000000003536112645757432031475 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; /** * This class represents an implementation to the font descriptor that gets its * information from a COS Dictionary. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDFontDescriptorDictionary extends PDFontDescriptor implements COSObjectable { private COSDictionary dic; private float xHeight = Float.NEGATIVE_INFINITY; private float capHeight = Float.NEGATIVE_INFINITY; private int flags = -1; /** * Constructor. */ public PDFontDescriptorDictionary() { dic = new COSDictionary(); dic.setItem( COSName.TYPE, COSName.FONT_DESC ); } /** * Constructor. * * @param desc The wrapped COS Dictionary. */ public PDFontDescriptorDictionary( COSDictionary desc ) { dic = desc; } /** * This will get the dictionary for this object. * * @return The COS dictionary. */ public COSDictionary getCOSDictionary() { return dic; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return dic; } /** * Get the font name. * * @return The name of the font. */ public String getFontName() { String retval = null; COSName name = (COSName)dic.getDictionaryObject( COSName.FONT_NAME ); if( name != null ) { retval = name.getName(); } return retval; } /** * This will set the font name. * * @param fontName The new name for the font. */ public void setFontName( String fontName ) { COSName name = null; if( fontName != null ) { name = COSName.getPDFName( fontName ); } dic.setItem( COSName.FONT_NAME, name ); } /** * A string representing the preferred font family. * * @return The font family. */ public String getFontFamily() { String retval = null; COSString name = (COSString)dic.getDictionaryObject( COSName.FONT_FAMILY ); if( name != null ) { retval = name.getString(); } return retval; } /** * This will set the font family. * * @param fontFamily The font family. */ public void setFontFamily( String fontFamily ) { COSString name = null; if( fontFamily != null ) { name = new COSString( fontFamily ); } dic.setItem( COSName.FONT_FAMILY, name ); } /** * The weight of the font. According to the PDF spec "possible values are * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is * more weight and appears to be more bold. * * @return The font weight. */ public float getFontWeight() { return dic.getFloat( COSName.FONT_WEIGHT,0 ); } /** * Set the weight of the font. * * @param fontWeight The new weight of the font. */ public void setFontWeight( float fontWeight ) { dic.setFloat( COSName.FONT_WEIGHT, fontWeight ); } /** * A string representing the preferred font stretch. * According to the PDF Spec: * The font stretch value; it must be one of the following (ordered from * narrowest to widest): UltraCondensed, ExtraCondensed, Condensed, SemiCondensed, * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded. * * @return The stretch of the font. */ public String getFontStretch() { String retval = null; COSName name = (COSName)dic.getDictionaryObject( COSName.FONT_STRETCH ); if( name != null ) { retval = name.getName(); } return retval; } /** * This will set the font stretch. * * @param fontStretch The new stretch for the font. */ public void setFontStretch( String fontStretch ) { COSName name = null; if( fontStretch != null ) { name = COSName.getPDFName( fontStretch ); } dic.setItem( COSName.FONT_STRETCH, name ); } /** * This will get the font flags. * * @return The font flags. */ public int getFlags() { if (flags == -1) { flags = dic.getInt( COSName.FLAGS, 0 ); } return flags; } /** * This will set the font flags. * * @param flags The new font flags. */ public void setFlags( int flags ) { dic.setInt( COSName.FLAGS, flags ); this.flags = flags; } /** * This will get the fonts bounding box. * * @return The fonts bounding box. */ public PDRectangle getFontBoundingBox() { COSArray rect = (COSArray)dic.getDictionaryObject( COSName.FONT_BBOX ); PDRectangle retval = null; if( rect != null ) { retval = new PDRectangle( rect ); } return retval; } /** * Set the fonts bounding box. * * @param rect The new bouding box. */ public void setFontBoundingBox( PDRectangle rect ) { COSArray array = null; if( rect != null ) { array = rect.getCOSArray(); } dic.setItem( COSName.FONT_BBOX, array ); } /** * This will get the italic angle for the font. * * @return The italic angle. */ public float getItalicAngle() { return dic.getFloat( COSName.ITALIC_ANGLE, 0 ); } /** * This will set the italic angle for the font. * * @param angle The new italic angle for the font. */ public void setItalicAngle( float angle ) { dic.setFloat( COSName.ITALIC_ANGLE, angle ); } /** * This will get the ascent for the font. * * @return The ascent. */ public float getAscent() { return dic.getFloat( COSName.ASCENT, 0 ); } /** * This will set the ascent for the font. * * @param ascent The new ascent for the font. */ public void setAscent( float ascent ) { dic.setFloat( COSName.ASCENT, ascent ); } /** * This will get the descent for the font. * * @return The descent. */ public float getDescent() { return dic.getFloat( COSName.DESCENT, 0 ); } /** * This will set the descent for the font. * * @param descent The new descent for the font. */ public void setDescent( float descent ) { dic.setFloat( COSName.DESCENT, descent ); } /** * This will get the leading for the font. * * @return The leading. */ public float getLeading() { return dic.getFloat( COSName.LEADING, 0 ); } /** * This will set the leading for the font. * * @param leading The new leading for the font. */ public void setLeading( float leading ) { dic.setFloat( COSName.LEADING, leading ); } /** * This will get the CapHeight for the font. * * @return The cap height. */ public float getCapHeight() { if(capHeight==Float.NEGATIVE_INFINITY) { /* We observed a negative value being returned with * the Scheherazade font. PDFBOX-429 was logged for this. * We are not sure if returning the absolute value * is the correct fix, but it seems to work. */ capHeight = java.lang.Math.abs(dic.getFloat( COSName.CAP_HEIGHT, 0 )); } return capHeight; } /** * This will set the cap height for the font. * * @param capHeight The new cap height for the font. */ public void setCapHeight( float capHeight ) { dic.setFloat( COSName.CAP_HEIGHT, capHeight ); this.capHeight = capHeight; } /** * This will get the x height for the font. * * @return The x height. */ public float getXHeight() { if(xHeight==Float.NEGATIVE_INFINITY) { /* We observed a negative value being returned with * the Scheherazade font. PDFBOX-429 was logged for this. * We are not sure if returning the absolute value * is the correct fix, but it seems to work. */ xHeight = java.lang.Math.abs(dic.getFloat( COSName.XHEIGHT, 0 )); } return xHeight; } /** * This will set the x height for the font. * * @param xHeight The new x height for the font. */ public void setXHeight( float xHeight ) { dic.setFloat( COSName.XHEIGHT, xHeight ); this.xHeight = xHeight; } /** * This will get the stemV for the font. * * @return The stem v value. */ public float getStemV() { return dic.getFloat( COSName.STEM_V, 0 ); } /** * This will set the stem V for the font. * * @param stemV The new stem v for the font. */ public void setStemV( float stemV ) { dic.setFloat( COSName.STEM_V, stemV ); } /** * This will get the stemH for the font. * * @return The stem h value. */ public float getStemH() { return dic.getFloat( COSName.STEM_H, 0 ); } /** * This will set the stem H for the font. * * @param stemH The new stem h for the font. */ public void setStemH( float stemH ) { dic.setFloat( COSName.STEM_H, stemH ); } /** * This will get the average width for the font. * * @return The average width value. */ public float getAverageWidth() { return dic.getFloat( COSName.AVG_WIDTH, 0 ); } /** * This will set the average width for the font. * * @param averageWidth The new average width for the font. */ public void setAverageWidth( float averageWidth ) { dic.setFloat( COSName.AVG_WIDTH, averageWidth ); } /** * This will get the max width for the font. * * @return The max width value. */ public float getMaxWidth() { return dic.getFloat( COSName.MAX_WIDTH, 0 ); } /** * This will set the max width for the font. * * @param maxWidth The new max width for the font. */ public void setMaxWidth( float maxWidth ) { dic.setFloat( COSName.MAX_WIDTH, maxWidth ); } /** * This will get the missing width for the font. * * @return The missing width value. */ public float getMissingWidth() { return dic.getFloat( COSName.MISSING_WIDTH, 0 ); } /** * This will set the missing width for the font. * * @param missingWidth The new missing width for the font. */ public void setMissingWidth( float missingWidth ) { dic.setFloat( COSName.MISSING_WIDTH, missingWidth ); } /** * This will get the character set for the font. * * @return The character set value. */ public String getCharSet() { String retval = null; COSString name = (COSString)dic.getDictionaryObject( COSName.CHAR_SET ); if( name != null ) { retval = name.getString(); } return retval; } /** * This will set the character set for the font. * * @param charSet The new character set for the font. */ public void setCharacterSet( String charSet ) { COSString name = null; if( charSet != null ) { name = new COSString( charSet ); } dic.setItem( COSName.CHAR_SET, name ); } /** * A stream containing a Type 1 font program. * * @return A stream containing a Type 1 font program. */ public PDStream getFontFile() { PDStream retval = null; COSStream stream = (COSStream)dic.getDictionaryObject( COSName.FONT_FILE ); if( stream != null ) { retval = new PDStream( stream ); } return retval; } /** * Set the type 1 font program. * * @param type1Stream The type 1 stream. */ public void setFontFile( PDStream type1Stream ) { dic.setItem( COSName.FONT_FILE, type1Stream ); } /** * A stream containing a true type font program. * * @return A stream containing a true type font program. */ public PDStream getFontFile2() { PDStream retval = null; COSStream stream = (COSStream)dic.getDictionaryObject( COSName.FONT_FILE2 ); if( stream != null ) { retval = new PDStream( stream ); } return retval; } /** * Set the true type font program. * * @param ttfStream The true type stream. */ public void setFontFile2( PDStream ttfStream ) { dic.setItem( COSName.FONT_FILE2, ttfStream ); } /** * A stream containing a font program that is not true type or type 1. * * @return A stream containing a font program. */ public PDStream getFontFile3() { PDStream retval = null; COSStream stream = (COSStream)dic.getDictionaryObject( COSName.FONT_FILE3 ); if( stream != null ) { retval = new PDStream( stream ); } return retval; } /** * Set a stream containing a font program that is not true type or type 1. * * @param stream The font program stream. */ public void setFontFile3( PDStream stream ) { dic.setItem( COSName.FONT_FILE3, stream ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java0000644000000000000000000006674512645757432025422 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.fontbox.afm.AFMParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.afm.FontMetric; import org.apache.fontbox.cmap.CMapParser; import org.apache.fontbox.cmap.CMap; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDMatrix; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.util.ResourceLoader; import java.awt.Graphics; import java.awt.geom.AffineTransform; /** * This is the base class for all PDF fonts. * * @author Ben Litchfield * */ public abstract class PDFont implements COSObjectable { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDFont.class); /** * The cos dictionary for this font. */ protected COSDictionary font; /** * This is only used if this is a font object and it has an encoding. */ private Encoding fontEncoding = null; /** * The descriptor of the font. */ private PDFontDescriptor fontDescriptor = null; /** * The font matrix. */ protected PDMatrix fontMatrix = null; /** * This is only used if this is a font object and it has an encoding and it is * a type0 font with a cmap. */ protected CMap cmap = null; /** * The CMap holding the ToUnicode mapping. */ protected CMap toUnicodeCmap = null; private boolean hasToUnicode = false; private boolean widthsAreMissing = false; protected static Map cmapObjects = Collections.synchronizedMap( new HashMap() ); /** * A list a floats representing the widths. */ private List widths = null; /** * The static map of the default Adobe font metrics. */ private static final Map afmObjects = Collections.unmodifiableMap( getAdobeFontMetrics() ); // TODO move the Map to PDType1Font as these are the 14 Standard fonts // which are definitely Type 1 fonts private static Map getAdobeFontMetrics() { Map metrics = new HashMap(); addAdobeFontMetric( metrics, "Courier-Bold" ); addAdobeFontMetric( metrics, "Courier-BoldOblique" ); addAdobeFontMetric( metrics, "Courier" ); addAdobeFontMetric( metrics, "Courier-Oblique" ); addAdobeFontMetric( metrics, "Helvetica" ); addAdobeFontMetric( metrics, "Helvetica-Bold" ); addAdobeFontMetric( metrics, "Helvetica-BoldOblique" ); addAdobeFontMetric( metrics, "Helvetica-Oblique" ); addAdobeFontMetric( metrics, "Symbol" ); addAdobeFontMetric( metrics, "Times-Bold" ); addAdobeFontMetric( metrics, "Times-BoldItalic" ); addAdobeFontMetric( metrics, "Times-Italic" ); addAdobeFontMetric( metrics, "Times-Roman" ); addAdobeFontMetric( metrics, "ZapfDingbats" ); // PDFBOX-239 addAdobeFontMetric(metrics, "Arial", "Helvetica"); addAdobeFontMetric(metrics, "Arial,Bold", "Helvetica-Bold"); addAdobeFontMetric(metrics, "Arial,Italic", "Helvetica-Oblique"); addAdobeFontMetric(metrics, "Arial,BoldItalic", "Helvetica-BoldOblique"); return metrics; } protected static final String resourceRootCMAP = "org/apache/pdfbox/resources/cmap/"; private static final String resourceRootAFM = "org/apache/pdfbox/resources/afm/"; private static void addAdobeFontMetric( Map metrics, String name ) { addAdobeFontMetric(metrics, name, name); } private static void addAdobeFontMetric(Map metrics, String name, String filePrefix) { try { String resource = resourceRootAFM + filePrefix + ".afm"; InputStream afmStream = ResourceLoader.loadResource( resource ); if( afmStream != null ) { try { AFMParser parser = new AFMParser( afmStream ); parser.parse(); metrics.put( name, parser.getResult() ); } finally { afmStream.close(); } } } catch (Exception e) { // ignore } } /** * This will clear AFM resources that are stored statically. * This is usually not a problem unless you want to reclaim * resources for a long running process. * * SPECIAL NOTE: The font calculations are currently in COSObject, which * is where they will reside until PDFont is mature enough to take them over. * PDFont is the appropriate place for them and not in COSObject but we need font * calculations for text extraction. THIS METHOD WILL BE MOVED OR REMOVED * TO ANOTHER LOCATION IN A FUTURE VERSION OF PDFBOX. */ public static void clearResources() { cmapObjects.clear(); } /** * Constructor. */ public PDFont() { font = new COSDictionary(); font.setItem( COSName.TYPE, COSName.FONT ); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDFont( COSDictionary fontDictionary ) { font = fontDictionary; determineEncoding(); } /** * This will get the font descriptor for this font. * * @return The font descriptor for this font. * */ public PDFontDescriptor getFontDescriptor() { if(fontDescriptor == null) { COSDictionary fd = (COSDictionary)font.getDictionaryObject( COSName.FONT_DESC ); if (fd != null) { fontDescriptor = new PDFontDescriptorDictionary( fd ); } else { getAFM(); if( afm != null ) { fontDescriptor = new PDFontDescriptorAFM( afm ); } } } return fontDescriptor; } /** * This will set the font descriptor. * * @param fdDictionary The font descriptor. */ public void setFontDescriptor( PDFontDescriptorDictionary fdDictionary ) { COSDictionary dic = null; if( fdDictionary != null ) { dic = fdDictionary.getCOSDictionary(); } font.setItem( COSName.FONT_DESC, dic ); fontDescriptor = fdDictionary; } /** * Determines the encoding for the font. * This method as to be overwritten, as there are different * possibilities to define a mapping. */ protected abstract void determineEncoding(); /** * {@inheritDoc} */ public COSBase getCOSObject() { return font; } /** * This will get the font width for a character. * * @param c The character code to get the width for. * @param offset The offset into the array. * @param length The length of the data. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public abstract float getFontWidth( byte[] c, int offset, int length ) throws IOException; /** * This will get the font height for a character. * * @param c The character code to get the height for. * @param offset The offset into the array. * @param length The length of the data. * * @return The height is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public abstract float getFontHeight( byte[] c, int offset, int length ) throws IOException; /** * This will get the width of this string for this font. * * @param string The string to get the width of. * * @return The width of the string in 1000 units of text space, ie 333 567... * * @throws IOException If there is an error getting the width information. */ public float getStringWidth( String string ) throws IOException { byte[] data = string.getBytes("ISO-8859-1"); float totalWidth = 0; for( int i=0; i -1) { name = name.substring(name.indexOf("+")+1); } } else if ( baseFont instanceof COSString ) { COSString string = (COSString)baseFont; name = string.getString(); } if ( name != null ) { afm = afmObjects.get( name ); } } return afm; } private FontMetric afm = null; private COSBase encoding = null; /** * cache the {@link COSName#ENCODING} object from * the font's dictionary since it is called so often. *

* Use this method instead of *

     *   font.getDictionaryObject(COSName.ENCODING);
     * 
* @return the encoding */ protected COSBase getEncoding() { if (encoding == null) { encoding = font.getDictionaryObject( COSName.ENCODING ); } return encoding; } /** * Set the encoding object from the fonts dictionary. * @param encodingValue the given encoding. */ protected void setEncoding(COSBase encodingValue) { font.setItem( COSName.ENCODING, encodingValue ); encoding = encodingValue; } /** * Encode the given value using the CMap of the font. * * @param code the code to encode. * @param length the byte length of the given code. * @param isCIDFont indicates that the used font is a CID font. * * @return The value of the encoded character. * @throws IOException if something went wrong */ protected String cmapEncoding( int code, int length, boolean isCIDFont, CMap sourceCmap ) throws IOException { String retval = null; // there is not sourceCmap if this is a descendant font if (sourceCmap == null) { sourceCmap = cmap; } if (sourceCmap != null) { retval = sourceCmap.lookup(code, length); if (retval == null && isCIDFont) { retval = sourceCmap.lookupCID(code); } } return retval; } /** * This will perform the encoding of a character if needed. * * @param c The character to encode. * @param offset The offset into the array to get the data * @param length The number of bytes to read. * * @return The value of the encoded character. * * @throws IOException If there is an error during the encoding. */ public String encode( byte[] c, int offset, int length ) throws IOException { String retval = null; int code = getCodeFromArray( c, offset, length ); if( toUnicodeCmap != null ) { retval = cmapEncoding(code, length, false, toUnicodeCmap); } if( retval == null && cmap != null ) { retval = cmapEncoding(code, length, false, cmap); } // there is no cmap but probably an encoding with a suitable mapping if( retval == null ) { if( fontEncoding != null ) { retval = fontEncoding.getCharacter( code ); } if( retval == null && (cmap == null || length == 2)) { retval = getStringFromArray( c, offset, length ); } } return retval; } public int encodeToCID( byte[] c, int offset, int length ) throws IOException { int code = -1; if (encode(c, offset, length) != null) { code = getCodeFromArray( c, offset, length ); } return code; } private static final String[] SINGLE_CHAR_STRING = new String[256]; private static final String[][] DOUBLE_CHAR_STRING = new String[256][256]; static { for( int i=0; i<256; i++ ) { try { SINGLE_CHAR_STRING[i] = new String( new byte[] {(byte)i}, "ISO-8859-1" ); } catch (UnsupportedEncodingException e) { // Nothing should happen here LOG.error(e,e); } for( int j=0; j<256; j++ ) { try { DOUBLE_CHAR_STRING[i][j] = new String( new byte[] {(byte)i, (byte)j}, "UTF-16BE" ); } catch (UnsupportedEncodingException e) { // Nothing should happen here LOG.error(e,e); } } } } /** * Map the given byte(s) to a string. * * @param c the byte array * @param offset the offset of the byte(s) * @param length the number of bytes, usually 1 or 2 * @return the mapped string */ protected static String getStringFromArray( byte[] c, int offset, int length ) { String retval = null; if( length == 1 ) { retval = SINGLE_CHAR_STRING[(c[offset]+256)%256]; } else if( length == 2 ) { retval = DOUBLE_CHAR_STRING[(c[offset]+256)%256][(c[offset+1]+256)%256]; } return retval; } protected CMap parseCmap( String cmapRoot, InputStream cmapStream) { CMap targetCmap = null; if( cmapStream != null ) { CMapParser parser = new CMapParser(); try { targetCmap = parser.parse( cmapRoot, cmapStream ); // limit the cache to external CMaps if (cmapRoot != null) { cmapObjects.put( targetCmap.getName(), targetCmap ); } } catch (IOException exception) { LOG.error("An error occurs while reading a CMap", exception); } } return targetCmap; } /** * The will set the encoding for this font. * * @param enc The font encoding. */ public void setFontEncoding( Encoding enc ) { fontEncoding = enc; } /** * This will get or create the encoder. * * @return The encoding to use. */ public Encoding getFontEncoding() { return fontEncoding; } /** * This will always return "Font" for fonts. * * @return The type of object that this is. */ public String getType() { return font.getNameAsString( COSName.TYPE ); } // Memorized values to avoid repeated dictionary lookups private String subtype = null; private boolean type1Font; private boolean type3Font; private boolean trueTypeFont; private boolean type0Font; /** * This will get the subtype of font, Type1, Type3, ... * * @return The type of font that this is. */ public String getSubType() { if (subtype == null) { subtype = font.getNameAsString( COSName.SUBTYPE ); type1Font = "Type1".equals(subtype); trueTypeFont = "TrueType".equals(subtype); type0Font = "Type0".equals(subtype); type3Font = "Type3".equals(subtype); } return subtype; } /** * Determines if the font is a type 1 font. * @return returns true if the font is a type 1 font */ protected boolean isType1Font() { getSubType(); return type1Font; } /** * Determines if the font is a type 3 font. * * @return returns true if the font is a type 3 font */ public boolean isType3Font() { getSubType(); return type3Font; } /** * Determines if the font is a type 0 font. * @return returns true if the font is a type 0 font */ protected boolean isType0Font() { getSubType(); return type0Font; } private boolean isTrueTypeFont() { getSubType(); return trueTypeFont; } /** * Determines if the font is a symbolic font. * * @return returns true if the font is a symbolic font */ public boolean isSymbolicFont() { if (getFontDescriptor() != null) { return getFontDescriptor().isSymbolic(); } return false; } /** * The PostScript name of the font. * * @return The postscript name of the font. */ public String getBaseFont() { return font.getNameAsString( COSName.BASE_FONT ); } /** * Set the PostScript name of the font. * * @param baseFont The postscript name for the font. */ public void setBaseFont( String baseFont ) { font.setName( COSName.BASE_FONT, baseFont ); } /** * The code for the first char or -1 if there is none. * * @return The code for the first character. */ public int getFirstChar() { return font.getInt( COSName.FIRST_CHAR, -1 ); } /** * Set the first character this font supports. * * @param firstChar The first character. */ public void setFirstChar( int firstChar ) { font.setInt( COSName.FIRST_CHAR, firstChar ); } /** * The code for the last char or -1 if there is none. * * @return The code for the last character. */ public int getLastChar() { return font.getInt( COSName.LAST_CHAR, -1 ); } /** * Set the last character this font supports. * * @param lastChar The last character. */ public void setLastChar( int lastChar ) { font.setInt( COSName.LAST_CHAR, lastChar ); } /** * The widths of the characters. This will be null for the standard 14 fonts. * * @return The widths of the characters. * */ public List getWidths() { if (widths == null && !widthsAreMissing) { COSArray array = (COSArray)font.getDictionaryObject( COSName.WIDTHS ); if (array != null) { widths = COSArrayList.convertFloatCOSArrayToList(array); } else { widthsAreMissing = true; } } return widths; } /** * Set the widths of the characters code. * * @param widthsList The widths of the character codes. */ public void setWidths(List widthsList) { widths = widthsList; font.setItem( COSName.WIDTHS, COSArrayList.converterToCOSArray( widths ) ); } /** * This will get the matrix that is used to transform glyph space to * text space. By default there are 1000 glyph units to 1 text space * unit, but type3 fonts can use any value. * * Note:If this is a type3 font then it can be modified via the PDType3Font.setFontMatrix, otherwise this * is a read-only property. * * @return The matrix to transform from glyph space to text space. */ public PDMatrix getFontMatrix() { if (fontMatrix == null) { COSArray array = (COSArray)font.getDictionaryObject( COSName.FONT_MATRIX ); if( array == null ) { array = new COSArray(); array.add( new COSFloat( 0.001f ) ); array.add( COSInteger.ZERO ); array.add( COSInteger.ZERO ); array.add( new COSFloat( 0.001f ) ); array.add( COSInteger.ZERO ); array.add( COSInteger.ZERO ); } fontMatrix = new PDMatrix(array); } return fontMatrix; } /** * This will get the fonts bounding box. * * @return The fonts bounding box. * * @throws IOException If there is an error getting the bounding box. */ public abstract PDRectangle getFontBoundingBox() throws IOException; /** * {@inheritDoc} */ public boolean equals( Object other ) { return other instanceof PDFont && ((PDFont)other).getCOSObject() == this.getCOSObject(); } /** * {@inheritDoc} */ public int hashCode() { return this.getCOSObject().hashCode(); } /** * Determines the width of the given character. * @param charCode the code of the given character * @return the width of the character */ public float getFontWidth( int charCode ) { float width = -1; int firstChar = getFirstChar(); int lastChar = getLastChar(); if (charCode >= firstChar && charCode <= lastChar) { // maybe the font doesn't provide any widths if (!widthsAreMissing) { getWidths(); if (widths != null) { width = widths.get(charCode-firstChar).floatValue(); } } } else { PDFontDescriptor fd = getFontDescriptor(); if (fd instanceof PDFontDescriptorDictionary) { width = fd.getMissingWidth(); } } return width; } /** * Determines if a font as a ToUnicode entry. * @return true if the font has a ToUnicode entry */ protected boolean hasToUnicode() { return hasToUnicode; } /** * Sets hasToUnicode to the given value. * @param hasToUnicodeValue the given value for hasToUnicode */ protected void setHasToUnicode(boolean hasToUnicodeValue) { hasToUnicode = hasToUnicodeValue; } /** * Determines the width of the space character. * @return the width of the space character */ public abstract float getSpaceWidth(); /** * Returns the toUnicode mapping if present. * * @return the CMap representing the toUnicode mapping */ public CMap getToUnicodeCMap() { return toUnicodeCmap; } /** * Calling this will release all cached information. */ public void clear() { } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java0000644000000000000000000001510412645757432026323 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * This is implementation of the Type0 Font. See PDFBOX-605 * for the related improvement issue. * * @author Ben Litchfield * @version $Revision: 1.9 $ */ public class PDType0Font extends PDSimpleFont { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDType0Font.class); private COSArray descendantFontArray; private PDFont descendantFont; private COSDictionary descendantFontDictionary; private Font awtFont; /** * Constructor. */ public PDType0Font() { super(); font.setItem(COSName.SUBTYPE, COSName.TYPE0); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF * specification. */ public PDType0Font(COSDictionary fontDictionary) { super(fontDictionary); descendantFontDictionary = (COSDictionary) getDescendantFonts().getObject(0); if (descendantFontDictionary != null) { try { descendantFont = PDFontFactory.createFont(descendantFontDictionary); } catch (IOException exception) { LOG.error("Error while creating the descendant font!"); } } } /** * {@inheritDoc} */ @Override public Font getawtFont() throws IOException { if (awtFont == null) { if (descendantFont != null) { awtFont = ((PDSimpleFont) descendantFont).getawtFont(); if (awtFont != null) { setIsFontSubstituted(((PDSimpleFont) descendantFont).isFontSubstituted()); /* * Fix Oracle JVM Crashes. * Tested with Oracle JRE 6.0_45-b06 and 7.0_21-b11 */ awtFont.canDisplay(1); } } if (awtFont == null) { awtFont = FontManager.getStandardFont(); LOG.info("Using font " + awtFont.getName() + " instead of " + descendantFont.getFontDescriptor().getFontName()); setIsFontSubstituted(true); } } return awtFont; } /** * This will get the fonts bounding box. * * @return The fonts bounding box. * * @throws IOException If there is an error getting the bounding box. */ @Override public PDRectangle getFontBoundingBox() throws IOException { throw new RuntimeException("Not yet implemented"); } /** * This will get the font width for a character. * * @param c The character code to get the width for. * @param offset The offset into the array. * @param length The length of the data. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public float getFontWidth(byte[] c, int offset, int length) throws IOException { return descendantFont.getFontWidth(c, offset, length); } /** * This will get the font height for a character. * * @param c The character code to get the height for. * @param offset The offset into the array. * @param length The length of the data. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ @Override public float getFontHeight(byte[] c, int offset, int length) throws IOException { return descendantFont.getFontHeight(c, offset, length); } /** * This will get the average font width for all characters. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ @Override public float getAverageFontWidth() throws IOException { return descendantFont.getAverageFontWidth(); } private COSArray getDescendantFonts() { if (descendantFontArray == null) { descendantFontArray = (COSArray) font.getDictionaryObject(COSName.DESCENDANT_FONTS); } return descendantFontArray; } /** * {@inheritDoc} */ @Override public float getFontWidth(int charCode) { return descendantFont.getFontWidth(charCode); } @Override public String encode(byte[] c, int offset, int length) throws IOException { String retval = null; if (hasToUnicode()) { retval = super.encode(c, offset, length); } if (retval == null) { int result = cmap.lookupCID(c, offset, length); if (result != -1) { retval = descendantFont.cmapEncoding(result, 2, true, null); } } return retval; } /** * * Provides the descendant font. * * @return the descendant font. * */ public PDFont getDescendantFont() { return descendantFont; } @Override public void clear() { super.clear(); descendantFontArray = null; if (descendantFont != null) { descendantFont.clear(); descendantFont = null; } descendantFontDictionary = null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java0000644000000000000000000004322612645757432026561 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import org.apache.fontbox.afm.FontMetric; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.encoding.DictionaryEncoding; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.encoding.EncodingManager; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.common.PDRectangle; import static org.apache.pdfbox.pdmodel.font.PDFont.resourceRootCMAP; import org.apache.pdfbox.util.ResourceLoader; /** * This class contains implementation details of the simple pdf fonts. * * @author Ben Litchfield * @version $Revision: 1.18 $ */ public abstract class PDSimpleFont extends PDFont { private final HashMap mFontSizes = new HashMap(128); private float avgFontWidth = 0.0f; private float avgFontHeight = 0.0f; private float fontWidthOfSpace = -1f; private static final byte[] SPACE_BYTES = { (byte)32 }; /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDSimpleFont.class); /** * Constructor. */ public PDSimpleFont() { super(); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDSimpleFont( COSDictionary fontDictionary ) { super( fontDictionary ); } /** * Looks up, creates, returns the AWT Font. * * @return returns the awt font to bes used for rendering * @throws IOException if something went wrong. */ public Font getawtFont() throws IOException { LOG.error("Not yet implemented:" + getClass().getName() ); return null; } /** * {@inheritDoc} */ public void drawString( String string, int[] codePoints, Graphics g, float fontSize, AffineTransform at, float x, float y ) throws IOException { Font awtFont = getawtFont(); FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true); GlyphVector glyphs = null; boolean useCodepoints = codePoints != null && isType0Font(); PDFont descendantFont = useCodepoints ? ((PDType0Font)this).getDescendantFont() : null; // symbolic fonts may trigger the same fontmanager.so/dll error as described below if (useCodepoints && !descendantFont.getFontDescriptor().isSymbolic()) { PDCIDFontType2Font cid2Font = null; if (descendantFont instanceof PDCIDFontType2Font) { cid2Font = (PDCIDFontType2Font)descendantFont; } if((cid2Font != null && cid2Font.hasCIDToGIDMap()) || isFontSubstituted) { // we still have to use the string if a CIDToGIDMap is used glyphs = awtFont.createGlyphVector(frc, string); } else { glyphs = awtFont.createGlyphVector(frc, codePoints); } } else { // mdavis - fix fontmanager.so/dll on sun.font.FileFont.getGlyphImage // for font with bad cmaps? // Type1 fonts are not affected as they don't have cmaps if (!isType1Font() && awtFont.canDisplayUpTo(string) != -1) { LOG.warn("Changing font on <" + string + "> from <" + awtFont.getName() + "> to the default font"); awtFont = Font.decode(null).deriveFont(1f); } glyphs = awtFont.createGlyphVector(frc, string); } Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); writeFont(g2d, at, x, y, glyphs); } /** * This will get the font height for a character. * * @param c The character code to get the width for. * @param offset The offset into the array. * @param length The length of the data. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public float getFontHeight( byte[] c, int offset, int length ) throws IOException { // maybe there is already a precalculated value if (avgFontHeight > 0) { return avgFontHeight; } float retval = 0; FontMetric metric = getAFM(); if( metric != null ) { int code = getCodeFromArray( c, offset, length ); Encoding encoding = getFontEncoding(); String characterName = encoding.getName( code ); retval = metric.getCharacterHeight( characterName ); } else { PDFontDescriptor desc = getFontDescriptor(); if( desc != null ) { // the following values are all more or less accurate // at least all are average values. Maybe we'll find // another way to get those value for every single glyph // in the future if needed PDRectangle fontBBox = desc.getFontBoundingBox(); if (fontBBox != null) { retval = fontBBox.getHeight() / 2; } if( retval == 0 ) { retval = desc.getCapHeight(); } if( retval == 0 ) { retval = desc.getAscent(); } if( retval == 0 ) { retval = desc.getXHeight(); if (retval > 0) { retval -= desc.getDescent(); } } avgFontHeight = retval; } } return retval; } /** * This will get the font width for a character. * * @param c The character code to get the width for. * @param offset The offset into the array. * @param length The length of the data. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public float getFontWidth( byte[] c, int offset, int length ) throws IOException { int code = getCodeFromArray( c, offset, length ); Float fontWidth = mFontSizes.get(code); if (fontWidth == null) { fontWidth = getFontWidth(code); if (fontWidth <= 0) { //hmm should this be in PDType1Font?? fontWidth = getFontWidthFromAFMFile( code ); } mFontSizes.put(code, fontWidth); } return fontWidth; } /** * This will get the average font width for all characters. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public float getAverageFontWidth() throws IOException { float average = 0.0f; //AJW if (avgFontWidth != 0.0f) { average = avgFontWidth; } else { float totalWidth = 0.0f; float characterCount = 0.0f; COSArray widths = (COSArray)font.getDictionaryObject( COSName.WIDTHS ); if( widths != null ) { for( int i=0; i 0 ) { totalWidth += fontWidth.floatValue(); characterCount += 1; } } } if( totalWidth > 0 ) { average = totalWidth / characterCount; } else { average = getAverageFontWidthFromAFMFile(); } avgFontWidth = average; } return average; } /** * This will get the ToUnicode object. * * @return The ToUnicode object. */ public COSBase getToUnicode() { return font.getDictionaryObject( COSName.TO_UNICODE ); } /** * This will set the ToUnicode object. * * @param unicode The unicode object. */ public void setToUnicode( COSBase unicode ) { font.setItem( COSName.TO_UNICODE, unicode ); } /** * This will get the fonts bounding box. * * @return The fonts bouding box. * * @throws IOException If there is an error getting the bounding box. */ public PDRectangle getFontBoundingBox() throws IOException { return getFontDescriptor().getFontBoundingBox(); } /** * This will draw a string on a canvas using the font. * * @param g2d The graphics to draw onto. * @param at The transformation matrix with all information for scaling and shearing of the font. * @param x The x coordinate to draw at. * @param y The y coordinate to draw at. * @param glyphs The GlyphVector containing the glyphs to be drawn. * */ protected void writeFont(final Graphics2D g2d, final AffineTransform at, final float x, final float y, final GlyphVector glyphs) { // check if we have a rotation if (!at.isIdentity()) { for (int i = 0; i < glyphs.getNumGlyphs(); i++) { glyphs.setGlyphTransform(i, at); } } g2d.drawGlyphVector(glyphs, x, y); } /** * {@inheritDoc} */ protected void determineEncoding() { String cmapName = null; COSName encodingName = null; COSBase encoding = getEncoding(); Encoding fontEncoding = null; if (encoding != null) { if (encoding instanceof COSName) { if (cmap == null) { encodingName = (COSName)encoding; cmap = cmapObjects.get( encodingName.getName() ); if (cmap == null) { cmapName = encodingName.getName(); } } if (cmap == null && cmapName != null) { try { fontEncoding = EncodingManager.INSTANCE.getEncoding(encodingName); } catch(IOException exception) { LOG.debug("Debug: Could not find encoding for " + encodingName ); } } } else if(encoding instanceof COSStream ) { if (cmap == null) { COSStream encodingStream = (COSStream)encoding; try { InputStream is = encodingStream.getUnfilteredStream(); cmap = parseCmap(null, is); IOUtils.closeQuietly(is); } catch(IOException exception) { LOG.error("Error: Could not parse the embedded CMAP" ); } } } else if (encoding instanceof COSDictionary) { try { fontEncoding = new DictionaryEncoding((COSDictionary)encoding); } catch(IOException exception) { LOG.error("Error: Could not create the DictionaryEncoding" ); } } } setFontEncoding(fontEncoding); extractToUnicodeEncoding(); if (cmap == null && cmapName != null) { InputStream cmapStream = null; try { // look for a predefined CMap with the given name cmapStream = ResourceLoader.loadResource(resourceRootCMAP + cmapName); if (cmapStream != null) { cmap = parseCmap(resourceRootCMAP, cmapStream); if (cmap == null && encodingName == null) { LOG.error("Error: Could not parse predefined CMAP file for '" + cmapName + "'"); } } else { LOG.debug("Debug: '" + cmapName + "' isn't a predefined map, most likely it's embedded in the pdf itself."); } } catch(IOException exception) { LOG.error("Error: Could not find predefined CMAP file for '" + cmapName + "'" ); } finally { IOUtils.closeQuietly(cmapStream); } } } private void extractToUnicodeEncoding() { COSName encodingName = null; String cmapName = null; COSBase toUnicode = getToUnicode(); if( toUnicode != null ) { setHasToUnicode(true); if ( toUnicode instanceof COSStream ) { try { InputStream is = ((COSStream) toUnicode).getUnfilteredStream(); toUnicodeCmap = parseCmap(resourceRootCMAP, is); IOUtils.closeQuietly(is); } catch(IOException exception) { LOG.error("Error: Could not load embedded ToUnicode CMap" ); } } else if ( toUnicode instanceof COSName) { encodingName = (COSName)toUnicode; toUnicodeCmap = cmapObjects.get( encodingName.getName() ); if (toUnicodeCmap == null) { cmapName = encodingName.getName(); String resourceName = resourceRootCMAP + cmapName; try { toUnicodeCmap = parseCmap( resourceRootCMAP, ResourceLoader.loadResource( resourceName )); } catch(IOException exception) { LOG.error("Error: Could not find predefined ToUnicode CMap file for '" + cmapName + "'" ); } if( toUnicodeCmap == null) { LOG.error("Error: Could not parse predefined ToUnicode CMap file for '" + cmapName + "'" ); } } } } } private boolean isFontSubstituted = false; /** * This will get the value for isFontSubstituted, which indicates * if the font was substituted due to a problem with the embedded one. * * @return true if the font was substituted */ protected boolean isFontSubstituted() { return isFontSubstituted; } /** * This will set the value for isFontSubstituted. * * @param isSubstituted true if the font was substituted */ protected void setIsFontSubstituted(boolean isSubstituted) { isFontSubstituted = isSubstituted; } /** * {@inheritDoc} */ public float getSpaceWidth() { if (fontWidthOfSpace == -1f) { COSBase toUnicode = getToUnicode(); try { if (toUnicode != null) { int spaceMapping = toUnicodeCmap.getSpaceMapping(); if (spaceMapping > -1) { fontWidthOfSpace = getFontWidth(spaceMapping); } } else { fontWidthOfSpace = getFontWidth( SPACE_BYTES, 0, 1 ); } // use the average font width as fall back if (fontWidthOfSpace <= 0) { fontWidthOfSpace = getAverageFontWidth(); } } catch (Exception e) { LOG.error("Can't determine the width of the space character using 250 as default", e); fontWidthOfSpace = 250f; } } return fontWidthOfSpace; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java0000644000000000000000000002741212645757432025726 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.util.ResourceLoader; /** * This is implementation for the CIDFontType0/CIDFontType2 Fonts. * * @author Ben Litchfield * @version $Revision: 1.11 $ */ public abstract class PDCIDFont extends PDSimpleFont { /** * Log instance. */ private static final Log log = LogFactory.getLog(PDCIDFont.class); private Map widthCache = null; private long defaultWidth = 0; /** * Constructor. */ public PDCIDFont() { super(); } /** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. */ public PDCIDFont( COSDictionary fontDictionary ) { super( fontDictionary ); extractWidths(); } /** * This will get the fonts bouding box. * * @return The fonts bouding box. * * @throws IOException If there is an error getting the font bounding box. */ public PDRectangle getFontBoundingBox() throws IOException { throw new RuntimeException( "getFontBoundingBox(): Not yet implemented" ); } /** * This will get the default width. The default value for the default width is 1000. * * @return The default width for the glyphs in this font. */ public long getDefaultWidth() { if (defaultWidth == 0) { COSNumber number = (COSNumber)font.getDictionaryObject( COSName.DW); if( number != null ) { defaultWidth = number.intValue(); } else { defaultWidth = 1000; } } return defaultWidth; } /** * This will set the default width for the glyphs of this font. * * @param dw The default width. */ public void setDefaultWidth( long dw ) { defaultWidth = dw; font.setLong( COSName.DW, dw ); } /** * This will get the font width for a character. * * @param c The character code to get the width for. * @param offset The offset into the array. * @param length The length of the data. * * @return The width is in 1000 unit of text space, ie 333 or 777 * * @throws IOException If an error occurs while parsing. */ public float getFontWidth( byte[] c, int offset, int length ) throws IOException { float retval = getDefaultWidth(); int code = getCodeFromArray( c, offset, length ); Float widthFloat = widthCache.get( code ); if( widthFloat != null ) { retval = widthFloat.floatValue(); } return retval; } private void extractWidths() { if (widthCache == null) { widthCache = new HashMap(); COSArray widths = (COSArray)font.getDictionaryObject( COSName.W ); if( widths != null ) { int size = widths.size(); int counter = 0; while (counter < size) { COSNumber firstCode = (COSNumber)widths.getObject( counter++ ); COSBase next = widths.getObject( counter++ ); if( next instanceof COSArray ) { COSArray array = (COSArray)next; int startRange = firstCode.intValue(); int arraySize = array.size(); for (int i=0; i 0 ) { totalWidths += rangeWidth.floatValue(); characterCount += 1; } } } } float average = totalWidths / characterCount; if( average <= 0 ) { average = defaultWidth; } return average; } /** * {@inheritDoc} */ public float getFontWidth( int charCode ) { float width = getDefaultWidth(); if (widthCache.containsKey(charCode)) { width = widthCache.get(charCode); } return width; } /** * Extract the CIDSystemInfo. * @return the CIDSystemInfo as String */ private String getCIDSystemInfo() { String cidSystemInfo = null; COSDictionary cidsysteminfo = (COSDictionary)font.getDictionaryObject(COSName.CIDSYSTEMINFO); if (cidsysteminfo != null) { String ordering = cidsysteminfo.getString(COSName.ORDERING); String registry = cidsysteminfo.getString(COSName.REGISTRY); int supplement = cidsysteminfo.getInt(COSName.SUPPLEMENT); cidSystemInfo = registry + "-" + ordering+ "-" + supplement; } return cidSystemInfo; } @Override protected void determineEncoding() { String cidSystemInfo = getCIDSystemInfo(); if (cidSystemInfo != null) { if (cidSystemInfo.contains("Identity")) { cidSystemInfo = "Identity-H"; } else if (cidSystemInfo.startsWith("Adobe-UCS-")) { cidSystemInfo = "Adobe-Identity-UCS"; } else { cidSystemInfo = cidSystemInfo.substring(0,cidSystemInfo.lastIndexOf("-"))+"-UCS2"; } cmap = cmapObjects.get( cidSystemInfo ); if (cmap == null) { InputStream cmapStream = null; try { // look for a predefined CMap with the given name cmapStream = ResourceLoader.loadResource(resourceRootCMAP + cidSystemInfo); if (cmapStream != null) { cmap = parseCmap(resourceRootCMAP, cmapStream); if (cmap == null) { log.error("Error: Could not parse predefined CMAP file for '" + cidSystemInfo + "'"); } } else { log.debug("Debug: '" + cidSystemInfo + "' isn't a predefined CMap, most likely it's embedded in the pdf itself."); } } catch(IOException exception) { log.error("Error: Could not find predefined CMAP file for '" + cidSystemInfo + "'" ); } finally { IOUtils.closeQuietly(cmapStream); } } } else { super.determineEncoding(); } } @Override public String encode(byte[] c, int offset, int length) throws IOException { String result = null; if (cmap != null) { result = cmapEncoding(getCodeFromArray( c, offset, length ), length, true, cmap); } else { result = super.encode(c, offset, length); } return result; } @Override public void clear() { super.clear(); if (widthCache != null) { widthCache.clear(); widthCache = null; } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java0000644000000000000000000001110412645757432026725 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.font; import java.io.IOException; import java.util.Map; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This will create the correct type of font based on information in the dictionary. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public class PDFontFactory { /** * private constructor, should only use static methods in this class. */ private PDFontFactory() { } /** * Logger instance. */ private static final Log LOG = LogFactory.getLog(PDFontFactory.class); /** * This will create the correct font based on information in the dictionary. * * @param dic The populated dictionary. * * @param fontCache A Map to cache already created fonts * * @return The corrent implementation for the font. * * @throws IOException If the dictionary is not valid. * * @deprecated due to some side effects font caching is no longer supported, * use {@link #createFont(COSDictionary)} instead */ public static PDFont createFont(COSDictionary dic, Map fontCache) throws IOException { return createFont(dic); } /** * This will create the correct font based on information in the dictionary. * * @param dic The populated dictionary. * * @return The corrent implementation for the font. * * @throws IOException If the dictionary is not valid. */ public static PDFont createFont( COSDictionary dic ) throws IOException { PDFont retval = null; COSName type = (COSName)dic.getDictionaryObject( COSName.TYPE ); if( type != null && !COSName.FONT.equals( type ) ) { LOG.error( "Cannot create font if /Type is not /Font. Actual=" +type ); } COSName subType = (COSName)dic.getDictionaryObject( COSName.SUBTYPE ); if (subType == null) { throw new IOException( "Cannot create font as /SubType is not set." ); } if( subType.equals( COSName.TYPE1) ) { retval = new PDType1Font( dic ); } else if( subType.equals( COSName.MM_TYPE1 ) ) { retval = new PDMMType1Font( dic ); } else if( subType.equals( COSName.TRUE_TYPE ) ) { retval = new PDTrueTypeFont( dic ); } else if( subType.equals( COSName.TYPE3 ) ) { retval = new PDType3Font( dic ); } else if( subType.equals( COSName.TYPE0 ) ) { retval = new PDType0Font( dic ); } else if( subType.equals( COSName.CID_FONT_TYPE0 ) ) { retval = new PDCIDFontType0Font( dic ); } else if( subType.equals( COSName.CID_FONT_TYPE2 ) ) { retval = new PDCIDFontType2Font( dic ); } else { // assuming Type 1 font (see PDFBOX-1988) because it seems that Adobe Reader does this // however, we may need more sophisticated logic perhaps looking at the FontFile LOG.warn( "Invalid font subtype '" + subType.getName() + "'" ); return new PDType1Font( dic ); } return retval; } /** * Create a default font * * @return a default font * @throws IOException if something goes wrong */ public static PDFont createDefaultFont() throws IOException { COSDictionary dict = new COSDictionary(); dict.setItem(COSName.TYPE, COSName.FONT); dict.setItem (COSName.SUBTYPE, COSName.TYPE1); dict.setString(COSName.BASE_FONT, "Arial"); return createFont(dict); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentNameDictionary.java0000644000000000000000000001307712645757432030141 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This class holds all of the name trees that are available at the document level. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDDocumentNameDictionary implements COSObjectable { private COSDictionary nameDictionary; private PDDocumentCatalog catalog; /** * Constructor. * * @param cat The document catalog that this dictionary is part of. */ public PDDocumentNameDictionary( PDDocumentCatalog cat ) { COSBase names = cat.getCOSDictionary().getDictionaryObject(COSName.NAMES); if (names != null) { nameDictionary = (COSDictionary)names; } else { nameDictionary = new COSDictionary(); cat.getCOSDictionary().setItem(COSName.NAMES, nameDictionary); } catalog = cat; } /** * Constructor. * * @param cat The document that this dictionary is part of. * @param names The names dictionary. */ public PDDocumentNameDictionary( PDDocumentCatalog cat, COSDictionary names ) { catalog = cat; nameDictionary = names; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return nameDictionary; } /** * Convert this standard java object to a COS object. * * @return The cos dictionary for this object. */ public COSDictionary getCOSDictionary() { return nameDictionary; } /** * Get the destination named tree node. The value in this name tree will be PDDestination * objects. * * @return The destination name tree node. */ public PDDestinationNameTreeNode getDests() { PDDestinationNameTreeNode dests = null; COSDictionary dic = (COSDictionary)nameDictionary.getDictionaryObject( COSName.DESTS ); //The document catalog also contains the Dests entry sometimes //so check there as well. if( dic == null ) { dic = (COSDictionary)catalog.getCOSDictionary().getDictionaryObject( COSName.DESTS ); } if( dic != null ) { dests = new PDDestinationNameTreeNode( dic ); } return dests; } /** * Set the named destinations that are associated with this document. * * @param dests The destination names. */ public void setDests( PDDestinationNameTreeNode dests ) { nameDictionary.setItem( COSName.DESTS, dests ); //The dests can either be in the document catalog or in the //names dictionary, PDFBox will just maintain the one in the //names dictionary for now unless there is a reason to do //something else. //clear the potentially out of date Dests reference. catalog.getCOSDictionary().setItem( COSName.DESTS, (COSObjectable)null); } /** * Get the embedded files named tree node. The value in this name tree will be PDComplexFileSpecification * objects. * * @return The embedded files name tree node. */ public PDEmbeddedFilesNameTreeNode getEmbeddedFiles() { PDEmbeddedFilesNameTreeNode retval = null; COSDictionary dic = (COSDictionary)nameDictionary.getDictionaryObject( COSName.EMBEDDED_FILES ); if( dic != null ) { retval = new PDEmbeddedFilesNameTreeNode( dic ); } return retval; } /** * Set the named embedded files that are associated with this document. * * @param ef The new embedded files */ public void setEmbeddedFiles( PDEmbeddedFilesNameTreeNode ef ) { nameDictionary.setItem( COSName.EMBEDDED_FILES, ef ); } /** * Get the document level javascript entries. The value in this name tree will be PDTextStream. * * @return The document level named javascript. */ public PDJavascriptNameTreeNode getJavaScript() { PDJavascriptNameTreeNode retval = null; COSDictionary dic = (COSDictionary)nameDictionary.getDictionaryObject( COSName.JAVA_SCRIPT ); if( dic != null ) { retval = new PDJavascriptNameTreeNode( dic ); } return retval; } /** * Set the named javascript entries that are associated with this document. * * @param js The new Javascript entries. */ public void setJavascript( PDJavascriptNameTreeNode js ) { nameDictionary.setItem( COSName.JAVA_SCRIPT, js ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/0000755000000000000000000000000012645757432024627 5ustar rootroot././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardDecryptionMaterial.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardDecryptionMaterial.j0000644000000000000000000000357712645757432032276 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; /** * * Represents the necessary information to decrypt a document protected by * the standard security handler (password protection). * * This is only composed of a password. * * The following example shows how to decrypt a document protected with * the standard security handler: * *
 *  PDDocument doc = PDDocument.load(in);
 *  StandardDecryptionMaterial dm = new StandardDecryptionMaterial("password");
 *  doc.openProtection(dm);
 *  
* * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * * @version $Revision: 1.2 $ */ public class StandardDecryptionMaterial extends DecryptionMaterial { private String password = null; /** * Create a new standard decryption material with the given password. * * @param pwd The password. */ public StandardDecryptionMaterial(String pwd) { password = pwd; } /** * Returns the password. * * @return The password used to decrypt the document. */ public String getPassword() { return password; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeyRecipient.java0000644000000000000000000000400212645757432031220 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.security.cert.X509Certificate; /** * Represents a recipient in the public key protection policy. * * @see PublicKeyProtectionPolicy * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * * @version $Revision: 1.2 $ */ public class PublicKeyRecipient { private X509Certificate x509; private AccessPermission permission; /** * Returns the X509 certificate of the recipient. * * @return The X509 certificate */ public X509Certificate getX509() { return x509; } /** * Set the X509 certificate of the recipient. * * @param aX509 The X509 certificate */ public void setX509(X509Certificate aX509) { this.x509 = aX509; } /** * Returns the access permission granted to the recipient. * * @return The access permission object. */ public AccessPermission getPermission() { return permission; } /** * Set the access permission granted to the recipient. * * @param permissions The permission to set. */ public void setPermission(AccessPermission permissions) { this.permission = permissions; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/ProtectionPolicy.java0000644000000000000000000000421612645757432031003 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; /** * This class represents the protection policy to apply to a document. * * Objects implementing this abstract class can be passed to the protect method of PDDocument * to protect a document. * * @see org.apache.pdfbox.pdmodel.PDDocument#protect(ProtectionPolicy) * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * @version $Revision: 1.3 $ */ public abstract class ProtectionPolicy { private static final int DEFAULT_KEY_LENGTH = 40; private int encryptionKeyLength = DEFAULT_KEY_LENGTH; /** * set the length in (bits) of the secret key that will be * used to encrypt document data. * The default value is 40 bits, which provides a low security level * but is compatible with old versions of Acrobat Reader. * * @param l the length in bits (must be 40 or 128) */ public void setEncryptionKeyLength(int l) { if(l!=40 && l!=128) { throw new RuntimeException("Invalid key length '" + l + "' value must be 40 or 128!"); } encryptionKeyLength = l; } /** * Get the length of the secrete key that will be used to encrypt * document data. * * @return The length (in bits) of the encryption key. */ public int getEncryptionKeyLength() { return encryptionKeyLength; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/package.html0000644000000000000000000000201112645757432027102 0ustar rootroot The encryption package will handle the PDF document security handlers and the functionality of pluggable security handlers. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java0000644000000000000000000003177112645757432032107 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; /** * This class is a specialized view of the encryption dictionary of a PDF document. * It contains a low level dictionary (COSDictionary) and provides the methods to * manage its fields. * * The available fields are the ones who are involved by standard security handler * and public key security handler. * * @author Ben Litchfield * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * * @version $Revision: 1.7 $ */ public class PDEncryptionDictionary { /** * See PDF Reference 1.4 Table 3.13. */ public static final int VERSION0_UNDOCUMENTED_UNSUPPORTED = 0; /** * See PDF Reference 1.4 Table 3.13. */ public static final int VERSION1_40_BIT_ALGORITHM = 1; /** * See PDF Reference 1.4 Table 3.13. */ public static final int VERSION2_VARIABLE_LENGTH_ALGORITHM = 2; /** * See PDF Reference 1.4 Table 3.13. */ public static final int VERSION3_UNPUBLISHED_ALGORITHM = 3; /** * See PDF Reference 1.4 Table 3.13. */ public static final int VERSION4_SECURITY_HANDLER = 4; /** * The default security handler. */ public static final String DEFAULT_NAME = "Standard"; /** * The default length for the encryption key. */ public static final int DEFAULT_LENGTH = 40; /** * The default version, according to the PDF Reference. */ public static final int DEFAULT_VERSION = VERSION0_UNDOCUMENTED_UNSUPPORTED; /** * COS encryption dictionary. */ protected COSDictionary encryptionDictionary = null; /** * creates a new empty encryption dictionary. */ public PDEncryptionDictionary() { encryptionDictionary = new COSDictionary(); } /** * creates a new encryption dictionary from the low level dictionary provided. * @param d the low level dictionary that will be managed by the newly created object */ public PDEncryptionDictionary(COSDictionary d) { encryptionDictionary = d; } /** * This will get the dictionary associated with this encryption dictionary. * * @return The COS dictionary that this object wraps. */ public COSDictionary getCOSDictionary() { return encryptionDictionary; } /** * Sets the filter entry of the encryption dictionary. * * @param filter The filter name. */ public void setFilter(String filter) { encryptionDictionary.setItem( COSName.FILTER, COSName.getPDFName( filter ) ); } /** * Get the name of the filter. * * @return The filter name contained in this encryption dictionary. */ public String getFilter() { return encryptionDictionary.getNameAsString( COSName.FILTER ); } /** * Get the name of the subfilter. * * @return The subfilter name contained in this encryption dictionary. */ public String getSubFilter() { return encryptionDictionary.getNameAsString( COSName.SUB_FILTER ); } /** * Set the subfilter entry of the encryption dictionary. * * @param subfilter The value of the subfilter field. */ public void setSubFilter(String subfilter) { encryptionDictionary.setName( COSName.SUB_FILTER, subfilter ); } /** * This will set the V entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.13.

* Note: This value is used to decrypt the pdf document. If you change this when * the document is encrypted then decryption will fail!. * * @param version The new encryption version. */ public void setVersion(int version) { encryptionDictionary.setInt( COSName.V, version ); } /** * This will return the V entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.13. * * @return The encryption version to use. */ public int getVersion() { return encryptionDictionary.getInt( COSName.V, 0 ); } /** * This will set the number of bits to use for the encryption algorithm. * * @param length The new key length. */ public void setLength(int length) { encryptionDictionary.setInt(COSName.LENGTH, length); } /** * This will return the Length entry of the encryption dictionary.

* The length in bits for the encryption algorithm. This will return a multiple of 8. * * @return The length in bits for the encryption algorithm */ public int getLength() { return encryptionDictionary.getInt( COSName.LENGTH, 40 ); } /** * This will set the R entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.14.

* * Note: This value is used to decrypt the pdf document. If you change this when * the document is encrypted then decryption will fail!. * * @param revision The new encryption version. */ public void setRevision(int revision) { encryptionDictionary.setInt( COSName.R, revision ); } /** * This will return the R entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.14. * * @return The encryption revision to use. */ public int getRevision() { return encryptionDictionary.getInt( COSName.R, DEFAULT_VERSION ); } /** * This will set the O entry in the standard encryption dictionary. * * @param o A 32 byte array or null if there is no owner key. * * @throws IOException If there is an error setting the data. */ public void setOwnerKey(byte[] o) throws IOException { COSString owner = new COSString(); owner.append( o ); encryptionDictionary.setItem( COSName.O, owner ); } /** * This will get the O entry in the standard encryption dictionary. * * @return A 32 byte array or null if there is no owner key. * * @throws IOException If there is an error accessing the data. */ public byte[] getOwnerKey() throws IOException { byte[] o = null; COSString owner = (COSString)encryptionDictionary.getDictionaryObject( COSName.O ); if( owner != null ) { o = owner.getBytes(); } return o; } /** * This will set the U entry in the standard encryption dictionary. * * @param u A 32 byte array. * * @throws IOException If there is an error setting the data. */ public void setUserKey(byte[] u) throws IOException { COSString user = new COSString(); user.append( u ); encryptionDictionary.setItem( COSName.U, user ); } /** * This will get the U entry in the standard encryption dictionary. * * @return A 32 byte array or null if there is no user key. * * @throws IOException If there is an error accessing the data. */ public byte[] getUserKey() throws IOException { byte[] u = null; COSString user = (COSString)encryptionDictionary.getDictionaryObject( COSName.U ); if( user != null ) { u = user.getBytes(); } return u; } /** * This will set the permissions bit mask. * * @param permissions The new permissions bit mask */ public void setPermissions(int permissions) { encryptionDictionary.setInt( COSName.P, permissions ); } /** * This will get the permissions bit mask. * * @return The permissions bit mask. */ public int getPermissions() { return encryptionDictionary.getInt( COSName.P, 0 ); } /** * Will get the EncryptMetaData dictionary info. * * @return true if EncryptMetaData is explicitly set to false (the default is true) */ public boolean isEncryptMetaData() { // default is true (see 7.6.3.2 Standard Encryption Dictionary PDF 32000-1:2008) boolean encryptMetaData = true; COSBase value = encryptionDictionary.getDictionaryObject(COSName.ENCRYPT_META_DATA); if (value instanceof COSBoolean) { encryptMetaData = ((COSBoolean)value).getValue(); } return encryptMetaData; } /** * This will set the Recipients field of the dictionary. This field contains an array * of string. * @param recipients the array of bytes arrays to put in the Recipients field. * @throws IOException If there is an error setting the data. */ public void setRecipients(byte[][] recipients) throws IOException { COSArray array = new COSArray(); for(int i=0; i
* The length in bits for the crypt filter algorithm. This will return a multiple of 8. * * @return The length in bits for the encryption algorithm */ public int getLength() { return cryptFilterDictionary.getInt( COSName.LENGTH, 40 ); } /** * This will set the crypt filter method. * Allowed values are: NONE, V2, AESV2 * * @param cfm name of the crypt filter method. * * @throws IOException If there is an error setting the data. */ public void setCryptFilterMethod(COSName cfm) throws IOException { cryptFilterDictionary.setItem( COSName.CFM, cfm ); } /** * This will return the crypt filter method. * Allowed values are: NONE, V2, AESV2 * * @return the name of the crypt filter method. * * @throws IOException If there is an error accessing the data. */ public COSName getCryptFilterMethod() throws IOException { return (COSName)cryptFilterDictionary.getDictionaryObject( COSName.CFM ); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/BadSecurityHandlerException.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/BadSecurityHandlerException.0000644000000000000000000000310712645757432032224 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; /** * This exception can be thrown by the SecurityHandlersManager class when * a document required an unimplemented security handler to be opened. * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * @version $Revision: 1.2 $ */ public class BadSecurityHandlerException extends Exception { /** * Default Constructor. */ public BadSecurityHandlerException() { super(); } /** * Constructor. * * @param e A sub exception. */ public BadSecurityHandlerException(Exception e) { super(e); } /** * Constructor. * * @param msg Message describing exception. */ public BadSecurityHandlerException(String msg) { super(msg); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryptionManager.java0000644000000000000000000001004712645757432031345 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * This class will handle loading of the different security handlers. * * See PDF Reference 1.4 section "3.5 Encryption" * * @author Ben Litchfield * @version $Revision: 1.7 $ * @deprecated Made deprecated by the new security layer of PDFBox. Use SecurityHandlers instead. */ public class PDEncryptionManager { private static Map handlerMap = Collections.synchronizedMap( new HashMap() ); static { registerSecurityHandler( PDStandardEncryption.FILTER_NAME, PDStandardEncryption.class ); } private PDEncryptionManager() { } /** * This will allow the user to register new security handlers when unencrypting a * document. * * @param filterName As described in the encryption dictionary. * @param handlerClass A subclass of PDEncryptionDictionary that has a constructor that takes * a COSDictionary. */ public static void registerSecurityHandler( String filterName, Class handlerClass ) { handlerMap.put( COSName.getPDFName( filterName ), handlerClass ); } /** * This will get the correct security handler for the encryption dictionary. * * @param dictionary The encryption dictionary. * * @return An implementation of PDEncryptionDictionary(PDStandardEncryption for most cases). * * @throws IOException If a security handler could not be found. */ public static PDEncryptionDictionary getEncryptionDictionary( COSDictionary dictionary ) throws IOException { Object retval = null; if( dictionary != null ) { COSName filter = (COSName)dictionary.getDictionaryObject( COSName.FILTER ); Class handlerClass = (Class)handlerMap.get( filter ); if( handlerClass == null ) { throw new IOException( "No handler for security handler '" + filter.getName() + "'" ); } else { try { Constructor ctor = handlerClass.getConstructor( new Class[] { COSDictionary.class } ); retval = ctor.newInstance( new Object[] { dictionary } ); } catch( NoSuchMethodException e ) { throw new IOException( e.getMessage() ); } catch( InstantiationException e ) { throw new IOException( e.getMessage() ); } catch( IllegalAccessException e ) { throw new IOException( e.getMessage() ); } catch( InvocationTargetException e ) { throw new IOException( e.getMessage() ); } } } return (PDEncryptionDictionary)retval; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java0000644000000000000000000005473012645757432030610 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.encryption.ARCFour; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.exceptions.WrappedIOException; import org.apache.pdfbox.pdmodel.PDDocument; /** * This class represents a security handler as described in the PDF specifications. A security handler is responsible of * documents protection. * * @author Ben Litchfield * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * */ public abstract class SecurityHandler { /** * CONSTANTS. */ private static final Log LOG = LogFactory.getLog(SecurityHandler.class); private static final int DEFAULT_KEY_LENGTH = 40; /* * See 7.6.2, page 58, PDF 32000-1:2008 */ private static final byte[] AES_SALT = { (byte) 0x73, (byte) 0x41, (byte) 0x6c, (byte) 0x54 }; /** * The value of V field of the Encryption dictionary. */ protected int version; /** * The length of the secret key used to encrypt the document. */ protected int keyLength = DEFAULT_KEY_LENGTH; /** * The encryption key that will used to encrypt / decrypt. */ protected byte[] encryptionKey; /** * The document whose security is handled by this security handler. */ protected PDDocument document; /** * The RC4 implementation used for cryptographic functions. */ protected ARCFour rc4 = new ARCFour(); /** * indicates if the Metadata have to be decrypted of not */ protected boolean decryptMetadata; private Set objects = new HashSet(); private Set potentialSignatures = new HashSet(); /** * If true, AES will be used. */ private boolean aes; /** * The access permission granted to the current user for the document. These permissions are computed during * decryption and are in read only mode. */ protected AccessPermission currentAccessPermission = null; /** * Prepare the document for encryption. * * @param doc * The document that will be encrypted. * * @throws CryptographyException * If there is an error while preparing. * @throws IOException * If there is an error with the document. */ public abstract void prepareDocumentForEncryption(PDDocument doc) throws CryptographyException, IOException; /** * Prepares everything to decrypt the document. * * If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, this method is called from there. Only if * decryption of single objects is needed this should be called instead. * * @param encDictionary * encryption dictionary, can be retrieved via {@link PDDocument#getEncryptionDictionary()} * @param documentIDArray * document id which is returned via {@link COSDocument#getDocumentID()} * @param decryptionMaterial * Information used to decrypt the document. * * @throws IOException * If there is an error accessing data. * @throws CryptographyException * If there is an error with decryption. */ public abstract void prepareForDecryption(PDEncryptionDictionary encDictionary, COSArray documentIDArray, DecryptionMaterial decryptionMaterial) throws CryptographyException, IOException; /** * Prepare the document for decryption. * * @param doc * The document to decrypt. * @param mat * Information required to decrypt the document. * @throws CryptographyException * If there is an error while preparing. * @throws IOException * If there is an error with the document. */ public abstract void decryptDocument(PDDocument doc, DecryptionMaterial mat) throws CryptographyException, IOException; /** * This method must be called by an implementation of this class to really proceed to decryption. * * @throws IOException * If there is an error in the decryption. * @throws CryptographyException * If there is an error in the decryption. */ protected void proceedDecryption() throws IOException, CryptographyException { COSDictionary trailer = document.getDocument().getTrailer(); COSArray fields = (COSArray) trailer.getObjectFromPath("Root/AcroForm/Fields"); // We need to collect all the signature dictionaries, for some // reason the 'Contents' entry of signatures is not really encrypted if (fields != null) { for (int i = 0; i < fields.size(); i++) { COSDictionary field = (COSDictionary) fields.getObject(i); if (field != null) { addDictionaryAndSubDictionary(potentialSignatures, field); } else { throw new IOException("Could not decypt document, object not found."); } } } List allObjects = document.getDocument().getObjects(); Iterator objectIter = allObjects.iterator(); COSDictionary encryptionDict = document.getEncryptionDictionary().getCOSDictionary(); while (objectIter.hasNext()) { COSObject nextObj = objectIter.next(); COSBase nextCOSBase = nextObj.getObject(); if (nextCOSBase != encryptionDict) { decryptObject(nextObj); } } document.setEncryptionDictionary(null); } private void addDictionaryAndSubDictionary(Set set, COSDictionary dic) { if (dic != null) // in case dictionary is part of object stream we have null value here { set.add(dic); COSArray kids = (COSArray) dic.getDictionaryObject(COSName.KIDS); for (int i = 0; kids != null && i < kids.size(); i++) { addDictionaryAndSubDictionary(set, (COSDictionary) kids.getObject(i)); } COSBase value = dic.getDictionaryObject(COSName.V); if (value instanceof COSDictionary) { addDictionaryAndSubDictionary(set, (COSDictionary) value); } } } /** * Encrypt a set of data. * * @param objectNumber * The data object number. * @param genNumber * The data generation number. * @param data * The data to encrypt. * @param output * The output to write the encrypted data to. * @throws CryptographyException * If there is an error during the encryption. * @throws IOException * If there is an error reading the data. * @deprecated While this works fine for RC4 encryption, it will never decrypt AES data You should use * encryptData(objectNumber, genNumber, data, output, decrypt) which can do everything. This function is * just here for compatibility reasons and will be removed in the future. */ public void encryptData(long objectNumber, long genNumber, InputStream data, OutputStream output) throws CryptographyException, IOException { // default to encrypting since the function is named "encryptData" encryptData(objectNumber, genNumber, data, output, false); } /** * Encrypt a set of data. * * @param objectNumber * The data object number. * @param genNumber * The data generation number. * @param data * The data to encrypt. * @param output * The output to write the encrypted data to. * @param decrypt * true to decrypt the data, false to encrypt it * * @throws CryptographyException * If there is an error during the encryption. * @throws IOException * If there is an error reading the data. */ public void encryptData(long objectNumber, long genNumber, InputStream data, OutputStream output, boolean decrypt) throws CryptographyException, IOException { if (aes && !decrypt) { throw new IllegalArgumentException("AES encryption is not yet implemented."); } byte[] newKey = new byte[encryptionKey.length + 5]; System.arraycopy(encryptionKey, 0, newKey, 0, encryptionKey.length); // PDF 1.4 reference pg 73 // step 1 // we have the reference // step 2 newKey[newKey.length - 5] = (byte) (objectNumber & 0xff); newKey[newKey.length - 4] = (byte) ((objectNumber >> 8) & 0xff); newKey[newKey.length - 3] = (byte) ((objectNumber >> 16) & 0xff); newKey[newKey.length - 2] = (byte) (genNumber & 0xff); newKey[newKey.length - 1] = (byte) ((genNumber >> 8) & 0xff); // step 3 byte[] digestedKey = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(newKey); if (aes) { md.update(AES_SALT); } digestedKey = md.digest(); } catch (NoSuchAlgorithmException e) { throw new CryptographyException(e); } // step 4 int length = Math.min(newKey.length, 16); byte[] finalKey = new byte[length]; System.arraycopy(digestedKey, 0, finalKey, 0, length); if (aes) { byte[] iv = new byte[16]; data.read(iv); try { Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey aesKey = new SecretKeySpec(finalKey, "AES"); IvParameterSpec ips = new IvParameterSpec(iv); decryptCipher.init(decrypt ? Cipher.DECRYPT_MODE : Cipher.ENCRYPT_MODE, aesKey, ips); byte[] buffer = new byte[256]; for (int n = 0; -1 != (n = data.read(buffer));) { output.write(decryptCipher.update(buffer, 0, n)); } output.write(decryptCipher.doFinal()); } catch (InvalidKeyException e) { throw new WrappedIOException(e.getMessage(), e); } catch (InvalidAlgorithmParameterException e) { throw new WrappedIOException(e.getMessage(), e); } catch (NoSuchAlgorithmException e) { throw new WrappedIOException(e.getMessage(), e); } catch (NoSuchPaddingException e) { throw new WrappedIOException(e.getMessage(), e); } catch (IllegalBlockSizeException e) { throw new WrappedIOException(e.getMessage(), e); } catch (BadPaddingException e) { throw new WrappedIOException(e.getMessage(), e); } } else { rc4.setKey(finalKey); rc4.write(data, output); } output.flush(); } /** * This will decrypt an object in the document. * * @param object * The object to decrypt. * * @throws CryptographyException * If there is an error decrypting the stream. * @throws IOException * If there is an error getting the stream data. */ private void decryptObject(COSObject object) throws CryptographyException, IOException { long objNum = object.getObjectNumber().intValue(); long genNum = object.getGenerationNumber().intValue(); COSBase base = object.getObject(); decrypt(base, objNum, genNum); } /** * This will dispatch to the correct method. * * @param obj * The object to decrypt. * @param objNum * The object number. * @param genNum * The object generation Number. * * @throws CryptographyException * If there is an error decrypting the stream. * @throws IOException * If there is an error getting the stream data. */ private void decrypt(COSBase obj, long objNum, long genNum) throws CryptographyException, IOException { if (!objects.contains(obj)) { objects.add(obj); if (obj instanceof COSString) { decryptString((COSString) obj, objNum, genNum); } else if (obj instanceof COSStream) { decryptStream((COSStream) obj, objNum, genNum); } else if (obj instanceof COSDictionary) { decryptDictionary((COSDictionary) obj, objNum, genNum); } else if (obj instanceof COSArray) { decryptArray((COSArray) obj, objNum, genNum); } } } /** * This will decrypt a stream. * * @param stream * The stream to decrypt. * @param objNum * The object number. * @param genNum * The object generation number. * * @throws CryptographyException * If there is an error getting the stream. * @throws IOException * If there is an error getting the stream data. */ public void decryptStream(COSStream stream, long objNum, long genNum) throws CryptographyException, IOException { COSBase type = stream.getDictionaryObject(COSName.TYPE); if (!decryptMetadata && COSName.METADATA.equals(type)) { return; } // "The cross-reference stream shall not be encrypted" if (COSName.XREF.equals(type)) { return; } decryptDictionary(stream, objNum, genNum); InputStream encryptedStream = stream.getFilteredStream(); encryptData(objNum, genNum, encryptedStream, stream.createFilteredStream(), true /* decrypt */); } /** * This will encrypt a stream, but not the dictionary as the dictionary is encrypted by visitFromString() in * COSWriter and we don't want to encrypt it twice. * * @param stream * The stream to decrypt. * @param objNum * The object number. * @param genNum * The object generation number. * * @throws CryptographyException * If there is an error getting the stream. * @throws IOException * If there is an error getting the stream data. */ public void encryptStream(COSStream stream, long objNum, long genNum) throws CryptographyException, IOException { InputStream encryptedStream = stream.getFilteredStream(); encryptData(objNum, genNum, encryptedStream, stream.createFilteredStream(), false /* encrypt */); } /** * This will decrypt a dictionary. * * @param dictionary * The dictionary to decrypt. * @param objNum * The object number. * @param genNum * The object generation number. * * @throws CryptographyException * If there is an error decrypting the document. * @throws IOException * If there is an error creating a new string. */ private void decryptDictionary(COSDictionary dictionary, long objNum, long genNum) throws CryptographyException, IOException { COSBase type = dictionary.getDictionaryObject(COSName.TYPE); boolean isSignature = COSName.SIG.equals(type) || COSName.DOC_TIME_STAMP.equals(type); for (Map.Entry entry : dictionary.entrySet()) { if (isSignature && COSName.CONTENTS.equals(entry.getKey())) { // do not decrypt the signature contents string continue; } COSBase value = entry.getValue(); // within a dictionary only the following kind of COS objects have to be decrypted if (value instanceof COSString || value instanceof COSStream || value instanceof COSArray || value instanceof COSDictionary) { // if we are a signature dictionary and contain a Contents entry then // we don't decrypt it. if (!(entry.getKey().equals(COSName.CONTENTS) && value instanceof COSString && potentialSignatures .contains(dictionary))) { decrypt(value, objNum, genNum); } } } } /** * This will encrypt a string. * * @param string * the string to encrypt. * @param objNum * The object number. * @param genNum * The object generation number. * * @throws IOException * If an error occurs writing the new string. */ public void encryptString(COSString string, long objNum, long genNum) throws CryptographyException, IOException { ByteArrayInputStream data = new ByteArrayInputStream(string.getBytes()); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); encryptData(objNum, genNum, data, buffer, false /* decrypt */); string.reset(); string.append(buffer.toByteArray()); } /** * This will decrypt a string. * * @param string * the string to decrypt. * @param objNum * The object number. * @param genNum * The object generation number. * * @throws CryptographyException * If an error occurs during decryption. * @throws IOException * If an error occurs writing the new string. */ public void decryptString(COSString string, long objNum, long genNum) throws CryptographyException, IOException { ByteArrayInputStream bais = new ByteArrayInputStream(string.getBytes()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { encryptData(objNum, genNum, bais, baos, true /* decrypt */); string.reset(); string.append(baos.toByteArray()); } catch (WrappedIOException ex) { LOG.error("Failed to decrypt COSString of length " + string.getBytes().length + " in object " + objNum + ": " + ex.getMessage()); } } /** * This will decrypt an array. * * @param array * The array to decrypt. * @param objNum * The object number. * @param genNum * The object generation number. * * @throws CryptographyException * If an error occurs during decryption. * @throws IOException * If there is an error accessing the data. */ public void decryptArray(COSArray array, long objNum, long genNum) throws CryptographyException, IOException { for (int i = 0; i < array.size(); i++) { decrypt(array.get(i), objNum, genNum); } } /** * Getter of the property keyLength. * * @return Returns the keyLength. */ public int getKeyLength() { return keyLength; } /** * Setter of the property keyLength. * * @param keyLen * The keyLength to set. */ public void setKeyLength(int keyLen) { this.keyLength = keyLen; } /** * Returns the access permissions that were computed during document decryption. The returned object is in read only * mode. * * @return the access permissions or null if the document was not decrypted. */ public AccessPermission getCurrentAccessPermission() { return currentAccessPermission; } /** * True if AES is used for encryption and decryption. * * @return true if AEs is used */ public boolean isAES() { return aes; } /** * Set to true if AES for encryption and decryption should be used. * * @param aesValue * if true AES will be used * */ public void setAES(boolean aesValue) { aes = aesValue; } /** * Returns whether a protection policy has been set. * * @return true if a protection policy has been set. */ public abstract boolean hasProtectionPolicy(); }pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDStandardEncryption.java0000644000000000000000000003012512645757432031532 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSString; import java.io.IOException; /** * This class holds information that is related to the standard PDF encryption. * * See PDF Reference 1.4 section "3.5 Encryption" * * @author Ben Litchfield * @version $Revision: 1.7 $ * @deprecated Made deprecated by the new security layer of PDFBox. Use SecurityHandlers instead. */ public class PDStandardEncryption extends PDEncryptionDictionary { /** * The 'Filter' name for this security handler. */ public static final String FILTER_NAME = "Standard"; /** * The default revision of one is not specified. */ public static final int DEFAULT_REVISION = 3; /** * Encryption revision 2. */ public static final int REVISION2 = 2; /** * Encryption revision 3. */ public static final int REVISION3 = 3; /** * Encryption revision 4. */ public static final int REVISION4 = 4; /** * The default set of permissions which is to allow all. */ public static final int DEFAULT_PERMISSIONS = 0xFFFFFFFF ^ 3;//bits 0 & 1 need to be zero private static final int PRINT_BIT = 3; private static final int MODIFICATION_BIT = 4; private static final int EXTRACT_BIT = 5; private static final int MODIFY_ANNOTATIONS_BIT = 6; private static final int FILL_IN_FORM_BIT = 9; private static final int EXTRACT_FOR_ACCESSIBILITY_BIT = 10; private static final int ASSEMBLE_DOCUMENT_BIT = 11; private static final int DEGRADED_PRINT_BIT = 12; /** * Default constructor that uses Version 2, Revision 3, 40 bit encryption, * all permissions allowed. */ public PDStandardEncryption() { super(); encryptionDictionary.setItem( COSName.FILTER, COSName.getPDFName( FILTER_NAME ) ); setVersion( PDEncryptionDictionary.VERSION1_40_BIT_ALGORITHM ); setRevision( PDStandardEncryption.REVISION2 ); setPermissions( DEFAULT_PERMISSIONS ); } /** * Constructor from existing dictionary. * * @param dict The existing encryption dictionary. */ public PDStandardEncryption( COSDictionary dict ) { super( dict ); } /** * This will return the R entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.14. * * @return The encryption revision to use. */ public int getRevision() { int revision = DEFAULT_VERSION; COSNumber cosRevision = (COSNumber)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "R" ) ); if( cosRevision != null ) { revision = cosRevision.intValue(); } return revision; } /** * This will set the R entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.14.

* * Note: This value is used to decrypt the pdf document. If you change this when * the document is encrypted then decryption will fail!. * * @param revision The new encryption version. */ public void setRevision( int revision ) { encryptionDictionary.setInt( COSName.getPDFName( "R" ), revision ); } /** * This will get the O entry in the standard encryption dictionary. * * @return A 32 byte array or null if there is no owner key. */ public byte[] getOwnerKey() { byte[] o = null; COSString owner = (COSString)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "O" ) ); if( owner != null ) { o = owner.getBytes(); } return o; } /** * This will set the O entry in the standard encryption dictionary. * * @param o A 32 byte array or null if there is no owner key. * * @throws IOException If there is an error setting the data. */ public void setOwnerKey( byte[] o ) throws IOException { COSString owner = new COSString(); owner.append( o ); encryptionDictionary.setItem( COSName.getPDFName( "O" ), owner ); } /** * This will get the U entry in the standard encryption dictionary. * * @return A 32 byte array or null if there is no user key. */ public byte[] getUserKey() { byte[] u = null; COSString user = (COSString)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "U" ) ); if( user != null ) { u = user.getBytes(); } return u; } /** * This will set the U entry in the standard encryption dictionary. * * @param u A 32 byte array. * * @throws IOException If there is an error setting the data. */ public void setUserKey( byte[] u ) throws IOException { COSString user = new COSString(); user.append( u ); encryptionDictionary.setItem( COSName.getPDFName( "U" ), user ); } /** * This will get the permissions bit mask. * * @return The permissions bit mask. */ public int getPermissions() { int permissions = 0; COSInteger p = (COSInteger)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "P" ) ); if( p != null ) { permissions = p.intValue(); } return permissions; } /** * This will set the permissions bit mask. * * @param p The new permissions bit mask */ public void setPermissions( int p ) { encryptionDictionary.setInt( COSName.getPDFName( "P" ), p ); } private boolean isPermissionBitOn( int bit ) { return (getPermissions() & (1 << (bit-1))) != 0; } private boolean setPermissionBit( int bit, boolean value ) { int permissions = getPermissions(); if( value ) { permissions = permissions | (1 << (bit-1)); } else { permissions = permissions & (0xFFFFFFFF ^ (1 << (bit-1))); } setPermissions( permissions ); return (getPermissions() & (1 << (bit-1))) != 0; } /** * This will tell if the user can print. * * @return true If supplied with the user password they are allowed to print. */ public boolean canPrint() { return isPermissionBitOn( PRINT_BIT ); } /** * Set if the user can print. * * @param allowPrinting A boolean determining if the user can print. */ public void setCanPrint( boolean allowPrinting ) { setPermissionBit( PRINT_BIT, allowPrinting ); } /** * This will tell if the user can modify contents of the document. * * @return true If supplied with the user password they are allowed to modify the document */ public boolean canModify() { return isPermissionBitOn( MODIFICATION_BIT ); } /** * Set if the user can modify the document. * * @param allowModifications A boolean determining if the user can modify the document. */ public void setCanModify( boolean allowModifications ) { setPermissionBit( MODIFICATION_BIT, allowModifications ); } /** * This will tell if the user can extract text and images from the PDF document. * * @return true If supplied with the user password they are allowed to extract content * from the PDF document */ public boolean canExtractContent() { return isPermissionBitOn( EXTRACT_BIT ); } /** * Set if the user can extract content from the document. * * @param allowExtraction A boolean determining if the user can extract content * from the document. */ public void setCanExtractContent( boolean allowExtraction ) { setPermissionBit( EXTRACT_BIT, allowExtraction ); } /** * This will tell if the user can add/modify text annotations, fill in interactive forms fields. * * @return true If supplied with the user password they are allowed to modify annotations. */ public boolean canModifyAnnotations() { return isPermissionBitOn( MODIFY_ANNOTATIONS_BIT ); } /** * Set if the user can modify annotations. * * @param allowAnnotationModification A boolean determining if the user can modify annotations. */ public void setCanModifyAnnotations( boolean allowAnnotationModification ) { setPermissionBit( MODIFY_ANNOTATIONS_BIT, allowAnnotationModification ); } /** * This will tell if the user can fill in interactive forms. * * @return true If supplied with the user password they are allowed to fill in form fields. */ public boolean canFillInForm() { return isPermissionBitOn( FILL_IN_FORM_BIT ); } /** * Set if the user can fill in interactive forms. * * @param allowFillingInForm A boolean determining if the user can fill in interactive forms. */ public void setCanFillInForm( boolean allowFillingInForm ) { setPermissionBit( FILL_IN_FORM_BIT, allowFillingInForm ); } /** * This will tell if the user can extract text and images from the PDF document * for accessibility purposes. * * @return true If supplied with the user password they are allowed to extract content * from the PDF document */ public boolean canExtractForAccessibility() { return isPermissionBitOn( EXTRACT_FOR_ACCESSIBILITY_BIT ); } /** * Set if the user can extract content from the document for accessibility purposes. * * @param allowExtraction A boolean determining if the user can extract content * from the document. */ public void setCanExtractForAccessibility( boolean allowExtraction ) { setPermissionBit( EXTRACT_FOR_ACCESSIBILITY_BIT, allowExtraction ); } /** * This will tell if the user can insert/rotate/delete pages. * * @return true If supplied with the user password they are allowed to extract content * from the PDF document */ public boolean canAssembleDocument() { return isPermissionBitOn( ASSEMBLE_DOCUMENT_BIT ); } /** * Set if the user can insert/rotate/delete pages. * * @param allowAssembly A boolean determining if the user can assemble the document. */ public void setCanAssembleDocument( boolean allowAssembly ) { setPermissionBit( ASSEMBLE_DOCUMENT_BIT, allowAssembly ); } /** * This will tell if the user can print the document in a degraded format. * * @return true If supplied with the user password they are allowed to print the * document in a degraded format. */ public boolean canPrintDegraded() { return isPermissionBitOn( DEGRADED_PRINT_BIT ); } /** * Set if the user can print the document in a degraded format. * * @param allowAssembly A boolean determining if the user can print the * document in a degraded format. */ public void setCanPrintDegraded( boolean allowAssembly ) { setPermissionBit( DEGRADED_PRINT_BIT, allowAssembly ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/DecryptionMaterial.java0000644000000000000000000000223012645757432031266 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; /** * This class represents data required to decrypt PDF documents. This can * be a password for standard security or a X509 certificate with a private * key for public key security. * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * @version $Revision: 1.2 $ */ public abstract class DecryptionMaterial { } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeyProtectionPolicy.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeyProtectionPolicy.ja0000644000000000000000000001053412645757432032264 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Iterator; /** * This class represents the protection policy to use to protect * a document with the public key security handler as described * in the PDF specification 1.6 p104. * * PDF documents are encrypted so that they can be decrypted by * one or more recipients. Each recipient have its own access permission. * * The following code sample shows how to protect a document using * the public key security handler. In this code sample, doc is * a PDDocument object. * *
 * PublicKeyProtectionPolicy policy = new PublicKeyProtectionPolicy();
 * PublicKeyRecipient recip = new PublicKeyRecipient();
 * AccessPermission ap = new AccessPermission();
 * ap.setCanModify(false);
 * recip.setPermission(ap);
 *
 * // load the recipient's certificate
 * InputStream inStream = new FileInputStream(certificate_path);
 * CertificateFactory cf = CertificateFactory.getInstance("X.509");
 * X509Certificate certificate = (X509Certificate)cf.generateCertificate(inStream);
 * inStream.close();
 *
 * recip.setX509(certificate); // set the recipient's certificate
 * policy.addRecipient(recip);
 * policy.setEncryptionKeyLength(128); // the document will be encrypted with 128 bits secret key
 * doc.protect(policy);
 * doc.save(out);
 * 
* * * @see org.apache.pdfbox.pdmodel.PDDocument#protect(ProtectionPolicy) * @see AccessPermission * @see PublicKeyRecipient * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * * @version $Revision: 1.2 $ */ public class PublicKeyProtectionPolicy extends ProtectionPolicy { /** * The list of recipients. */ private ArrayList recipients = null; /** * The X509 certificate used to decrypt the current document. */ private X509Certificate decryptionCertificate; /** * Constructor for encryption. Just creates an empty recipients list. */ public PublicKeyProtectionPolicy() { recipients = new ArrayList(); } /** * Adds a new recipient to the recipients list. * * @param r A new recipient. */ public void addRecipient(PublicKeyRecipient r) { recipients.add(r); } /** * Removes a recipient from the recipients list. * * @param r The recipient to remove. * * @return true If a recipient was found and removed. */ public boolean removeRecipient(PublicKeyRecipient r) { return recipients.remove(r); } /** * Returns an iterator to browse the list of recipients. Object * found in this iterator are PublicKeyRecipient. * * @return The recipients list iterator. */ public Iterator getRecipientsIterator() { return recipients.iterator(); } /** * Getter of the property decryptionCertificate. * * @return Returns the decryptionCertificate. */ public X509Certificate getDecryptionCertificate() { return decryptionCertificate; } /** * Setter of the property decryptionCertificate. * * @param aDecryptionCertificate The decryption certificate to set. */ public void setDecryptionCertificate(X509Certificate aDecryptionCertificate) { this.decryptionCertificate = aDecryptionCertificate; } /** * Returns the number of recipients. * * @return The number of recipients. */ public int getRecipientsNumber() { return recipients.size(); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeyDecryptionMaterial.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeyDecryptionMaterial.0000644000000000000000000001231012645757432032234 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.X509Certificate; import java.util.Enumeration; /** * This class holds necessary information to decrypt a PDF document * protected by the public key security handler. * * To decrypt such a document, we need: *
    *
  • a valid X509 certificate which correspond to one of the recipient of the document
  • *
  • the private key corresponding to this certificate *
  • the password to decrypt the private key if necessary
  • *
* * Objects of this class can be used with the openProtection method of PDDocument. * * The following example shows how to decrypt a document using a PKCS#12 certificate * (typically files with a pfx extension). * *
 * PDDocument doc = PDDocument.load(document_path);
 * KeyStore ks = KeyStore.getInstance("PKCS12");
 * ks.load(new FileInputStream(certificate_path), password.toCharArray());
 * PublicKeyDecryptionMaterial dm = new PublicKeyDecryptionMaterial(ks, null, password);
 * doc.openProtection(dm);
 * 
* * In this code sample certificate_path contains the path to the PKCS#12 certificate. * * @see org.apache.pdfbox.pdmodel.PDDocument#openProtection(DecryptionMaterial) * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * @version $Revision: 1.2 $ */ public class PublicKeyDecryptionMaterial extends DecryptionMaterial { private String password = null; private KeyStore keyStore = null; private String alias = null; /** * Create a new public key decryption material. * * @param keystore The keystore were the private key and the certificate are * @param a The alias of the private key and the certificate. * If the keystore contains only 1 entry, this parameter can be left null. * @param pwd The password to extract the private key from the keystore. */ public PublicKeyDecryptionMaterial(KeyStore keystore, String a, String pwd) { keyStore = keystore; alias = a; password = pwd; } /** * Returns the certificate contained in the keystore. * * @return The certificate that will be used to try to open the document. * * @throws KeyStoreException If there is an error accessing the certificate. */ public X509Certificate getCertificate() throws KeyStoreException { if(keyStore.size() == 1) { Enumeration aliases = keyStore.aliases(); String keyStoreAlias = (String)aliases.nextElement(); return (X509Certificate)keyStore.getCertificate(keyStoreAlias); } else { if(keyStore.containsAlias(alias)) { return (X509Certificate)keyStore.getCertificate(alias); } throw new KeyStoreException("the keystore does not contain the given alias"); } } /** * Returns the password given by the user and that will be used * to open the private key. * * @return The password. */ public String getPassword() { return password; } /** * returns The private key that will be used to open the document protection. * @return The private key. * @throws KeyStoreException If there is an error accessing the key. */ public Key getPrivateKey() throws KeyStoreException { try { if(keyStore.size() == 1) { Enumeration aliases = keyStore.aliases(); String keyStoreAlias = (String)aliases.nextElement(); return keyStore.getKey(keyStoreAlias, password.toCharArray()); } else { if(keyStore.containsAlias(alias)) { return keyStore.getKey(alias, password.toCharArray()); } throw new KeyStoreException("the keystore does not contain the given alias"); } } catch(UnrecoverableKeyException ex) { throw new KeyStoreException("the private key is not recoverable"); } catch(NoSuchAlgorithmException ex) { throw new KeyStoreException("the algorithm necessary to recover the key is not available"); } } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardProtectionPolicy.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardProtectionPolicy.jav0000644000000000000000000000665712645757432032336 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; /** * This class represents the protection policy to add to a document * for password-based protection. * * The following example shows how to protect a PDF document with password. * In this example, the document will be protected so that someone opening * the document with the user password user_pwd will not be * able to modify the document. * *
 * AccessPermission ap = new AccessPermission();
 * ap.setCanModify(false);
 * StandardProtectionPolicy policy = new StandardProtectionPolicy(owner_pwd, user_pwd, ap);
 * doc.protect(policy);
 * 
* * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * @version $Revision: 1.3 $ */ public class StandardProtectionPolicy extends ProtectionPolicy { private AccessPermission permissions; private String ownerPassword = ""; private String userPassword = ""; /** * Creates an new instance of the standard protection policy * in order to protect a PDF document with passwords. * * @param ownerPass The owner's password. * @param userPass The users's password. * @param perms The access permissions given to the user. */ public StandardProtectionPolicy(String ownerPass, String userPass, AccessPermission perms) { this.permissions = perms; this.userPassword = userPass; this.ownerPassword = ownerPass; } /** * Getter of the property permissions. * * @return Returns the permissions. */ public AccessPermission getPermissions() { return permissions; } /** * Setter of the property permissions. * * @param perms The permissions to set. */ public void setPermissions(AccessPermission perms) { this.permissions = perms; } /** * Getter of the property ownerPassword. * * @return Returns the ownerPassword. */ public String getOwnerPassword() { return ownerPassword; } /** * Setter of the property ownerPassword. * * @param ownerPass The ownerPassword to set. */ public void setOwnerPassword(String ownerPass) { this.ownerPassword = ownerPass; } /** * Getter of the property userPassword. * * @return Returns the userPassword. */ public String getUserPassword() { return userPassword; } /** * Setter of the property userPassword. * * @param userPass The userPassword to set. */ public void setUserPassword(String userPass) { this.userPassword = userPass; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java0000644000000000000000000007703212645757432032271 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.encryption.ARCFour; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.pdmodel.PDDocument; /** * * The class implements the standard security handler as decribed * in the PDF specifications. This security handler protects document * with password. * * @see StandardProtectionPolicy to see how to protect document with this security handler. * * @author Ben Litchfield * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * */ public class StandardSecurityHandler extends SecurityHandler { /** * Type of security handler. */ public static final String FILTER = "Standard"; private static final int DEFAULT_VERSION = 1; private static final int DEFAULT_REVISION = 3; private int revision = DEFAULT_REVISION; private StandardProtectionPolicy policy; private ARCFour rc4 = new ARCFour(); /** * Protection policy class for this handler. */ public static final Class PROTECTION_POLICY_CLASS = StandardProtectionPolicy.class; /** * Standard padding for encryption. */ public static final byte[] ENCRYPT_PADDING = { (byte)0x28, (byte)0xBF, (byte)0x4E, (byte)0x5E, (byte)0x4E, (byte)0x75, (byte)0x8A, (byte)0x41, (byte)0x64, (byte)0x00, (byte)0x4E, (byte)0x56, (byte)0xFF, (byte)0xFA, (byte)0x01, (byte)0x08, (byte)0x2E, (byte)0x2E, (byte)0x00, (byte)0xB6, (byte)0xD0, (byte)0x68, (byte)0x3E, (byte)0x80, (byte)0x2F, (byte)0x0C, (byte)0xA9, (byte)0xFE, (byte)0x64, (byte)0x53, (byte)0x69, (byte)0x7A }; /** * Constructor. */ public StandardSecurityHandler() { } /** * Constructor used for encryption. * * @param p The protection policy. */ public StandardSecurityHandler(StandardProtectionPolicy p) { policy = p; keyLength = policy.getEncryptionKeyLength(); } /** * Computes the version number of the StandardSecurityHandler * regarding the encryption key length. * See PDF Spec 1.6 p 93 and PDF 1.7 AEL3 * * @return The computed cersion number. */ private int computeVersionNumber() { if(keyLength == 40) { return DEFAULT_VERSION; } return 2; } /** * Computes the revision version of the StandardSecurityHandler to * use regarding the version number and the permissions bits set. * See PDF Spec 1.6 p98 * * @return The computed revision number. */ private int computeRevisionNumber() { if(version < 2 && !policy.getPermissions().hasAnyRevision3PermissionSet()) { return 2; } if ( version == 2 || version == 3 || policy.getPermissions().hasAnyRevision3PermissionSet()) { return 3; } return 4; } /** * Decrypt the document. * * @param doc The document to be decrypted. * @param decryptionMaterial Information used to decrypt the document. * * @throws IOException If there is an error accessing data. * @throws CryptographyException If there is an error with decryption. */ public void decryptDocument(PDDocument doc, DecryptionMaterial decryptionMaterial) throws CryptographyException, IOException { document = doc; PDEncryptionDictionary dictionary = document.getEncryptionDictionary(); COSArray documentIDArray = document.getDocument().getDocumentID(); prepareForDecryption(dictionary, documentIDArray, decryptionMaterial); this.proceedDecryption(); } /** * Prepares everything to decrypt the document. * * If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, this method is * called from there. Only if decryption of single objects is needed this should be called instead. * * @param encDictionary encryption dictionary, can be retrieved via {@link PDDocument#getEncryptionDictionary()} * @param documentIDArray document id which is returned via {@link COSDocument#getDocumentID()} * @param decryptionMaterial Information used to decrypt the document. * * @throws IOException If there is an error accessing data. * @throws CryptographyException If there is an error with decryption. */ public void prepareForDecryption(PDEncryptionDictionary encDictionary, COSArray documentIDArray, DecryptionMaterial decryptionMaterial) throws CryptographyException, IOException { if(!(decryptionMaterial instanceof StandardDecryptionMaterial)) { throw new CryptographyException("Provided decryption material is not compatible with the document"); } decryptMetadata = encDictionary.isEncryptMetaData(); StandardDecryptionMaterial material = (StandardDecryptionMaterial)decryptionMaterial; String password = material.getPassword(); if(password == null) { password = ""; } int dicPermissions = encDictionary.getPermissions(); int dicRevision = encDictionary.getRevision(); int dicLength = encDictionary.getLength()/8; //some documents may have not document id, see //test\encryption\encrypted_doc_no_id.pdf byte[] documentIDBytes = null; if( documentIDArray != null && documentIDArray.size() >= 1 ) { COSString id = (COSString)documentIDArray.getObject( 0 ); documentIDBytes = id.getBytes(); } else { documentIDBytes = new byte[0]; } // we need to know whether the meta data was encrypted for password calculation boolean encryptMetadata = encDictionary.isEncryptMetaData(); byte[] u = encDictionary.getUserKey(); byte[] o = encDictionary.getOwnerKey(); boolean isUserPassword = isUserPassword( password.getBytes("ISO-8859-1"), u, o, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata); boolean isOwnerPassword = isOwnerPassword( password.getBytes("ISO-8859-1"), u, o, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata); if( isUserPassword ) { currentAccessPermission = new AccessPermission( dicPermissions ); encryptionKey = computeEncryptedKey( password.getBytes("ISO-8859-1"), o, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata ); } else if( isOwnerPassword ) { currentAccessPermission = AccessPermission.getOwnerAccessPermission(); byte[] computedUserPassword = getUserPassword(password.getBytes("ISO-8859-1"),o,dicRevision,dicLength ); encryptionKey = computeEncryptedKey( computedUserPassword, o, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata); } else { throw new CryptographyException( "Error: The supplied password does not match either the owner or user password in the document." ); } if (encDictionary.getVersion() == 4 || encDictionary.getVersion() == 5) { // detect whether AES encryption is used. This assumes that the encryption algo is // stored in the PDCryptFilterDictionary // However, crypt filters are used only when V is 4 or 5. PDCryptFilterDictionary stdCryptFilterDictionary = encDictionary.getStdCryptFilterDictionary(); if (stdCryptFilterDictionary != null) { COSName cryptFilterMethod = stdCryptFilterDictionary.getCryptFilterMethod(); if (cryptFilterMethod != null) { setAES("AESV2".equalsIgnoreCase(cryptFilterMethod.getName())); } } } } /** * Prepare document for encryption. * * @param doc The documeent to encrypt. * * @throws IOException If there is an error accessing data. * @throws CryptographyException If there is an error with decryption. */ public void prepareDocumentForEncryption(PDDocument doc) throws CryptographyException, IOException { document = doc; PDEncryptionDictionary encryptionDictionary = document.getEncryptionDictionary(); if(encryptionDictionary == null) { encryptionDictionary = new PDEncryptionDictionary(); } version = computeVersionNumber(); revision = computeRevisionNumber(); encryptionDictionary.setFilter(FILTER); encryptionDictionary.setVersion(version); if (version != 4 && version != 5) { // remove CF, StmF, and StrF entries that may be left from a previous encryption encryptionDictionary.removeV45filters(); } encryptionDictionary.setRevision(revision); encryptionDictionary.setLength(keyLength); String ownerPassword = policy.getOwnerPassword(); String userPassword = policy.getUserPassword(); if( ownerPassword == null ) { ownerPassword = ""; } if( userPassword == null ) { userPassword = ""; } int permissionInt = policy.getPermissions().getPermissionBytes(); encryptionDictionary.setPermissions(permissionInt); int length = keyLength/8; COSArray idArray = document.getDocument().getDocumentID(); //check if the document has an id yet. If it does not then //generate one if( idArray == null || idArray.size() < 2 ) { idArray = new COSArray(); try { MessageDigest md = MessageDigest.getInstance( "MD5" ); BigInteger time = BigInteger.valueOf( System.currentTimeMillis() ); md.update( time.toByteArray() ); md.update( ownerPassword.getBytes("ISO-8859-1") ); md.update( userPassword.getBytes("ISO-8859-1") ); md.update( document.getDocument().toString().getBytes("ISO-8859-1") ); byte[] id = md.digest( this.toString().getBytes("ISO-8859-1") ); COSString idString = new COSString(); idString.append( id ); idArray.add( idString ); idArray.add( idString ); document.getDocument().setDocumentID( idArray ); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } catch(IOException e ) { throw new CryptographyException( e ); } } COSString id = (COSString)idArray.getObject( 0 ); byte[] o = computeOwnerPassword( ownerPassword.getBytes("ISO-8859-1"), userPassword.getBytes("ISO-8859-1"), revision, length); byte[] u = computeUserPassword( userPassword.getBytes("ISO-8859-1"), o, permissionInt, id.getBytes(), revision, length, true); encryptionKey = computeEncryptedKey( userPassword.getBytes("ISO-8859-1"), o, permissionInt, id.getBytes(), revision, length, true); encryptionDictionary.setOwnerKey(o); encryptionDictionary.setUserKey(u); document.setEncryptionDictionary( encryptionDictionary ); document.getDocument().setEncryptionDictionary(encryptionDictionary.getCOSDictionary()); } /** * Check for owner password. * * @param ownerPassword The owner password. * @param u The u entry of the encryption dictionary. * @param o The o entry of the encryption dictionary. * @param permissions The set of permissions on the document. * @param id The document id. * @param encRevision The encryption algorithm revision. * @param length The encryption key length. * @param encryptMetadata The encryption metadata * * @return True If the ownerPassword param is the owner password. * * @throws CryptographyException If there is an error during encryption. * @throws IOException If there is an error accessing data. */ public final boolean isOwnerPassword( byte[] ownerPassword, byte[] u, byte[] o, int permissions, byte[] id, int encRevision, int length, boolean encryptMetadata) throws CryptographyException, IOException { byte[] userPassword = getUserPassword( ownerPassword, o, encRevision, length ); return isUserPassword( userPassword, u, o, permissions, id, encRevision, length, encryptMetadata ); } /** * Get the user password based on the owner password. * * @param ownerPassword The plaintext owner password. * @param o The o entry of the encryption dictionary. * @param encRevision The encryption revision number. * @param length The key length. * * @return The u entry of the encryption dictionary. * * @throws CryptographyException If there is an error generating the user password. * @throws IOException If there is an error accessing data while generating the user password. */ public final byte[] getUserPassword( byte[] ownerPassword, byte[] o, int encRevision, int length ) throws CryptographyException, IOException { try { ByteArrayOutputStream result = new ByteArrayOutputStream(); byte[] rc4Key = computeRC4key(ownerPassword, encRevision, length); if( encRevision == 2 && length != 5 ) { throw new CryptographyException( "Error: Expected length=5 actual=" + length ); } //3.7 step 2 if( encRevision == 2 ) { rc4.setKey( rc4Key ); rc4.write( o, result ); } else if( encRevision == 3 || encRevision == 4) { byte[] iterationKey = new byte[ rc4Key.length ]; byte[] otemp = new byte[ o.length ]; //sm System.arraycopy( o, 0, otemp, 0, o.length ); //sm rc4.write( o, result);//sm for( int i=19; i>=0; i-- ) { System.arraycopy( rc4Key, 0, iterationKey, 0, rc4Key.length ); for( int j=0; j< iterationKey.length; j++ ) { iterationKey[j] = (byte)(iterationKey[j] ^ (byte)i); } rc4.setKey( iterationKey ); result.reset(); //sm rc4.write( otemp, result ); //sm otemp = result.toByteArray(); //sm } } return result.toByteArray(); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } } /** * Compute the encryption key. * * @param password The password to compute the encrypted key. * @param o The o entry of the encryption dictionary. * @param permissions The permissions for the document. * @param id The document id. * @param encRevision The revision of the encryption algorithm. * @param length The length of the encryption key. * @param encryptMetadata The encryption metadata * * @return The encrypted key bytes. * * @throws CryptographyException If there is an error with encryption. */ public final byte[] computeEncryptedKey( byte[] password, byte[] o, int permissions, byte[] id, int encRevision, int length, boolean encryptMetadata) throws CryptographyException { byte[] result = new byte[ length ]; try { //PDFReference 1.4 pg 78 //step1 byte[] padded = truncateOrPad( password ); //step 2 MessageDigest md = MessageDigest.getInstance("MD5"); md.update( padded ); //step 3 md.update( o ); //step 4 byte zero = (byte)(permissions >>> 0); byte one = (byte)(permissions >>> 8); byte two = (byte)(permissions >>> 16); byte three = (byte)(permissions >>> 24); md.update( zero ); md.update( one ); md.update( two ); md.update( three ); //step 5 md.update( id ); //(Security handlers of revision 4 or greater) If document metadata is not being encrypted, //pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function. //see 7.6.3.3 Algorithm 2 Step f of PDF 32000-1:2008 if( encRevision == 4 && !encryptMetadata) { md.update(new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}); } byte[] digest = md.digest(); //step 6 if( encRevision == 3 || encRevision == 4) { for( int i=0; i<50; i++ ) { md.reset(); md.update( digest, 0, length ); digest = md.digest(); } } //step 7 if( encRevision == 2 && length != 5 ) { throw new CryptographyException( "Error: length should be 5 when revision is two actual=" + length ); } System.arraycopy( digest, 0, result, 0, length ); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } return result; } /** * This will compute the user password hash. * * @param password The plain text password. * @param o The owner password hash. * @param permissions The document permissions. * @param id The document id. * @param encRevision The revision of the encryption. * @param length The length of the encryption key. * @param encryptMetadata The encryption metadata * * @return The user password. * * @throws CryptographyException If there is an error computing the user password. * @throws IOException If there is an IO error. */ public final byte[] computeUserPassword( byte[] password, byte[] o, int permissions, byte[] id, int encRevision, int length, boolean encryptMetadata) throws CryptographyException, IOException { ByteArrayOutputStream result = new ByteArrayOutputStream(); //STEP 1 byte[] encryptionKey = computeEncryptedKey( password, o, permissions, id, encRevision, length, encryptMetadata ); if( encRevision == 2 ) { //STEP 2 rc4.setKey( encryptionKey ); rc4.write( ENCRYPT_PADDING, result ); } else if( encRevision == 3 || encRevision == 4 ) { try { //STEP 2 MessageDigest md = MessageDigest.getInstance("MD5"); //md.update( truncateOrPad( password ) ); md.update( ENCRYPT_PADDING ); //STEP 3 md.update( id ); result.write( md.digest() ); //STEP 4 and 5 byte[] iterationKey = new byte[ encryptionKey.length ]; for( int i=0; i<20; i++ ) { System.arraycopy( encryptionKey, 0, iterationKey, 0, iterationKey.length ); for( int j=0; j< iterationKey.length; j++ ) { iterationKey[j] = (byte)(iterationKey[j] ^ i); } rc4.setKey( iterationKey ); ByteArrayInputStream input = new ByteArrayInputStream( result.toByteArray() ); result.reset(); rc4.write( input, result ); } //step 6 byte[] finalResult = new byte[32]; System.arraycopy( result.toByteArray(), 0, finalResult, 0, 16 ); System.arraycopy( ENCRYPT_PADDING, 0, finalResult, 16, 16 ); result.reset(); result.write( finalResult ); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e ); } } return result.toByteArray(); } /** * Compute the owner entry in the encryption dictionary. * * @param ownerPassword The plaintext owner password. * @param userPassword The plaintext user password. * @param encRevision The revision number of the encryption algorithm. * @param length The length of the encryption key. * * @return The o entry of the encryption dictionary. * * @throws CryptographyException If there is an error with encryption. * @throws IOException If there is an error accessing data. */ public final byte[] computeOwnerPassword( byte[] ownerPassword, byte[] userPassword, int encRevision, int length ) throws CryptographyException, IOException { try { byte[] rc4Key = computeRC4key(ownerPassword, encRevision, length); //STEP 5 byte[] paddedUser = truncateOrPad( userPassword ); //STEP 6 rc4.setKey( rc4Key ); ByteArrayOutputStream crypted = new ByteArrayOutputStream(); rc4.write( new ByteArrayInputStream( paddedUser ), crypted ); //STEP 7 if( encRevision == 3 || encRevision == 4 ) { byte[] iterationKey = new byte[ rc4Key.length ]; for( int i=1; i<20; i++ ) { System.arraycopy( rc4Key, 0, iterationKey, 0, rc4Key.length ); for( int j=0; j< iterationKey.length; j++ ) { iterationKey[j] = (byte)(iterationKey[j] ^ (byte)i); } rc4.setKey( iterationKey ); ByteArrayInputStream input = new ByteArrayInputStream( crypted.toByteArray() ); crypted.reset(); rc4.write( input, crypted ); } } //STEP 8 return crypted.toByteArray(); } catch( NoSuchAlgorithmException e ) { throw new CryptographyException( e.getMessage() ); } } // steps (a) to (d) of "Algorithm 3: Computing the encryption dictionary's O (owner password) value". private byte[] computeRC4key(byte[] ownerPassword, int encRevision, int length) throws NoSuchAlgorithmException, CryptographyException { if (encRevision == 2 && length != 5) { throw new CryptographyException( "Error: Expected length=5 actual=" + length); } //3.3 STEP a byte[] ownerPadded = truncateOrPad(ownerPassword); //3.3 STEP b MessageDigest md = MessageDigest.getInstance("MD5"); md.update(ownerPadded); byte[] digest = md.digest(); //3.3 STEP c if (encRevision == 3 || encRevision == 4) { for (int i = 0; i < 50; i++) { // this deviates from the spec - however, omitting the length // parameter prevents the file to be opened in Adobe Reader // with the owner password when the key length is 40 bit (= 5 bytes) md.reset(); md.update(digest, 0, length); digest = md.digest(); } } //3.3 STEP d byte[] rc4Key = new byte[(int) length]; System.arraycopy(digest, 0, rc4Key, 0, (int) length); return rc4Key; } /** * This will take the password and truncate or pad it as necessary. * * @param password The password to pad or truncate. * * @return The padded or truncated password. */ private final byte[] truncateOrPad( byte[] password ) { byte[] padded = new byte[ ENCRYPT_PADDING.length ]; int bytesBeforePad = Math.min( password.length, padded.length ); System.arraycopy( password, 0, padded, 0, bytesBeforePad ); System.arraycopy( ENCRYPT_PADDING, 0, padded, bytesBeforePad, ENCRYPT_PADDING.length-bytesBeforePad ); return padded; } /** * Check if a plaintext password is the user password. * * @param password The plaintext password. * @param u The u entry of the encryption dictionary. * @param o The o entry of the encryption dictionary. * @param permissions The permissions set in the the PDF. * @param id The document id used for encryption. * @param encRevision The revision of the encryption algorithm. * @param length The length of the encryption key. * @param encryptMetadata The encryption metadata * * @return true If the plaintext password is the user password. * * @throws CryptographyException If there is an error during encryption. * @throws IOException If there is an error accessing data. */ public final boolean isUserPassword( byte[] password, byte[] u, byte[] o, int permissions, byte[] id, int encRevision, int length, boolean encryptMetadata) throws CryptographyException, IOException { boolean matches = false; //STEP 1 byte[] computedValue = computeUserPassword( password, o, permissions, id, encRevision, length, encryptMetadata ); if( encRevision == 2 ) { //STEP 2 matches = Arrays.equals(u, computedValue); } else if( encRevision == 3 || encRevision == 4 ) { //STEP 2 matches = arraysEqual( u, computedValue, 16 ); } else { throw new IOException( "Unknown Encryption Revision " + encRevision ); } return matches; } /** * Check if a plaintext password is the user password. * * @param password The plaintext password. * @param u The u entry of the encryption dictionary. * @param o The o entry of the encryption dictionary. * @param permissions The permissions set in the the PDF. * @param id The document id used for encryption. * @param encRevision The revision of the encryption algorithm. * @param length The length of the encryption key. * @param encryptMetadata The encryption metadata * * @return true If the plaintext password is the user password. * * @throws CryptographyException If there is an error during encryption. * @throws IOException If there is an error accessing data. */ public final boolean isUserPassword( String password, byte[] u, byte[] o, int permissions, byte[] id, int encRevision, int length, boolean encryptMetadata ) throws CryptographyException, IOException { return isUserPassword(password.getBytes("ISO-8859-1"), u,o,permissions, id, encRevision, length, encryptMetadata); } /** * Check for owner password. * * @param password The owner password. * @param u The u entry of the encryption dictionary. * @param o The o entry of the encryption dictionary. * @param permissions The set of permissions on the document. * @param id The document id. * @param encRevision The encryption algorithm revision. * @param length The encryption key length. * @param encryptMetadata The encryption metadata * * @return True If the ownerPassword param is the owner password. * * @throws CryptographyException If there is an error during encryption. * @throws IOException If there is an error accessing data. */ public final boolean isOwnerPassword( String password, byte[] u, byte[] o, int permissions, byte[] id, int encRevision, int length, boolean encryptMetadata) throws CryptographyException, IOException { return isOwnerPassword(password.getBytes("ISO-8859-1"), u,o,permissions, id, encRevision, length, encryptMetadata); } private static final boolean arraysEqual( byte[] first, byte[] second, int count ) { // both arrays have to have a minimum length of count if (first.length < count || second.length < count) { return false; } for( int i=0; i *
  • print the document
  • *
  • modify the content of the document
  • *
  • copy or extract content of the document
  • *
  • add or modify annotations
  • *
  • fill in interactive form fields
  • *
  • extract text and graphics for accessibility to visually impaired people
  • *
  • assemble the document
  • *
  • print in degraded quality
  • * * * This class can be used to protect a document by assigning access permissions to recipients. * In this case, it must be used with a specific ProtectionPolicy. * * * When a document is decrypted, it has a currentAccessPermission property which is the access permissions * granted to the user who decrypted the document. * * @see ProtectionPolicy * @see org.apache.pdfbox.pdmodel.PDDocument#getCurrentAccessPermission() * * @author Ben Litchfield * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * */ public class AccessPermission { private static final int DEFAULT_PERMISSIONS = 0xFFFFFFFF ^ 3;//bits 0 & 1 need to be zero private static final int PRINT_BIT = 3; private static final int MODIFICATION_BIT = 4; private static final int EXTRACT_BIT = 5; private static final int MODIFY_ANNOTATIONS_BIT = 6; private static final int FILL_IN_FORM_BIT = 9; private static final int EXTRACT_FOR_ACCESSIBILITY_BIT = 10; private static final int ASSEMBLE_DOCUMENT_BIT = 11; private static final int DEGRADED_PRINT_BIT = 12; private int bytes = DEFAULT_PERMISSIONS; private boolean readOnly = false; /** * Create a new access permission object. * By default, all permissions are granted. */ public AccessPermission() { bytes = DEFAULT_PERMISSIONS; } /** * Create a new access permission object from a byte array. * Bytes are ordered most significant byte first. * * @param b the bytes as defined in PDF specs */ public AccessPermission(byte[] b) { bytes = 0; bytes |= b[0] & 0xFF; bytes <<= 8; bytes |= b[1] & 0xFF; bytes <<= 8; bytes |= b[2] & 0xFF; bytes <<= 8; bytes |= b[3] & 0xFF; } /** * Creates a new access permission object from a single integer. * * @param permissions The permission bits. */ public AccessPermission( int permissions ) { bytes = permissions; } private boolean isPermissionBitOn( int bit ) { return (bytes & (1 << (bit-1))) != 0; } private boolean setPermissionBit( int bit, boolean value ) { int permissions = bytes; if( value ) { permissions = permissions | (1 << (bit-1)); } else { permissions = permissions & (0xFFFFFFFF ^ (1 << (bit-1))); } bytes = permissions; return (bytes & (1 << (bit-1))) != 0; } /** * This will tell if the access permission corresponds to owner * access permission (no restriction). * * @return true if the access permission does not restrict the use of the document */ public boolean isOwnerPermission() { return (this.canAssembleDocument() && this.canExtractContent() && this.canExtractForAccessibility() && this.canFillInForm() && this.canModify() && this.canModifyAnnotations() && this.canPrint() && this.canPrintDegraded() ); } /** * returns an access permission object for a document owner. * * @return A standard owner access permission set. */ public static AccessPermission getOwnerAccessPermission() { AccessPermission ret = new AccessPermission(); ret.setCanAssembleDocument(true); ret.setCanExtractContent(true); ret.setCanExtractForAccessibility(true); ret.setCanFillInForm(true); ret.setCanModify(true); ret.setCanModifyAnnotations(true); ret.setCanPrint(true); ret.setCanPrintDegraded(true); return ret; } /** * This returns an integer representing the access permissions. * This integer can be used for public key encryption. This format * is not documented in the PDF specifications but is necessary for compatibility * with Adobe Acrobat and Adobe Reader. * * @return the integer representing access permissions */ public int getPermissionBytesForPublicKey() { setPermissionBit(1, true); setPermissionBit(7, false); setPermissionBit(8, false); for(int i=13; i<=32; i++) { setPermissionBit(i, false); } return bytes; } /** * The returns an integer representing the access permissions. * This integer can be used for standard PDF encryption as specified * in the PDF specifications. * * @return the integer representing the access permissions */ public int getPermissionBytes() { return bytes; } /** * This will tell if the user can print. * * @return true If supplied with the user password they are allowed to print. */ public boolean canPrint() { return isPermissionBitOn( PRINT_BIT ); } /** * Set if the user can print. * This method will have no effect if the object is in read only mode * * @param allowPrinting A boolean determining if the user can print. */ public void setCanPrint( boolean allowPrinting ) { if(!readOnly) { setPermissionBit( PRINT_BIT, allowPrinting ); } } /** * This will tell if the user can modify contents of the document. * * @return true If supplied with the user password they are allowed to modify the document */ public boolean canModify() { return isPermissionBitOn( MODIFICATION_BIT ); } /** * Set if the user can modify the document. * This method will have no effect if the object is in read only mode * * @param allowModifications A boolean determining if the user can modify the document. */ public void setCanModify( boolean allowModifications ) { if(!readOnly) { setPermissionBit( MODIFICATION_BIT, allowModifications ); } } /** * This will tell if the user can extract text and images from the PDF document. * * @return true If supplied with the user password they are allowed to extract content * from the PDF document */ public boolean canExtractContent() { return isPermissionBitOn( EXTRACT_BIT ); } /** * Set if the user can extract content from the document. * This method will have no effect if the object is in read only mode * * @param allowExtraction A boolean determining if the user can extract content * from the document. */ public void setCanExtractContent( boolean allowExtraction ) { if(!readOnly) { setPermissionBit( EXTRACT_BIT, allowExtraction ); } } /** * This will tell if the user can add/modify text annotations, fill in interactive forms fields. * * @return true If supplied with the user password they are allowed to modify annotations. */ public boolean canModifyAnnotations() { return isPermissionBitOn( MODIFY_ANNOTATIONS_BIT ); } /** * Set if the user can modify annotations. * This method will have no effect if the object is in read only mode * * @param allowAnnotationModification A boolean determining if the user can modify annotations. */ public void setCanModifyAnnotations( boolean allowAnnotationModification ) { if(!readOnly) { setPermissionBit( MODIFY_ANNOTATIONS_BIT, allowAnnotationModification ); } } /** * This will tell if the user can fill in interactive forms. * * @return true If supplied with the user password they are allowed to fill in form fields. */ public boolean canFillInForm() { return isPermissionBitOn( FILL_IN_FORM_BIT ); } /** * Set if the user can fill in interactive forms. * This method will have no effect if the object is in read only mode * * @param allowFillingInForm A boolean determining if the user can fill in interactive forms. */ public void setCanFillInForm( boolean allowFillingInForm ) { if(!readOnly) { setPermissionBit( FILL_IN_FORM_BIT, allowFillingInForm ); } } /** * This will tell if the user can extract text and images from the PDF document * for accessibility purposes. * * @return true If supplied with the user password they are allowed to extract content * from the PDF document */ public boolean canExtractForAccessibility() { return isPermissionBitOn( EXTRACT_FOR_ACCESSIBILITY_BIT ); } /** * Set if the user can extract content from the document for accessibility purposes. * This method will have no effect if the object is in read only mode * * @param allowExtraction A boolean determining if the user can extract content * from the document. */ public void setCanExtractForAccessibility( boolean allowExtraction ) { if(!readOnly) { setPermissionBit( EXTRACT_FOR_ACCESSIBILITY_BIT, allowExtraction ); } } /** * This will tell if the user can insert/rotate/delete pages. * * @return true If supplied with the user password they are allowed to extract content * from the PDF document */ public boolean canAssembleDocument() { return isPermissionBitOn( ASSEMBLE_DOCUMENT_BIT ); } /** * Set if the user can insert/rotate/delete pages. * This method will have no effect if the object is in read only mode * * @param allowAssembly A boolean determining if the user can assemble the document. */ public void setCanAssembleDocument( boolean allowAssembly ) { if(!readOnly) { setPermissionBit( ASSEMBLE_DOCUMENT_BIT, allowAssembly ); } } /** * This will tell if the user can print the document in a degraded format. * * @return true If supplied with the user password they are allowed to print the * document in a degraded format. */ public boolean canPrintDegraded() { return isPermissionBitOn( DEGRADED_PRINT_BIT ); } /** * Set if the user can print the document in a degraded format. * This method will have no effect if the object is in read only mode * * @param allowAssembly A boolean determining if the user can print the * document in a degraded format. */ public void setCanPrintDegraded( boolean allowAssembly ) { if(!readOnly) { setPermissionBit( DEGRADED_PRINT_BIT, allowAssembly ); } } /** * Locks the access permission read only (ie, the setters will have no effects). * After that, the object cannot be unlocked. * This method is used for the currentAccessPermssion of a document to avoid * users to change access permission. */ public void setReadOnly() { readOnly = true; } /** * This will tell if the object has been set as read only. * * @return true if the object is in read only mode. */ public boolean isReadOnly() { return readOnly; } /** * Indicates if any revision 3 access permission is set or not. * * @return true if any revision 3 access permission is set */ protected boolean hasAnyRevision3PermissionSet() { if (canFillInForm()) { return true; } if (canExtractForAccessibility()) { return true; } if (canAssembleDocument()) { return true; } if (canPrintDegraded()) { return true; } return false; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandlersManager.java0000644000000000000000000001756212645757432032270 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.lang.reflect.Constructor; import java.security.Security; import java.util.Hashtable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * This class manages security handlers for the application. It follows the singleton pattern. * To be usable, security managers must be registered in it. Security managers are retrieved by * the application when necessary. * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * * @version $Revision: 1.3 $ * */ public class SecurityHandlersManager { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(SecurityHandlersManager.class); /** * The unique instance of this manager. */ private static SecurityHandlersManager instance; /** * hashtable used to index handlers regarding their name. * Basically this will be used when opening an encrypted * document to find the appropriate security handler to handle * security features of the document. */ private Hashtable handlerNames = null; /** * Hashtable used to index handlers regarding the class of * protection policy they use. Basically this will be used when * encrypting a document. */ private Hashtable handlerPolicyClasses = null; /** * private constructor. */ private SecurityHandlersManager() { handlerNames = new Hashtable(); handlerPolicyClasses = new Hashtable(); try { this.registerHandler( StandardSecurityHandler.FILTER, StandardSecurityHandler.class, StandardProtectionPolicy.class); this.registerHandler( PublicKeySecurityHandler.FILTER, PublicKeySecurityHandler.class, PublicKeyProtectionPolicy.class); } catch (BadSecurityHandlerException e) { // should never happen throw new RuntimeException(e); } } /** * register a security handler. * * If the security handler was already registered an exception is thrown. * If another handler was previously registered for the same filter name or * for the same policy name, an exception is thrown * * @param filterName The name of the filter. * @param securityHandlerClass Security Handler class to register. * @param protectionPolicyClass Protection Policy class to register. * * @throws BadSecurityHandlerException If there is an error registering the security handler. */ public void registerHandler(String filterName, Class securityHandlerClass, Class protectionPolicyClass) throws BadSecurityHandlerException { if(handlerNames.contains(securityHandlerClass) || handlerPolicyClasses.contains(securityHandlerClass)) { throw new BadSecurityHandlerException("the following security handler was already registered: " + securityHandlerClass.getName()); } if(SecurityHandler.class.isAssignableFrom(securityHandlerClass)) { try { if(handlerNames.containsKey(filterName)) { throw new BadSecurityHandlerException("a security handler was already registered " + "for the filter name " + filterName); } if(handlerPolicyClasses.containsKey(protectionPolicyClass)) { throw new BadSecurityHandlerException("a security handler was already registered " + "for the policy class " + protectionPolicyClass.getName()); } handlerNames.put(filterName, securityHandlerClass); handlerPolicyClasses.put(protectionPolicyClass, securityHandlerClass); } catch(Exception e) { throw new BadSecurityHandlerException(e); } } else { throw new BadSecurityHandlerException("The class is not a super class of SecurityHandler"); } } /** * Get the singleton instance. * * @return The SecurityHandlersManager. */ public static SecurityHandlersManager getInstance() { if(instance == null) { instance = new SecurityHandlersManager(); Security.addProvider(new BouncyCastleProvider()); } return instance; } /** * Get the security handler for the protection policy. * * @param policy The policy to get the security handler for. * * @return The appropriate security handler. * * @throws BadSecurityHandlerException If it is unable to create a SecurityHandler. */ public SecurityHandler getSecurityHandler(ProtectionPolicy policy) throws BadSecurityHandlerException { Object found = handlerPolicyClasses.get(policy.getClass()); if(found == null) { throw new BadSecurityHandlerException( "Cannot find an appropriate security handler for " + policy.getClass().getName()); } Class handlerclass = (Class) found; Class[] argsClasses = {policy.getClass()}; Object[] args = {policy}; try { Constructor c = handlerclass.getDeclaredConstructor(argsClasses); SecurityHandler handler = (SecurityHandler)c.newInstance(args); return handler; } catch(Exception e) { LOG.error(e,e); throw new BadSecurityHandlerException( "problem while trying to instanciate the security handler "+ handlerclass.getName() + ": " + e.getMessage()); } } /** * Retrieve the appropriate SecurityHandler for a the given filter name. * The filter name is an entry of the encryption dictionary of an encrypted document. * * @param filterName The filter name. * * @return The appropriate SecurityHandler if it exists. * * @throws BadSecurityHandlerException If the security handler does not exist. */ public SecurityHandler getSecurityHandler(String filterName) throws BadSecurityHandlerException { Object found = handlerNames.get(filterName); if(found == null) { throw new BadSecurityHandlerException("Cannot find an appropriate security handler for " + filterName); } Class handlerclass = (Class) found; Class[] argsClasses = {}; Object[] args = {}; try { Constructor c = handlerclass.getDeclaredConstructor(argsClasses); SecurityHandler handler = (SecurityHandler)c.newInstance(args); return handler; } catch(Exception e) { LOG.error(e,e); throw new BadSecurityHandlerException( "problem while trying to instanciate the security handler "+ handlerclass.getName() + ": " + e.getMessage()); } } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.jav0000644000000000000000000004103412645757432032250 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.encryption; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.Iterator; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.DERObject; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DEROutputStream; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.cms.EncryptedContentInfo; import org.bouncycastle.asn1.cms.EnvelopedData; import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; import org.bouncycastle.asn1.cms.RecipientIdentifier; import org.bouncycastle.asn1.cms.RecipientInfo; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.TBSCertificateStructure; import org.bouncycastle.cms.CMSEnvelopedData; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.RecipientInformation; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.pdmodel.PDDocument; /** * This class implements the public key security handler * described in the PDF specification. * * [PDF Spec 1.6 p104] * * @see PublicKeyProtectionPolicy to see how to protect document with this security handler. * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * @version $Revision: 1.3 $ */ public class PublicKeySecurityHandler extends SecurityHandler { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PublicKeySecurityHandler.class); /** * The filter name. */ public static final String FILTER = "Adobe.PubSec"; private static final String SUBFILTER = "adbe.pkcs7.s4"; private PublicKeyProtectionPolicy policy = null; /** * Constructor. */ public PublicKeySecurityHandler() { } /** * Constructor used for encryption. * * @param p The protection policy. */ public PublicKeySecurityHandler(PublicKeyProtectionPolicy p) { policy = p; this.keyLength = policy.getEncryptionKeyLength(); } /** * Decrypt the document. * * @param doc The document to decrypt. * @param decryptionMaterial The data used to decrypt the document. * * @throws CryptographyException If there is an error during decryption. * @throws IOException If there is an error accessing data. */ public void decryptDocument(PDDocument doc, DecryptionMaterial decryptionMaterial) throws CryptographyException, IOException { this.document = doc; PDEncryptionDictionary dictionary = doc.getEncryptionDictionary(); prepareForDecryption( dictionary, doc.getDocument().getDocumentID(), decryptionMaterial ); proceedDecryption(); } /** * Prepares everything to decrypt the document. * * If {@link #decryptDocument(PDDocument, DecryptionMaterial)} is used, this method is * called from there. Only if decryption of single objects is needed this should be called instead. * * @param encDictionary encryption dictionary, can be retrieved via {@link PDDocument#getEncryptionDictionary()} * @param documentIDArray document id which is returned via {@link org.apache.pdfbox.cos.COSDocument#getDocumentID()} (not used by this handler) * @param decryptionMaterial Information used to decrypt the document. * * @throws IOException If there is an error accessing data. * @throws CryptographyException If there is an error with decryption. */ public void prepareForDecryption(PDEncryptionDictionary encDictionary, COSArray documentIDArray, DecryptionMaterial decryptionMaterial) throws CryptographyException, IOException { if (!(decryptionMaterial instanceof PublicKeyDecryptionMaterial)) { throw new CryptographyException("Provided decryption material is not compatible with the document"); } decryptMetadata = encDictionary.isEncryptMetaData(); if (encDictionary.getLength() != 0) { this.keyLength = encDictionary.getLength(); } PublicKeyDecryptionMaterial material = (PublicKeyDecryptionMaterial) decryptionMaterial; try { boolean foundRecipient = false; // the decrypted content of the enveloped data that match // the certificate in the decryption material provided byte[] envelopedData = null; // the bytes of each recipient in the recipients array byte[][] recipientFieldsBytes = new byte[encDictionary.getRecipientsLength()][]; int recipientFieldsLength = 0; for (int i = 0; i < encDictionary.getRecipientsLength(); i++) { COSString recipientFieldString = encDictionary.getRecipientStringAt(i); byte[] recipientBytes = recipientFieldString.getBytes(); CMSEnvelopedData data = new CMSEnvelopedData(recipientBytes); Iterator recipCertificatesIt = data.getRecipientInfos().getRecipients().iterator(); while (recipCertificatesIt.hasNext()) { RecipientInformation ri = (RecipientInformation) recipCertificatesIt.next(); // Impl: if a matching certificate was previously found it is an error, // here we just don't care about it if (ri.getRID().match(material.getCertificate()) && !foundRecipient) { foundRecipient = true; envelopedData = ri.getContent(material.getPrivateKey(), "BC"); break; } } recipientFieldsBytes[i] = recipientBytes; recipientFieldsLength += recipientBytes.length; } if (!foundRecipient || envelopedData == null) { throw new CryptographyException("The certificate matches no recipient entry"); } if (envelopedData.length != 24) { throw new CryptographyException("The enveloped data does not contain 24 bytes"); } // now envelopedData contains: // - the 20 bytes seed // - the 4 bytes of permission for the current user byte[] accessBytes = new byte[4]; System.arraycopy(envelopedData, 20, accessBytes, 0, 4); currentAccessPermission = new AccessPermission(accessBytes); currentAccessPermission.setReadOnly(); // what we will put in the SHA1 = the seed + each byte contained in the recipients array byte[] sha1Input = new byte[recipientFieldsLength + 20]; // put the seed in the sha1 input System.arraycopy(envelopedData, 0, sha1Input, 0, 20); // put each bytes of the recipients array in the sha1 input int sha1InputOffset = 20; for (int i = 0; i < recipientFieldsBytes.length; i++) { System.arraycopy(recipientFieldsBytes[i], 0, sha1Input, sha1InputOffset, recipientFieldsBytes[i].length); sha1InputOffset += recipientFieldsBytes[i].length; } MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] mdResult = md.digest(sha1Input); // we have the encryption key ... encryptionKey = new byte[this.keyLength / 8]; System.arraycopy(mdResult, 0, encryptionKey, 0, this.keyLength / 8); } catch (CMSException e) { throw new CryptographyException(e); } catch (KeyStoreException e) { throw new CryptographyException(e); } catch (NoSuchProviderException e) { throw new CryptographyException(e); } catch (NoSuchAlgorithmException e) { throw new CryptographyException(e); } } /** * Prepare the document for encryption. * * @param doc The document that will be encrypted. * * @throws CryptographyException If there is an error while encrypting. */ public void prepareDocumentForEncryption(PDDocument doc) throws CryptographyException { try { PDEncryptionDictionary dictionary = doc.getEncryptionDictionary(); if (dictionary == null) { dictionary = new PDEncryptionDictionary(); } dictionary.setFilter(FILTER); dictionary.setLength(this.keyLength); dictionary.setVersion(2); // remove CF, StmF, and StrF entries that may be left from a previous encryption dictionary.removeV45filters(); dictionary.setSubFilter(SUBFILTER); byte[][] recipientsField = new byte[policy.getRecipientsNumber()][]; // create the 20 bytes seed byte[] seed = new byte[20]; KeyGenerator key = KeyGenerator.getInstance("AES"); key.init(192, new SecureRandom()); SecretKey sk = key.generateKey(); System.arraycopy(sk.getEncoded(), 0, seed, 0, 20); // create the 20 bytes seed Iterator it = policy.getRecipientsIterator(); int i = 0; while(it.hasNext()) { PublicKeyRecipient recipient = (PublicKeyRecipient)it.next(); X509Certificate certificate = recipient.getX509(); int permission = recipient.getPermission().getPermissionBytesForPublicKey(); byte[] pkcs7input = new byte[24]; byte one = (byte)(permission); byte two = (byte)(permission >>> 8); byte three = (byte)(permission >>> 16); byte four = (byte)(permission >>> 24); System.arraycopy(seed, 0, pkcs7input, 0, 20); // put this seed in the pkcs7 input pkcs7input[20] = four; pkcs7input[21] = three; pkcs7input[22] = two; pkcs7input[23] = one; DERObject obj = createDERForRecipient(pkcs7input, certificate); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DEROutputStream k = new DEROutputStream(baos); k.writeObject(obj); recipientsField[i] = baos.toByteArray(); i++; } dictionary.setRecipients(recipientsField); int sha1InputLength = seed.length; for(int j=0; jBen Litchfield * @author Gerardo Ortiz * * @version $Revision: 1.12 $ */ public class PDDocumentInformation implements COSObjectable { private COSDictionary info; /** * Default Constructor. */ public PDDocumentInformation() { info = new COSDictionary(); } /** * Constructor that is used for a preexisting dictionary. * * @param dic The underlying dictionary. */ public PDDocumentInformation( COSDictionary dic ) { info = dic; } /** * This will get the underlying dictionary that this object wraps. * * @return The underlying info dictionary. */ public COSDictionary getDictionary() { return info; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return info; } /** * Return the properties String value. *

    * Allows to retrieve the * low level date for validation purposes. *

    * * @param propertyKey the dictionaries key * @return the properties value */ public Object getPropertyStringValue(String propertyKey) { return info.getString(propertyKey); } /** * This will get the title of the document. This will return null if no title exists. * * @return The title of the document. */ public String getTitle() { return info.getString( COSName.TITLE ); } /** * This will set the title of the document. * * @param title The new title for the document. */ public void setTitle( String title ) { info.setString( COSName.TITLE, title ); } /** * This will get the author of the document. This will return null if no author exists. * * @return The author of the document. */ public String getAuthor() { return info.getString( COSName.AUTHOR ); } /** * This will set the author of the document. * * @param author The new author for the document. */ public void setAuthor( String author ) { info.setString( COSName.AUTHOR, author ); } /** * This will get the subject of the document. This will return null if no subject exists. * * @return The subject of the document. */ public String getSubject() { return info.getString( COSName.SUBJECT ); } /** * This will set the subject of the document. * * @param subject The new subject for the document. */ public void setSubject( String subject ) { info.setString( COSName.SUBJECT, subject ); } /** * This will get the keywords of the document. This will return null if no keywords exists. * * @return The keywords of the document. */ public String getKeywords() { return info.getString( COSName.KEYWORDS ); } /** * This will set the keywords of the document. * * @param keywords The new keywords for the document. */ public void setKeywords( String keywords ) { info.setString( COSName.KEYWORDS, keywords ); } /** * This will get the creator of the document. This will return null if no creator exists. * * @return The creator of the document. */ public String getCreator() { return info.getString( COSName.CREATOR ); } /** * This will set the creator of the document. * * @param creator The new creator for the document. */ public void setCreator( String creator ) { info.setString( COSName.CREATOR, creator ); } /** * This will get the producer of the document. This will return null if no producer exists. * * @return The producer of the document. */ public String getProducer() { return info.getString( COSName.PRODUCER ); } /** * This will set the producer of the document. * * @param producer The new producer for the document. */ public void setProducer( String producer ) { info.setString( COSName.PRODUCER, producer ); } /** * This will get the creation date of the document. This will return null if no creation date exists. * * @return The creation date of the document. * * @throws IOException If there is an error creating the date. */ public Calendar getCreationDate() throws IOException { return info.getDate( COSName.CREATION_DATE ); } /** * This will set the creation date of the document. * * @param date The new creation date for the document. */ public void setCreationDate( Calendar date ) { info.setDate( COSName.CREATION_DATE, date ); } /** * This will get the modification date of the document. This will return null if no modification date exists. * * @return The modification date of the document. * * @throws IOException If there is an error creating the date. */ public Calendar getModificationDate() throws IOException { return info.getDate( COSName.MOD_DATE ); } /** * This will set the modification date of the document. * * @param date The new modification date for the document. */ public void setModificationDate( Calendar date ) { info.setDate( COSName.MOD_DATE, date ); } /** * This will get the trapped value for the document. * This will return null if one is not found. * * @return The trapped value for the document. */ public String getTrapped() { return info.getNameAsString( COSName.TRAPPED ); } /** * This will get the keys of all metadata information fields for the document. * * @return all metadata key strings. * @since Apache PDFBox 1.3.0 */ public Set getMetadataKeys() { Set keys = new TreeSet(); for (COSName key : info.keySet()) { keys.add(key.getName()); } return keys; } /** * This will get the value of a custom metadata information field for the document. * This will return null if one is not found. * * @param fieldName Name of custom metadata field from pdf document. * * @return String Value of metadata field * */ public String getCustomMetadataValue(String fieldName) { return info.getString( fieldName ); } /** * Set the custom metadata value. * * @param fieldName The name of the custom metadata field. * @param fieldValue The value to the custom metadata field. */ public void setCustomMetadataValue( String fieldName, String fieldValue ) { info.setString( fieldName, fieldValue ); } /** * This will set the trapped of the document. This will be * 'True', 'False', or 'Unknown'. * * @param value The new trapped value for the document. */ public void setTrapped( String value ) { if( value != null && !value.equals( "True" ) && !value.equals( "False" ) && !value.equals( "Unknown" ) ) { throw new RuntimeException( "Valid values for trapped are " + "'True', 'False', or 'Unknown'" ); } info.setName( COSName.TRAPPED, value ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java0000644000000000000000000005335212645757432025506 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSDictionaryMap; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFontFactory; import org.apache.pdfbox.pdmodel.graphics.PDExtendedGraphicsState; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; import org.apache.pdfbox.pdmodel.graphics.pattern.PDPatternResources; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingResources; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage; import org.apache.pdfbox.pdmodel.markedcontent.PDPropertyList; import org.apache.pdfbox.util.MapUtil; /** * This represents a set of resources available at the page/pages/stream level. * * @author Ben Litchfield * @author BM * */ public class PDResources implements COSObjectable { private COSDictionary resources; private Map fonts = null; private Map fontMappings = new HashMap(); private Map colorspaces = null; private Map xobjects = null; private Map xobjectMappings = null; private HashMap images = null; private Map graphicsStates = null; private Map patterns = null; private Map shadings = null; /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDResources.class); /** * Default constructor. */ public PDResources() { resources = new COSDictionary(); } /** * Prepopulated resources. * * @param resourceDictionary The cos dictionary for this resource. */ public PDResources(COSDictionary resourceDictionary) { resources = resourceDictionary; } /** * This will get the underlying dictionary. * * @return The dictionary for these resources. */ public COSDictionary getCOSDictionary() { return resources; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return resources; } /** * Calling this will release all cached information. * */ public void clear() { if (fonts != null) { for(PDFont font : fonts.values()) { font.clear(); } fonts.clear(); fonts = null; } if (fontMappings != null) { fontMappings.clear(); fontMappings = null; } if (colorspaces != null) { colorspaces.clear(); colorspaces = null; } if (xobjects != null) { for(PDXObject xobject : xobjects.values()) { xobject.clear(); } xobjects.clear(); xobjects = null; } if (xobjectMappings != null) { xobjectMappings.clear(); xobjectMappings = null; } if (images != null) { images.clear(); images = null; } if (graphicsStates != null) { graphicsStates.clear(); graphicsStates = null; } if (patterns != null) { patterns.clear(); patterns = null; } if (shadings != null) { shadings.clear(); shadings = null; } } /** * This will get the map of fonts. This will never return null. The keys are string and the values are PDFont * objects. * * @param fontCache A map of existing PDFont objects to reuse. * @return The map of fonts. * * @throws IOException If there is an error getting the fonts. * * @deprecated due to some side effects font caching is no longer supported, use {@link #getFonts()} instead */ public Map getFonts(Map fontCache) throws IOException { return getFonts(); } /** * This will get the map of fonts. This will never return null. * * @return The map of fonts. */ public Map getFonts() { if (fonts == null) { // at least an empty map will be returned // TODO we should return null instead of an empty map fonts = new HashMap(); COSDictionary fontsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.FONT); if (fontsDictionary == null) { fontsDictionary = new COSDictionary(); resources.setItem(COSName.FONT, fontsDictionary); } else { for (COSName fontName : fontsDictionary.keySet()) { COSBase font = fontsDictionary.getDictionaryObject(fontName); // data-000174.pdf contains a font that is a COSArray, looks to be an error in the // PDF, we will just ignore entries that are not dictionaries. if (font instanceof COSDictionary) { PDFont newFont = null; try { newFont = PDFontFactory.createFont((COSDictionary) font); } catch (IOException exception) { LOG.error("error while creating a font", exception); } if (newFont != null) { fonts.put(fontName.getName(), newFont); } } } } setFonts(fonts); } return fonts; } /** * This will get the map of PDXObjects that are in the resource dictionary. This will never return null. * * @return The map of xobjects. */ public Map getXObjects() { if (xobjects == null) { // at least an empty map will be returned // TODO we should return null instead of an empty map xobjects = new HashMap(); COSDictionary xobjectsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.XOBJECT); if (xobjectsDictionary == null) { xobjectsDictionary = new COSDictionary(); resources.setItem(COSName.XOBJECT, xobjectsDictionary); } else { xobjects = new HashMap(); for (COSName objName : xobjectsDictionary.keySet()) { PDXObject xobject = null; try { xobject = PDXObject.createXObject(xobjectsDictionary.getDictionaryObject(objName)); } catch (IOException exception) { LOG.error("error while creating a xobject", exception); } if (xobject != null) { xobjects.put(objName.getName(), xobject); } } } setXObjects(xobjects); } return xobjects; } /** * This will get the map of images. An empty map will be returned if there are no underlying images. So far the keys * are COSName of the image and the value is the corresponding PDXObjectImage. * * @return The map of images. * @throws IOException If there is an error writing the picture. * * @deprecated use {@link #getXObjects()} instead, as the images map isn't synchronized with the XObjects map. */ public Map getImages() throws IOException { if (images == null) { Map allXObjects = getXObjects(); images = new HashMap(); for (Map.Entry entry : allXObjects.entrySet()) { PDXObject xobject = entry.getValue(); if (xobject instanceof PDXObjectImage) { images.put(entry.getKey(), (PDXObjectImage) xobject); } } } return images; } /** * This will set the map of fonts. * * @param fontsValue The new map of fonts. */ public void setFonts(Map fontsValue) { fonts = fontsValue; if (fontsValue != null) { resources.setItem(COSName.FONT, COSDictionaryMap.convert(fontsValue)); fontMappings = reverseMap(fontsValue, PDFont.class); } else { resources.removeItem(COSName.FONT); fontMappings = null; } } /** * This will set the map of xobjects. * * @param xobjectsValue The new map of xobjects. */ public void setXObjects(Map xobjectsValue) { xobjects = xobjectsValue; if (xobjectsValue != null) { resources.setItem(COSName.XOBJECT, COSDictionaryMap.convert(xobjectsValue)); xobjectMappings = reverseMap(xobjects, PDXObject.class); } else { resources.removeItem(COSName.XOBJECT); xobjectMappings = null; } } /** * This will get the map of colorspaces. This will return null if the underlying resources dictionary does not have * a colorspace dictionary. The keys are string and the values are PDColorSpace objects. * * @return The map of colorspaces. */ public Map getColorSpaces() { if (colorspaces == null) { COSDictionary csDictionary = (COSDictionary) resources.getDictionaryObject(COSName.COLORSPACE); if (csDictionary != null) { colorspaces = new HashMap(); for (COSName csName : csDictionary.keySet()) { COSBase cs = csDictionary.getDictionaryObject(csName); PDColorSpace colorspace = null; try { colorspace = PDColorSpaceFactory.createColorSpace(cs); } catch (IOException exception) { LOG.error("error while creating a colorspace", exception); } if (colorspace != null) { colorspaces.put(csName.getName(), colorspace); } } } } return colorspaces; } /** * This will set the map of colorspaces. * * @param csValue The new map of colorspaces. */ public void setColorSpaces(Map csValue) { colorspaces = csValue; if (csValue != null) { resources.setItem(COSName.COLORSPACE, COSDictionaryMap.convert(csValue)); } else { resources.removeItem(COSName.COLORSPACE); } } /** * This will get the map of graphic states. This will return null if the underlying resources dictionary does not * have a graphics dictionary. The keys are the graphic state name as a String and the values are * PDExtendedGraphicsState objects. * * @return The map of extended graphic state objects. */ public Map getGraphicsStates() { if (graphicsStates == null) { COSDictionary states = (COSDictionary) resources.getDictionaryObject(COSName.EXT_G_STATE); if (states != null) { graphicsStates = new HashMap(); for (COSName name : states.keySet()) { COSDictionary dictionary = (COSDictionary) states.getDictionaryObject(name); graphicsStates.put(name.getName(), new PDExtendedGraphicsState(dictionary)); } } } return graphicsStates; } /** * This will set the map of graphics states. * * @param states The new map of states. */ public void setGraphicsStates(Map states) { graphicsStates = states; if (states != null) { Iterator iter = states.keySet().iterator(); COSDictionary dic = new COSDictionary(); while (iter.hasNext()) { String name = (String) iter.next(); PDExtendedGraphicsState state = states.get(name); dic.setItem(COSName.getPDFName(name), state.getCOSObject()); } resources.setItem(COSName.EXT_G_STATE, dic); } else { resources.removeItem(COSName.EXT_G_STATE); } } /** * Returns the dictionary mapping resource names to property list dictionaries for marked content. * * @return the property list */ public PDPropertyList getProperties() { PDPropertyList retval = null; COSDictionary props = (COSDictionary) resources.getDictionaryObject(COSName.PROPERTIES); if (props != null) { retval = new PDPropertyList(props); } return retval; } /** * Sets the dictionary mapping resource names to property list dictionaries for marked content. * * @param props the property list */ public void setProperties(PDPropertyList props) { resources.setItem(COSName.PROPERTIES, props.getCOSObject()); } /** * This will get the map of patterns. This will return null if the underlying resources dictionary does not have a * patterns dictionary. The keys are the pattern name as a String and the values are PDPatternResources objects. * * @return The map of pattern resources objects. * * @throws IOException If there is an error getting the pattern resources. */ public Map getPatterns() throws IOException { if (patterns == null) { COSDictionary patternsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.PATTERN); if (patternsDictionary != null) { patterns = new HashMap(); for (COSName name : patternsDictionary.keySet()) { COSDictionary dictionary = (COSDictionary) patternsDictionary.getDictionaryObject(name); patterns.put(name.getName(), PDPatternResources.create(dictionary)); } } } return patterns; } /** * This will set the map of patterns. * * @param patternsValue The new map of patterns. */ public void setPatterns(Map patternsValue) { patterns = patternsValue; if (patternsValue != null) { Iterator iter = patternsValue.keySet().iterator(); COSDictionary dic = new COSDictionary(); while (iter.hasNext()) { String name = iter.next(); PDPatternResources pattern = patternsValue.get(name); dic.setItem(COSName.getPDFName(name), pattern.getCOSObject()); } resources.setItem(COSName.PATTERN, dic); } else { resources.removeItem(COSName.PATTERN); } } /** * This will get the map of shadings. This will return null if the underlying resources dictionary does not have a * shading dictionary. The keys are the shading name as a String and the values are PDShadingResources objects. * * @return The map of shading resources objects. * * @throws IOException If there is an error getting the shading resources. */ public Map getShadings() throws IOException { if (shadings == null) { COSDictionary shadingsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.SHADING); if (shadingsDictionary != null) { shadings = new HashMap(); for (COSName name : shadingsDictionary.keySet()) { COSDictionary dictionary = (COSDictionary) shadingsDictionary.getDictionaryObject(name); shadings.put(name.getName(), PDShadingResources.create(dictionary)); } } } return shadings; } /** * This will set the map of shadings. * * @param shadingsValue The new map of shadings. */ public void setShadings(Map shadingsValue) { shadings = shadingsValue; if (shadingsValue != null) { Iterator iter = shadingsValue.keySet().iterator(); COSDictionary dic = new COSDictionary(); while (iter.hasNext()) { String name = iter.next(); PDShadingResources shading = shadingsValue.get(name); dic.setItem(COSName.getPDFName(name), shading.getCOSObject()); } resources.setItem(COSName.SHADING, dic); } else { resources.removeItem(COSName.SHADING); } } /** * Adds the given font to the resources of the current page. * * @param font the font to be added * @return the font name to be used within the content stream. */ public String addFont(PDFont font) { // use the getter to initialize a possible empty fonts map return addFont(font, MapUtil.getNextUniqueKey(getFonts(), "F")); } /** * Adds the given font to the resources of the current page using the given font key. * * @param font the font to be added * @param fontKey key to used to map to the given font * @return the font name to be used within the content stream. */ public String addFont(PDFont font, String fontKey) { if (fonts == null) { // initialize fonts map getFonts(); } String fontMapping = fontMappings.get(font); if (fontMapping == null) { fontMapping = fontKey; fontMappings.put(font, fontMapping); fonts.put(fontMapping, font); addFontToDictionary(font, fontMapping); } return fontMapping; } private void addFontToDictionary(PDFont font, String fontName) { COSDictionary fontsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.FONT); fontsDictionary.setItem(fontName, font); } /** * Adds the given XObject to the resources of the current the page. * * @param xobject the XObject to be added * @param prefix the prefix to be used for the name * * @return the XObject name to be used within the content stream. */ public String addXObject(PDXObject xobject, String prefix) { if (xobjects == null) { // initialize XObject map getXObjects(); } String objMapping = xobjectMappings.get(xobject); if (objMapping == null) { objMapping = MapUtil.getNextUniqueKey(xobjects, prefix); xobjectMappings.put(xobject, objMapping); xobjects.put(objMapping, xobject); addXObjectToDictionary(xobject, objMapping); } return objMapping; } private void addXObjectToDictionary(PDXObject xobject, String xobjectName) { COSDictionary xobjectsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.XOBJECT); xobjectsDictionary.setItem(xobjectName, xobject); } private Map reverseMap(Map map, Class keyClass) { Map reversed = new java.util.HashMap(); for (Map.Entry entry : map.entrySet()) { reversed.put(keyClass.cast(entry.getValue()), (String) entry.getKey()); } return reversed; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/0000755000000000000000000000000012645757432024752 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/0000755000000000000000000000000012645757432030650 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/0000755000000000000000000000000012645757432032327 5ustar rootroot././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/0000644000000000000000000000172412645757432032335 0ustar rootroot The outline package allows for a PDF outline(bookmarks) to be created. ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineNode.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/0000644000000000000000000002172512645757432032340 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This represents an node in an outline in a pdf document. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class PDOutlineNode implements COSObjectable { /** * The dictionary for this node. */ protected COSDictionary node; /** * Default Constructor. */ public PDOutlineNode() { node = new COSDictionary(); } /** * Default Constructor. * * @param dict The dictionary storage. */ public PDOutlineNode( COSDictionary dict) { node = dict; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return node; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return node; } /** * Get the parent of this object. This will either be a DocumentOutline or an OutlineItem. * * @return The parent of this object, or null if this is the document outline and there * is no parent. */ protected PDOutlineNode getParent() { PDOutlineNode retval = null; COSDictionary parent = (COSDictionary)node.getDictionaryObject( "Parent", "P" ); if( parent != null ) { if( parent.getDictionaryObject( "Parent", "P" ) == null ) { retval = new PDDocumentOutline( parent ); } else { retval = new PDOutlineItem( parent ); } } return retval; } /** * Set the parent of this object, this is maintained by these objects and should not * be called by any clients of PDFBox code. * * @param parent The parent of this object. */ protected void setParent( PDOutlineNode parent ) { node.setItem( "Parent", parent ); } /** * append a child node to this node. * * @param outlineNode The node to add. */ public void appendChild( PDOutlineItem outlineNode ) { outlineNode.setParent( this ); if( getFirstChild() == null ) { int currentOpenCount = getOpenCount(); setFirstChild( outlineNode ); //1 for the the item we are adding; int numberOfOpenNodesWeAreAdding = 1; if( outlineNode.isNodeOpen() ) { numberOfOpenNodesWeAreAdding += outlineNode.getOpenCount(); } if( isNodeOpen() ) { setOpenCount( currentOpenCount + numberOfOpenNodesWeAreAdding ); } else { setOpenCount( currentOpenCount - numberOfOpenNodesWeAreAdding ); } updateParentOpenCount( numberOfOpenNodesWeAreAdding ); } else { PDOutlineItem previousLastChild = getLastChild(); previousLastChild.insertSiblingAfter( outlineNode ); } PDOutlineItem lastNode = outlineNode; while(lastNode.getNextSibling() != null) { lastNode = lastNode.getNextSibling(); } setLastChild( lastNode ); } /** * Return the first child or null if there is no child. * * @return The first child. */ public PDOutlineItem getFirstChild() { PDOutlineItem last = null; COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "First" ); if( lastDic != null ) { last = new PDOutlineItem( lastDic ); } return last; } /** * Set the first child, this will be maintained by this class. * * @param outlineNode The new first child. */ protected void setFirstChild( PDOutlineNode outlineNode ) { node.setItem( "First", outlineNode ); } /** * Return the last child or null if there is no child. * * @return The last child. */ public PDOutlineItem getLastChild() { PDOutlineItem last = null; COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "Last" ); if( lastDic != null ) { last = new PDOutlineItem( lastDic ); } return last; } /** * Set the last child, this will be maintained by this class. * * @param outlineNode The new last child. */ protected void setLastChild( PDOutlineNode outlineNode ) { node.setItem( "Last", outlineNode ); } /** * Get the number of open nodes. Or a negative number if this node * is closed. See PDF Reference for more details. This value * is updated as you append children and siblings. * * @return The Count attribute of the outline dictionary. */ public int getOpenCount() { return node.getInt( "Count", 0 ); } /** * Set the open count. This number is automatically managed for you * when you add items to the outline. * * @param openCount The new open cound. */ protected void setOpenCount( int openCount ) { node.setInt( "Count", openCount ); } /** * This will set this node to be open when it is shown in the viewer. By default, when * a new node is created it will be closed. * This will do nothing if the node is already open. */ public void openNode() { //if the node is already open then do nothing. if( !isNodeOpen() ) { int openChildrenCount = 0; PDOutlineItem currentChild = getFirstChild(); while( currentChild != null ) { //first increase by one for the current child openChildrenCount++; //then increase by the number of open nodes the child has if( currentChild.isNodeOpen() ) { openChildrenCount += currentChild.getOpenCount(); } currentChild = currentChild.getNextSibling(); } setOpenCount( openChildrenCount ); updateParentOpenCount( openChildrenCount ); } } /** * Close this node. * */ public void closeNode() { //if the node is already closed then do nothing. if( isNodeOpen() ) { int openCount = getOpenCount(); updateParentOpenCount( -openCount ); setOpenCount( -openCount ); } } /** * Node is open if the open count is greater than zero. * @return true if this node is open. */ public boolean isNodeOpen() { return getOpenCount() > 0; } /** * The count parameter needs to be updated when you add or remove elements to * the outline. When you add an element at a lower level then you need to * increase all of the parents. * * @param amount The amount to update by. */ protected void updateParentOpenCount( int amount ) { PDOutlineNode parent = getParent(); if( parent != null ) { int currentCount = parent.getOpenCount(); //if the currentCount is negative or it is absent then //we will treat it as negative. The default is to be negative. boolean negative = currentCount < 0 || parent.getCOSDictionary().getDictionaryObject( "Count" ) == null; currentCount = Math.abs( currentCount ); currentCount += amount; if( negative ) { currentCount = -currentCount; } parent.setOpenCount( currentCount ); //recursively call parent to update count, but the parents count is only //updated if this is an open node if( !negative ) { parent.updateParentOpenCount( amount ); } } } } ././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/PDDocumentOutline.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/0000644000000000000000000000272212645757432032334 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline; import org.apache.pdfbox.cos.COSDictionary; /** * This represents an outline in a pdf document. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDDocumentOutline extends PDOutlineNode { /** * Default Constructor. */ public PDDocumentOutline() { super(); node.setName( "Type", "Outlines" ); } /** * Constructor for an existing document outline. * * @param dic The storage dictionary. */ public PDDocumentOutline( COSDictionary dic ) { super( dic ); } } ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineItem.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/outline/0000644000000000000000000003170212645757432032334 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline; import java.awt.Color; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.exceptions.OutlineNotLocalException; import org.apache.pdfbox.pdmodel.PDDestinationNameTreeNode; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentNameDestinationDictionary; import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionGoTo; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDNamedDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination; import org.apache.pdfbox.util.BitFlagHelper; /** * This represents an outline in a pdf document. * * @author Ben Litchfield * @version $Revision: 1.7 $ */ public class PDOutlineItem extends PDOutlineNode { private static final int ITALIC_FLAG = 1; private static final int BOLD_FLAG = 2; /** * Default Constructor. */ public PDOutlineItem() { super(); } /** * Constructor for an existing outline item. * * @param dic The storage dictionary. */ public PDOutlineItem( COSDictionary dic ) { super( dic ); } /** * Insert a sibling after this node. * * @param item The item to insert. */ public void insertSiblingAfter( PDOutlineItem item ) { item.setParent( getParent() ); PDOutlineItem next = getNextSibling(); setNextSibling( item ); item.setPreviousSibling( this ); if( next != null ) { item.setNextSibling( next ); next.setPreviousSibling( item ); } updateParentOpenCount( 1 ); } /** * {@inheritDoc} */ public PDOutlineNode getParent() { return super.getParent(); } /** * Return the previous sibling or null if there is no sibling. * * @return The previous sibling. */ public PDOutlineItem getPreviousSibling() { PDOutlineItem last = null; COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( COSName.PREV ); if( lastDic != null ) { last = new PDOutlineItem( lastDic ); } return last; } /** * Set the previous sibling, this will be maintained by this class. * * @param outlineNode The new previous sibling. */ protected void setPreviousSibling( PDOutlineNode outlineNode ) { node.setItem( COSName.PREV, outlineNode ); } /** * Return the next sibling or null if there is no next sibling. * * @return The next sibling. */ public PDOutlineItem getNextSibling() { PDOutlineItem last = null; COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( COSName.NEXT ); if( lastDic != null ) { last = new PDOutlineItem( lastDic ); } return last; } /** * Set the next sibling, this will be maintained by this class. * * @param outlineNode The new next sibling. */ protected void setNextSibling( PDOutlineNode outlineNode ) { node.setItem( COSName.NEXT, outlineNode ); } /** * Get the title of this node. * * @return The title of this node. */ public String getTitle() { return node.getString( COSName.TITLE ); } /** * Set the title for this node. * * @param title The new title for this node. */ public void setTitle( String title ) { node.setString( COSName.TITLE, title ); } /** * Get the page destination of this node. * * @return The page destination of this node. * @throws IOException If there is an error creating the destination. */ public PDDestination getDestination() throws IOException { return PDDestination.create( node.getDictionaryObject( COSName.DEST ) ); } /** * Set the page destination for this node. * * @param dest The new page destination for this node. */ public void setDestination( PDDestination dest ) { node.setItem( COSName.DEST, dest ); } /** * A convenience method that will create an XYZ destination using only the defaults. * * @param page The page to refer to. */ public void setDestination( PDPage page ) { PDPageXYZDestination dest = null; if( page != null ) { dest = new PDPageXYZDestination(); dest.setPage( page ); } setDestination( dest ); } /** * This method will attempt to find the page in this PDF document that this outline points to. * If the outline does not point to anything then this method will return null. If the outline * is an action that is not a GoTo action then this method will also return null. * * @param doc The document to get the page from. * * @return The page that this outline will go to when activated or null if it does not point to anything. * @throws IOException If there is an error when trying to find the page. */ public PDPage findDestinationPage( PDDocument doc ) throws IOException { PDPage page = null; PDDestination rawDest = getDestination(); if( rawDest == null ) { PDAction outlineAction = getAction(); if( outlineAction instanceof PDActionGoTo ) { rawDest = ((PDActionGoTo)outlineAction).getDestination(); } else if( outlineAction == null ) { //if the outline action is null then this outline does not refer //to anything and we will just return null. } else { throw new OutlineNotLocalException( "Error: Outline does not reference a local page." ); } } PDPageDestination pageDest = null; if( rawDest instanceof PDNamedDestination ) { //if we have a named destination we need to lookup the PDPageDestination PDNamedDestination namedDest = (PDNamedDestination)rawDest; PDDocumentNameDictionary namesDict = doc.getDocumentCatalog().getNames(); if( namesDict != null ) { PDDestinationNameTreeNode destsTree = namesDict.getDests(); if( destsTree != null ) { pageDest = (PDPageDestination)destsTree.getValue( namedDest.getNamedDestination() ); } } else { // Look up /Dests dictionary from catalog PDDocumentNameDestinationDictionary nameDestDict = doc.getDocumentCatalog().getDests(); if (nameDestDict != null) { String name = namedDest.getNamedDestination(); pageDest = (PDPageDestination) nameDestDict.getDestination(name); } } } else if( rawDest instanceof PDPageDestination) { pageDest = (PDPageDestination) rawDest; } else if( rawDest == null ) { //if the destination is null then we will simply return a null page. } else { throw new IOException( "Error: Unknown destination type " + rawDest ); } if( pageDest != null ) { page = pageDest.getPage(); if( page == null ) { // Malformed PDF: local destinations must have a page object, // not a page number, these are meant for remote destinations. int pageNumber = pageDest.getPageNumber(); if( pageNumber != -1 ) { List allPages = doc.getDocumentCatalog().getAllPages(); page = (PDPage)allPages.get( pageNumber ); } } } return page; } /** * Get the action of this node. * * @return The action of this node. */ public PDAction getAction() { return PDActionFactory.createAction( (COSDictionary)node.getDictionaryObject( COSName.A ) ); } /** * Set the action for this node. * * @param action The new action for this node. */ public void setAction( PDAction action ) { node.setItem( COSName.A, action ); } /** * Get the structure element of this node. * * @return The structure element of this node. */ public PDStructureElement getStructureElement() { PDStructureElement se = null; COSDictionary dic = (COSDictionary)node.getDictionaryObject( COSName.SE ); if( dic != null ) { se = new PDStructureElement( dic ); } return se; } /** * Set the structure element for this node. * * @param structureElement The new structure element for this node. */ public void setStructuredElement( PDStructureElement structureElement ) { node.setItem( COSName.SE, structureElement ); } /** * Get the text color of this node. Default is black and this method * will never return null. * * @return The structure element of this node. */ public PDColorState getTextColor() { PDColorState retval = null; COSArray csValues = (COSArray)node.getDictionaryObject( COSName.C ); if( csValues == null ) { csValues = new COSArray(); csValues.growToSize( 3, new COSFloat( 0 ) ); node.setItem( COSName.C, csValues ); } retval = new PDColorState(csValues); retval.setColorSpace( PDDeviceRGB.INSTANCE ); return retval; } /** * Set the text color for this node. The colorspace must be a PDDeviceRGB. * * @param textColor The text color for this node. */ public void setTextColor( PDColorState textColor ) { node.setItem( COSName.C, textColor.getCOSColorSpaceValue() ); } /** * Set the text color for this node. The colorspace must be a PDDeviceRGB. * * @param textColor The text color for this node. */ public void setTextColor( Color textColor ) { COSArray array = new COSArray(); array.add( new COSFloat( textColor.getRed()/255f)); array.add( new COSFloat( textColor.getGreen()/255f)); array.add( new COSFloat( textColor.getBlue()/255f)); node.setItem( COSName.C, array ); } /** * A flag telling if the text should be italic. * * @return The italic flag. */ public boolean isItalic() { return BitFlagHelper.getFlag( node, COSName.F, ITALIC_FLAG ); } /** * Set the italic property of the text. * * @param italic The new italic flag. */ public void setItalic( boolean italic ) { BitFlagHelper.setFlag( node, COSName.F, ITALIC_FLAG, italic ); } /** * A flag telling if the text should be bold. * * @return The bold flag. */ public boolean isBold() { return BitFlagHelper.getFlag( node, COSName.F, BOLD_FLAG ); } /** * Set the bold property of the text. * * @param bold The new bold flag. */ public void setBold( boolean bold ) { BitFlagHelper.setFlag( node, COSName.F, BOLD_FLAG, bold ); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/package.0000644000000000000000000000173312645757432032250 0ustar rootroot A package to allow access to document level navigation within a PDF document. ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000755000000000000000000000000012645757432032404 5ustar rootroot././@LongLink0000644000000000000000000000021300000000000011577 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitRectangleDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000001034712645757432032413 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; /** * This represents a destination to a page at a y location and the width is magnified * to just fit on the screen. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDPageFitRectangleDestination extends PDPageDestination { /** * The type of this destination. */ protected static final String TYPE = "FitR"; /** * Default constructor. * */ public PDPageFitRectangleDestination() { super(); array.growToSize(6); array.setName( 1, TYPE ); } /** * Constructor from an existing destination array. * * @param arr The destination array. */ public PDPageFitRectangleDestination( COSArray arr ) { super( arr ); } /** * Get the left x coordinate. A return value of -1 implies that the current x-coordinate * will be used. * * @return The left x coordinate. */ public int getLeft() { return array.getInt( 2 ); } /** * Set the left x-coordinate, a value of -1 implies that the current x-coordinate * will be used. * @param x The left x coordinate. */ public void setLeft( int x ) { array.growToSize( 3 ); if( x == -1 ) { array.set( 2, (COSBase)null ); } else { array.setInt( 2, x ); } } /** * Get the bottom y coordinate. A return value of -1 implies that the current y-coordinate * will be used. * * @return The bottom y coordinate. */ public int getBottom() { return array.getInt( 3 ); } /** * Set the bottom y-coordinate, a value of -1 implies that the current y-coordinate * will be used. * @param y The bottom y coordinate. */ public void setBottom( int y ) { array.growToSize( 6 ); if( y == -1 ) { array.set( 3, (COSBase)null ); } else { array.setInt( 3, y ); } } /** * Get the right x coordinate. A return value of -1 implies that the current x-coordinate * will be used. * * @return The right x coordinate. */ public int getRight() { return array.getInt( 4 ); } /** * Set the right x-coordinate, a value of -1 implies that the current x-coordinate * will be used. * @param x The right x coordinate. */ public void setRight( int x ) { array.growToSize( 6 ); if( x == -1 ) { array.set( 4, (COSBase)null ); } else { array.setInt( 4, x ); } } /** * Get the top y coordinate. A return value of -1 implies that the current y-coordinate * will be used. * * @return The top y coordinate. */ public int getTop() { return array.getInt( 5 ); } /** * Set the top y-coordinate, a value of -1 implies that the current y-coordinate * will be used. * @param y The top ycoordinate. */ public void setTop( int y ) { array.growToSize( 6 ); if( y == -1 ) { array.set( 5, (COSBase)null ); } else { array.setInt( 5, y ); } } } ././@LongLink0000644000000000000000000000021000000000000011574 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitHeightDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000630112645757432032406 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; /** * This represents a destination to a page at a x location and the height is magnified * to just fit on the screen. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDPageFitHeightDestination extends PDPageDestination { /** * The type of this destination. */ protected static final String TYPE = "FitV"; /** * The type of this destination. */ protected static final String TYPE_BOUNDED = "FitBV"; /** * Default constructor. * */ public PDPageFitHeightDestination() { super(); array.growToSize(3); array.setName( 1, TYPE ); } /** * Constructor from an existing destination array. * * @param arr The destination array. */ public PDPageFitHeightDestination( COSArray arr ) { super( arr ); } /** * Get the left x coordinate. A return value of -1 implies that the current x-coordinate * will be used. * * @return The left x coordinate. */ public int getLeft() { return array.getInt( 2 ); } /** * Set the left x-coordinate, a value of -1 implies that the current x-coordinate * will be used. * @param x The left x coordinate. */ public void setLeft( int x ) { array.growToSize( 3 ); if( x == -1 ) { array.set( 2, (COSBase)null ); } else { array.setInt( 2, x ); } } /** * A flag indicating if this page destination should just fit bounding box of the PDF. * * @return true If the destination should fit just the bounding box. */ public boolean fitBoundingBox() { return TYPE_BOUNDED.equals( array.getName( 1 ) ); } /** * Set if this page destination should just fit the bounding box. The default is false. * * @param fitBoundingBox A flag indicating if this should fit the bounding box. */ public void setFitBoundingBox( boolean fitBoundingBox ) { array.growToSize( 2 ); if( fitBoundingBox ) { array.setName( 1, TYPE_BOUNDED ); } else { array.setName( 1, TYPE ); } } } ././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000001603712645757432032415 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageNode; /** * This represents a destination to a page, see subclasses for specific parameters. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public abstract class PDPageDestination extends PDDestination { /** * Storage for the page destination. */ protected COSArray array; /** * Constructor to create empty page destination. * */ protected PDPageDestination() { array = new COSArray(); } /** * Constructor to create empty page destination. * * @param arr A page destination array. */ protected PDPageDestination( COSArray arr ) { array = arr; } /** * This will get the page for this destination. A page destination can either reference a page * (for a local destination) or a page number (when doing a remote destination to another PDF). * If this object is referencing by page number then this method will return null and * {@link #getPageNumber()} should be used. * * @return The page for this destination. */ public PDPage getPage() { PDPage retval = null; if( array.size() > 0 ) { COSBase page = array.getObject( 0 ); if( page instanceof COSDictionary ) { retval = new PDPage( (COSDictionary)page ); } } return retval; } /** * Set the page for this destination. * * @param page The page for the destination. */ public void setPage( PDPage page ) { array.set( 0, page ); } /** * This will get the page number for this destination. A page destination can either reference a * page (for a local destination) or a page number (when doing a remote destination to another * PDF). If this object is referencing by page number then this method will return that number, * otherwise -1 will be returned. * * @return The zero-based page number for this destination. */ public int getPageNumber() { int retval = -1; if( array.size() > 0 ) { COSBase page = array.getObject( 0 ); if( page instanceof COSNumber ) { retval = ((COSNumber)page).intValue(); } } return retval; } /** * Returns the page number for this destination, regardless of whether this is a page number or * a reference to a page. * * @since Apache PDFBox 1.0.0 * @see org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem * @return page number, or -1 if the destination type is unknown. The page number is 0-based if * it was in the dictionary (for remote destinations), and 1-based if it was computed from a * page reference (for local destinations). * @deprecated This method has inconsistent behavior (see returns), use {@link #retrieveDestPageNumber()} instead. */ @Deprecated public int findPageNumber() { int retval = -1; if( array.size() > 0 ) { COSBase page = array.getObject( 0 ); if( page instanceof COSNumber ) { retval = ((COSNumber)page).intValue(); } else if (page instanceof COSDictionary) { COSBase parent = page; while (((COSDictionary) parent).getDictionaryObject(COSName.PARENT, COSName.P) != null) { parent = ((COSDictionary) parent).getDictionaryObject(COSName.PARENT, COSName.P); } // now parent is the pages node PDPageNode pages = new PDPageNode((COSDictionary) parent); List allPages = new ArrayList(); pages.getAllKids(allPages); retval = allPages.indexOf(new PDPage((COSDictionary) page)) + 1; } } return retval; } /** * Returns the page number for this destination, regardless of whether this is a page number or * a reference to a page. * * @see org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem * @return the 0-based page number, or -1 if the destination type is unknown. */ public int retrieveDestPageNumber() { int retval = -1; if (array.size() > 0) { COSBase page = array.getObject(0); if (page instanceof COSNumber) { retval = ((COSNumber) page).intValue(); } else if (page instanceof COSDictionary) { COSBase parent = page; while (((COSDictionary) parent).getDictionaryObject(COSName.PARENT, COSName.P) != null) { parent = ((COSDictionary) parent).getDictionaryObject(COSName.PARENT, COSName.P); } // now parent is the pages node PDPageNode pages = new PDPageNode((COSDictionary) parent); List allPages = new ArrayList(); pages.getAllKids(allPages); retval = allPages.indexOf(new PDPage((COSDictionary) page)); } } return retval; } /** * Set the page number for this destination. * * @param pageNumber The page for the destination. */ public void setPageNumber( int pageNumber ) { array.set( 0, pageNumber ); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return array; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSArray getCOSArray() { return array; } } ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000173612645757432032415 0ustar rootroot The destination package allows destinations into a pdf document to be specified. ././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDNamedDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000645412645757432032417 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import java.io.IOException; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; /** * This represents a destination to a page by referencing it with a name. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class PDNamedDestination extends PDDestination { private COSBase namedDestination; /** * Constructor. * * @param dest The named destination. */ public PDNamedDestination( COSString dest ) { namedDestination = dest; } /** * Constructor. * * @param dest The named destination. */ public PDNamedDestination( COSName dest ) { namedDestination = dest; } /** * Default constructor. */ public PDNamedDestination() { //default, so do nothing } /** * Default constructor. * * @param dest The named destination. */ public PDNamedDestination( String dest ) { namedDestination = new COSString( dest ); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return namedDestination; } /** * This will get the name of the destination. * * @return The name of the destination. */ public String getNamedDestination() { String retval = null; if( namedDestination instanceof COSString ) { retval = ((COSString)namedDestination).getString(); } else if( namedDestination instanceof COSName ) { retval = ((COSName)namedDestination).getName(); } return retval; } /** * Set the named destination. * * @param dest The new named destination. * * @throws IOException If there is an error setting the named destination. */ public void setNamedDestination( String dest ) throws IOException { if( namedDestination instanceof COSString ) { COSString string = ((COSString)namedDestination); string.reset(); string.append( dest.getBytes("ISO-8859-1") ); } else if( dest == null ) { namedDestination = null; } else { namedDestination = new COSString( dest ); } } } ././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageXYZDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000755212645757432032417 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSNumber; /** * This represents a destination to a page at an x,y coordinate with a zoom setting. * The default x,y,z will be whatever is the current value in the viewer application and * are not required. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDPageXYZDestination extends PDPageDestination { /** * The type of this destination. */ protected static final String TYPE = "XYZ"; /** * Default constructor. * */ public PDPageXYZDestination() { super(); array.growToSize(5); array.setName( 1, TYPE ); } /** * Constructor from an existing destination array. * * @param arr The destination array. */ public PDPageXYZDestination( COSArray arr ) { super( arr ); } /** * Get the left x coordinate. Return values of 0 or -1 imply that the current x-coordinate * will be used. * * @return The left x coordinate. */ public int getLeft() { return array.getInt( 2 ); } /** * Set the left x-coordinate, values 0 or -1 imply that the current x-coordinate * will be used. * @param x The left x coordinate. */ public void setLeft( int x ) { array.growToSize( 3 ); if( x == -1 ) { array.set( 2, (COSBase)null ); } else { array.setInt( 2, x ); } } /** * Get the top y coordinate. Return values of 0 or -1 imply that the current y-coordinate * will be used. * * @return The top y coordinate. */ public int getTop() { return array.getInt( 3 ); } /** * Set the top y-coordinate, values 0 or -1 imply that the current y-coordinate * will be used. * @param y The top ycoordinate. */ public void setTop( int y ) { array.growToSize( 4 ); if( y == -1 ) { array.set( 3, (COSBase)null ); } else { array.setInt( 3, y ); } } /** * Get the zoom value. Return values of 0 or -1 imply that the current zoom * will be used. * * @return The zoom value for the page. */ public float getZoom() { COSBase obj = array.getObject(4); if (obj instanceof COSNumber) { return ((COSNumber) obj).floatValue(); } return -1; } /** * Set the zoom value for the page, values 0 or -1 imply that the current zoom * will be used. * @param zoom The zoom value. */ public void setZoom( float zoom ) { array.growToSize( 5 ); if( zoom == -1 ) { array.set( 4, (COSBase)null ); } else { array.set( 4, new COSFloat(zoom) ); } } } ././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000500412645757432032405 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import org.apache.pdfbox.cos.COSArray; /** * This represents a destination to a page and the page contents will be magnified to just * fit on the screen. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDPageFitDestination extends PDPageDestination { /** * The type of this destination. */ protected static final String TYPE = "Fit"; /** * The type of this destination. */ protected static final String TYPE_BOUNDED = "FitB"; /** * Default constructor. * */ public PDPageFitDestination() { super(); array.growToSize(2); array.setName( 1, TYPE ); } /** * Constructor from an existing destination array. * * @param arr The destination array. */ public PDPageFitDestination( COSArray arr ) { super( arr ); } /** * A flag indicating if this page destination should just fit bounding box of the PDF. * * @return true If the destination should fit just the bounding box. */ public boolean fitBoundingBox() { return TYPE_BOUNDED.equals( array.getName( 1 ) ); } /** * Set if this page destination should just fit the bounding box. The default is false. * * @param fitBoundingBox A flag indicating if this should fit the bounding box. */ public void setFitBoundingBox( boolean fitBoundingBox ) { array.growToSize( 2 ); if( fitBoundingBox ) { array.setName( 1, TYPE_BOUNDED ); } else { array.setName( 1, TYPE ); } } } ././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000762312645757432032416 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.common.PDDestinationOrAction; /** * This represents a destination in a PDF document. * * @author Ben Litchfield * @version $Revision: 1.6 $ */ public abstract class PDDestination implements PDDestinationOrAction { /** * This will create a new destination depending on the type of COSBase * that is passed in. * * @param base The base level object. * * @return A new destination. * * @throws IOException If the base cannot be converted to a Destination. */ public static PDDestination create( COSBase base ) throws IOException { PDDestination retval = null; if( base == null ) { //this is ok, just return null. } else if (base instanceof COSArray && ((COSArray) base).size() > 1 && ((COSArray) base).getObject(1) instanceof COSName) { COSArray array = (COSArray)base; COSName type = (COSName)array.getObject( 1 ); String typeString = type.getName(); if( typeString.equals( PDPageFitDestination.TYPE ) || typeString.equals( PDPageFitDestination.TYPE_BOUNDED )) { retval = new PDPageFitDestination( array ); } else if( typeString.equals( PDPageFitHeightDestination.TYPE ) || typeString.equals( PDPageFitHeightDestination.TYPE_BOUNDED )) { retval = new PDPageFitHeightDestination( array ); } else if( typeString.equals( PDPageFitRectangleDestination.TYPE ) ) { retval = new PDPageFitRectangleDestination( array ); } else if( typeString.equals( PDPageFitWidthDestination.TYPE ) || typeString.equals( PDPageFitWidthDestination.TYPE_BOUNDED )) { retval = new PDPageFitWidthDestination( array ); } else if( typeString.equals( PDPageXYZDestination.TYPE ) ) { retval = new PDPageXYZDestination( array ); } else { throw new IOException( "Unknown destination type: " + type.getName() ); } } else if( base instanceof COSString ) { retval = new PDNamedDestination( (COSString)base ); } else if( base instanceof COSName ) { retval = new PDNamedDestination( (COSName)base ); } else { throw new IOException( "Error: can't convert to Destination " + base ); } return retval; } /** * Return a string representation of this class. * * @return A human readable string. */ public String toString() { return super.toString(); } } ././@LongLink0000644000000000000000000000020700000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitWidthDestination.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/documentnavigation/destinat0000644000000000000000000000627012645757432032413 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; /** * This represents a destination to a page at a y location and the width is magnified * to just fit on the screen. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDPageFitWidthDestination extends PDPageDestination { /** * The type of this destination. */ protected static final String TYPE = "FitH"; /** * The type of this destination. */ protected static final String TYPE_BOUNDED = "FitBH"; /** * Default constructor. * */ public PDPageFitWidthDestination() { super(); array.growToSize(3); array.setName( 1, TYPE ); } /** * Constructor from an existing destination array. * * @param arr The destination array. */ public PDPageFitWidthDestination( COSArray arr ) { super( arr ); } /** * Get the top y coordinate. A return value of -1 implies that the current y-coordinate * will be used. * * @return The top y coordinate. */ public int getTop() { return array.getInt( 2 ); } /** * Set the top y-coordinate, a value of -1 implies that the current y-coordinate * will be used. * @param y The top ycoordinate. */ public void setTop( int y ) { array.growToSize( 3 ); if( y == -1 ) { array.set( 2, (COSBase)null ); } else { array.setInt( 2, y ); } } /** * A flag indicating if this page destination should just fit bounding box of the PDF. * * @return true If the destination should fit just the bounding box. */ public boolean fitBoundingBox() { return TYPE_BOUNDED.equals( array.getName( 1 ) ); } /** * Set if this page destination should just fit the bounding box. The default is false. * * @param fitBoundingBox A flag indicating if this should fit the bounding box. */ public void setFitBoundingBox( boolean fitBoundingBox ) { array.growToSize( 2 ); if( fitBoundingBox ) { array.setName( 1, TYPE_BOUNDED ); } else { array.setName( 1, TYPE ); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/0000755000000000000000000000000012645757432027277 5ustar rootroot././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDNumberFormatDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDNumberFormatD0000644000000000000000000002300112645757432032147 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.measurement; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This class represents a number format dictionary. * * @version $Revision: 1.0$ * */ public class PDNumberFormatDictionary implements COSObjectable { /** * The type of the dictionary. */ public static final String TYPE = "NumberFormat"; /** * Constant indicating that the label specified by U is a suffix to the value. */ public static final String LABEL_SUFFIX_TO_VALUE = "S"; /** * Constant indicating that the label specified by U is a postfix to the value. */ public static final String LABEL_PREFIX_TO_VALUE = "P"; /** * Constant for showing a fractional value as decimal to the precision specified by the D entry. */ public static final String FRACTIONAL_DISPLAY_DECIMAL = "D"; /** * Constant for showing a fractional value as a fraction with denominator specified by the D entry. */ public static final String FRACTIONAL_DISPLAY_FRACTION = "F"; /** * Constant for showing a fractional value without fractional part; round to the nearest whole unit. */ public static final String FRACTIONAL_DISPLAY_ROUND = "R"; /** * Constant for showing a fractional value without fractional part; truncate to achieve whole units. */ public static final String FRACTIONAL_DISPLAY_TRUNCATE = "T"; private COSDictionary numberFormatDictionary; /** * Constructor. */ public PDNumberFormatDictionary() { this.numberFormatDictionary = new COSDictionary(); this.numberFormatDictionary.setName(COSName.TYPE, TYPE); } /** * Constructor. * * @param dictionary the corresponding dictionary */ public PDNumberFormatDictionary(COSDictionary dictionary) { this.numberFormatDictionary = dictionary; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return this.numberFormatDictionary; } /** * This will return the dictionary. * * @return the number format dictionary */ public COSDictionary getDictionary() { return this.numberFormatDictionary; } /** * This will return the type of the number format dictionary. * It must be "NumberFormat" * * @return the type */ public String getType() { return TYPE; } /** * This will return the label for the units. * * @return the label for the units */ public String getUnits() { return this.getDictionary().getString("U"); } /** * This will set the label for the units. * * @param units the label for the units */ public void setUnits(String units) { this.getDictionary().setString("U", units); } /** * This will return the conversion factor. * * @return the conversion factor */ public float getConversionFactor() { return this.getDictionary().getFloat("C"); } /** * This will set the conversion factor. * * @param conversionFactor the conversion factor */ public void setConversionFactor(float conversionFactor) { this.getDictionary().setFloat("C", conversionFactor); } /** * This will return the value for the manner to display a fractional value. * * @return the manner to display a fractional value */ public String getFractionalDisplay() { return this.getDictionary().getString("F", FRACTIONAL_DISPLAY_DECIMAL); } /** * This will set the value for the manner to display a fractional value. * Allowed values are "D", "F", "R" and "T" * @param fractionalDisplay the manner to display a fractional value */ public void setFractionalDisplay(String fractionalDisplay) { if ((fractionalDisplay == null) || FRACTIONAL_DISPLAY_DECIMAL.equals(fractionalDisplay) || FRACTIONAL_DISPLAY_FRACTION.equals(fractionalDisplay) || FRACTIONAL_DISPLAY_ROUND.equals(fractionalDisplay) || FRACTIONAL_DISPLAY_TRUNCATE.equals(fractionalDisplay)) { this.getDictionary().setString("F", fractionalDisplay); } else { throw new IllegalArgumentException("Value must be \"D\", \"F\", \"R\", or \"T\", (or null)."); } } /** * This will return the precision or denominator of a fractional amount. * * @return the precision or denominator */ public int getDenominator() { return this.getDictionary().getInt("D"); } /** * This will set the precision or denominator of a fractional amount. * * @param denominator the precision or denominator */ public void setDenominator(int denominator) { this.getDictionary().setInt("D", denominator); } /** * This will return the value indication if the denominator of the fractional value is reduced/truncated . * * @return fd */ public boolean isFD() { return this.getDictionary().getBoolean("FD", false); } /** * This will set the value indication if the denominator of the fractional value is reduced/truncated . * The denominator may not be reduced/truncated if true * @param fd fd */ public void setFD(boolean fd) { this.getDictionary().setBoolean("FD", fd); } /** * This will return the text to be used between orders of thousands in display of numerical values. * * @return thousands separator */ public String getThousandsSeparator() { return this.getDictionary().getString("RT", ","); } /** * This will set the text to be used between orders of thousands in display of numerical values. * * @param thousandsSeparator thousands separator */ public void setThousandsSeparator(String thousandsSeparator) { this.getDictionary().setString("RT", thousandsSeparator); } /** * This will return the text to be used as the decimal point in displaying numerical values. * * @return decimal separator */ public String getDecimalSeparator() { return this.getDictionary().getString("RD", "."); } /** * This will set the text to be used as the decimal point in displaying numerical values. * * @param decimalSeparator decimal separator */ public void setDecimalSeparator(String decimalSeparator) { this.getDictionary().setString("RD", decimalSeparator); } /** * This will return the text to be concatenated to the left of the label specified by U. * @return label prefix */ public String getLabelPrefixString() { return this.getDictionary().getString("PS", " "); } /** * This will set the text to be concatenated to the left of the label specified by U. * @param labelPrefixString label prefix */ public void setLabelPrefixString(String labelPrefixString) { this.getDictionary().setString("PS", labelPrefixString); } /** * This will return the text to be concatenated after the label specified by U. * * @return label suffix */ public String getLabelSuffixString() { return this.getDictionary().getString("SS", " "); } /** * This will set the text to be concatenated after the label specified by U. * * @param labelSuffixString label suffix */ public void setLabelSuffixString(String labelSuffixString) { this.getDictionary().setString("SS", labelSuffixString); } /** * This will return a value indicating the ordering of the label specified by U to the calculated unit value. * * @return label position */ public String getLabelPositionToValue() { return this.getDictionary().getString("O", LABEL_SUFFIX_TO_VALUE); } /** * This will set the value indicating the ordering of the label specified by U to the calculated unit value. * Possible values are "S" and "P" * * @param labelPositionToValue label position */ public void setLabelPositionToValue(String labelPositionToValue) { if ((labelPositionToValue == null) || LABEL_PREFIX_TO_VALUE.equals(labelPositionToValue) || LABEL_SUFFIX_TO_VALUE.equals(labelPositionToValue)) { this.getDictionary().setString("O", labelPositionToValue); } else { throw new IllegalArgumentException("Value must be \"S\", or \"P\" (or null)."); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/package.html0000644000000000000000000000175512645757432031570 0ustar rootroot The measurement package contains classes that work with elements specifying measure properties. ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDViewportDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDViewportDicti0000644000000000000000000000773412645757432032255 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.measurement; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * This class represents a viewport dictionary. * * @version $Revision: 1.0 $ * */ public class PDViewportDictionary implements COSObjectable { /** * The type of this annotation. */ public static final String TYPE = "Viewport"; private COSDictionary viewportDictionary; /** * Constructor. */ public PDViewportDictionary() { this.viewportDictionary = new COSDictionary(); } /** * Constructor. * * @param dictionary the dictionary */ public PDViewportDictionary(COSDictionary dictionary) { this.viewportDictionary = dictionary; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return this.viewportDictionary; } /** * This will return the corresponding dictionary. * * @return the viewport dictionary */ public COSDictionary getDictionary() { return this.viewportDictionary; } /** * Returns the type of the viewport dictionary. * It must be "Viewport" * @return the type of the external data dictionary */ public String getType() { return TYPE; } /** * This will retrieve the rectangle specifying the location of the viewport. * * @return the location */ public PDRectangle getBBox() { COSArray bbox = (COSArray)this.getDictionary().getDictionaryObject("BBox"); if (bbox != null) { return new PDRectangle(bbox); } return null; } /** * This will set the rectangle specifying the location of the viewport. * * @param rectangle the rectangle specifying the location. */ public void setBBox(PDRectangle rectangle) { this.getDictionary().setItem("BBox", rectangle); } /** * This will retrieve the name of the viewport. * * @return the name of the viewport */ public String getName() { return this.getDictionary().getNameAsString(COSName.NAME); } /** * This will set the name of the viewport. * * @param name the name of the viewport */ public void setName(String name) { this.getDictionary().setName(COSName.NAME, name); } /** * This will retrieve the measure dictionary. * * @return the measure dictionary */ public PDMeasureDictionary getMeasure() { COSDictionary measure = (COSDictionary)this.getDictionary().getDictionaryObject("Measure"); if (measure != null) { return new PDMeasureDictionary(measure); } return null; } /** * This will set the measure dictionary. * * @param measure the measure dictionary */ public void setMeasure(PDMeasureDictionary measure) { this.getDictionary().setItem("Measure", measure); } } ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDRectlinearMeasureDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDRectlinearMea0000644000000000000000000002175412645757432032172 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.measurement; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This class represents a rectlinear measure dictionary. * * @version $Revision: 1.0 $ * */ public class PDRectlinearMeasureDictionary extends PDMeasureDictionary { /** * The subtype of the rectlinear measure dictionary. */ public static final String SUBTYPE = "RL"; /** * Constructor. */ public PDRectlinearMeasureDictionary() { this.setSubtype(SUBTYPE); } /** * Constructor. * * @param dictionary the corresponding dictionary */ public PDRectlinearMeasureDictionary(COSDictionary dictionary) { super(dictionary); } /** * This will return the scale ration. * * @return the scale ratio. */ public String getScaleRatio() { return this.getDictionary().getString(COSName.R); } /** * This will set the scale ration. * * @param scaleRatio the scale ratio. */ public void setScaleRatio(String scaleRatio) { this.getDictionary().setString(COSName.R, scaleRatio); } /** * This will return the changes along the x-axis. * * @return changes along the x-axis */ public PDNumberFormatDictionary[] getChangeXs() { COSArray x = (COSArray)this.getDictionary().getDictionaryObject("X"); if (x != null) { PDNumberFormatDictionary[] retval = new PDNumberFormatDictionary[x.size()]; for (int i = 0; i < x.size(); i++) { COSDictionary dic = (COSDictionary) x.get(i); retval[i] = new PDNumberFormatDictionary(dic); } return retval; } return null; } /** * This will set the changes along the x-axis. * * @param changeXs changes along the x-axis */ public void setChangeXs(PDNumberFormatDictionary[] changeXs) { COSArray array = new COSArray(); for (int i = 0; i < changeXs.length; i++) { array.add(changeXs[i]); } this.getDictionary().setItem("X", array); } /** * This will return the changes along the y-axis. * * @return changes along the y-axis */ public PDNumberFormatDictionary[] getChangeYs() { COSArray y = (COSArray)this.getDictionary().getDictionaryObject("Y"); if (y != null) { PDNumberFormatDictionary[] retval = new PDNumberFormatDictionary[y.size()]; for (int i = 0; i < y.size(); i++) { COSDictionary dic = (COSDictionary) y.get(i); retval[i] = new PDNumberFormatDictionary(dic); } return retval; } return null; } /** * This will set the changes along the y-axis. * * @param changeYs changes along the y-axis */ public void setChangeYs(PDNumberFormatDictionary[] changeYs) { COSArray array = new COSArray(); for (int i = 0; i < changeYs.length; i++) { array.add(changeYs[i]); } this.getDictionary().setItem("Y", array); } /** * This will return the distances. * * @return distances */ public PDNumberFormatDictionary[] getDistances() { COSArray d = (COSArray)this.getDictionary().getDictionaryObject("D"); if (d != null) { PDNumberFormatDictionary[] retval = new PDNumberFormatDictionary[d.size()]; for (int i = 0; i < d.size(); i++) { COSDictionary dic = (COSDictionary) d.get(i); retval[i] = new PDNumberFormatDictionary(dic); } return retval; } return null; } /** * This will set the distances. * * @param distances distances */ public void setDistances(PDNumberFormatDictionary[] distances) { COSArray array = new COSArray(); for (int i = 0; i < distances.length; i++) { array.add(distances[i]); } this.getDictionary().setItem("D", array); } /** * This will return the areas. * * @return areas */ public PDNumberFormatDictionary[] getAreas() { COSArray a = (COSArray)this.getDictionary().getDictionaryObject(COSName.A); if (a != null) { PDNumberFormatDictionary[] retval = new PDNumberFormatDictionary[a.size()]; for (int i = 0; i < a.size(); i++) { COSDictionary dic = (COSDictionary) a.get(i); retval[i] = new PDNumberFormatDictionary(dic); } return retval; } return null; } /** * This will set the areas. * * @param areas areas */ public void setAreas(PDNumberFormatDictionary[] areas) { COSArray array = new COSArray(); for (int i = 0; i < areas.length; i++) { array.add(areas[i]); } this.getDictionary().setItem(COSName.A, array); } /** * This will return the angles. * * @return angles */ public PDNumberFormatDictionary[] getAngles() { COSArray t = (COSArray)this.getDictionary().getDictionaryObject("T"); if (t != null) { PDNumberFormatDictionary[] retval = new PDNumberFormatDictionary[t.size()]; for (int i = 0; i < t.size(); i++) { COSDictionary dic = (COSDictionary) t.get(i); retval[i] = new PDNumberFormatDictionary(dic); } return retval; } return null; } /** * This will set the angles. * * @param angles angles */ public void setAngles(PDNumberFormatDictionary[] angles) { COSArray array = new COSArray(); for (int i = 0; i < angles.length; i++) { array.add(angles[i]); } this.getDictionary().setItem("T", array); } /** * This will return the sloaps of a line. * * @return the sloaps of a line */ public PDNumberFormatDictionary[] getLineSloaps() { COSArray s = (COSArray)this.getDictionary().getDictionaryObject("S"); if (s != null) { PDNumberFormatDictionary[] retval = new PDNumberFormatDictionary[s.size()]; for (int i = 0; i < s.size(); i++) { COSDictionary dic = (COSDictionary) s.get(i); retval[i] = new PDNumberFormatDictionary(dic); } return retval; } return null; } /** * This will set the sloaps of a line. * * @param lineSloaps the sloaps of a line */ public void setLineSloaps(PDNumberFormatDictionary[] lineSloaps) { COSArray array = new COSArray(); for (int i = 0; i < lineSloaps.length; i++) { array.add(lineSloaps[i]); } this.getDictionary().setItem("S", array); } /** * This will return the origin of the coordinate system. * * @return the origin */ public float[] getCoordSystemOrigin() { COSArray o = (COSArray)this.getDictionary().getDictionaryObject("O"); if (o != null) { return o.toFloatArray(); } return null; } /** * This will set the origin of the coordinate system. * * @param coordSystemOrigin the origin */ public void setCoordSystemOrigin(float[] coordSystemOrigin) { COSArray array = new COSArray(); array.setFloatArray(coordSystemOrigin); this.getDictionary().setItem("O", array); } /** * This will return the CYX factor. * * @return CYX factor */ public float getCYX() { return this.getDictionary().getFloat("CYX"); } /** * This will set the CYX factor. * * @param cyx CYX factor */ public void setCYX(float cyx) { this.getDictionary().setFloat("CYX", cyx); } } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDMeasureDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/measurement/PDMeasureDictio0000644000000000000000000000542412645757432032210 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.measurement; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This class represents a measure dictionary. * * @version $Revision: 1.0 $ * */ public class PDMeasureDictionary implements COSObjectable { /** * The type of the dictionary. */ public static final String TYPE = "Measure"; private COSDictionary measureDictionary; /** * Constructor. */ protected PDMeasureDictionary() { this.measureDictionary = new COSDictionary(); this.getDictionary().setName(COSName.TYPE, TYPE); } /** * Constructor. * * @param dictionary the corresponding dictionary */ public PDMeasureDictionary(COSDictionary dictionary) { this.measureDictionary = dictionary; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return this.measureDictionary; } /** * This will return the corresponding dictionary. * * @return the measure dictionary */ public COSDictionary getDictionary() { return this.measureDictionary; } /** * This will return the type of the measure dictionary. * It must be "Measure" * * @return the type */ public String getType() { return TYPE; } /** * returns the subtype of the measure dictionary. * @return the subtype of the measure data dictionary */ public String getSubtype() { return this.getDictionary().getNameAsString(COSName.SUBTYPE, PDRectlinearMeasureDictionary.SUBTYPE); } /** * This will set the subtype of the measure dictionary. * @param subtype the subtype of the measure dictionary */ protected void setSubtype(String subtype) { this.getDictionary().setName(COSName.SUBTYPE, subtype); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/0000755000000000000000000000000012645757432026227 5ustar rootroot././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDDocumentCatalogAdditionalActions.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDDocumentCatalogAdd0000644000000000000000000001410412645757432032060 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; /** * This class represents a document catalog's dictionary of actions * that occur due to events. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.2 $ */ public class PDDocumentCatalogAdditionalActions implements COSObjectable { private COSDictionary actions; /** * Default constructor. */ public PDDocumentCatalogAdditionalActions() { actions = new COSDictionary(); } /** * Constructor. * * @param a The action dictionary. */ public PDDocumentCatalogAdditionalActions( COSDictionary a ) { actions = a; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return actions; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return actions; } /** * This will get a JavaScript action to be performed * before closing a document. * The name WC stands for "will close". * * @return The WC entry of document catalog's additional actions dictionary. */ public PDAction getWC() { COSDictionary wc = (COSDictionary)actions.getDictionaryObject( "WC" ); PDAction retval = null; if( wc != null ) { retval = PDActionFactory.createAction( wc ); } return retval; } /** * This will set a JavaScript action to be performed * before closing a document. * The name WC stands for "will close". * * @param wc The action to be performed. */ public void setWC( PDAction wc ) { actions.setItem( "WC", wc ); } /** * This will get a JavaScript action to be performed * before saving a document. * The name WS stands for "will save". * * @return The WS entry of document catalog's additional actions dictionary. */ public PDAction getWS() { COSDictionary ws = (COSDictionary)actions.getDictionaryObject( "WS" ); PDAction retval = null; if( ws != null ) { retval = PDActionFactory.createAction( ws ); } return retval; } /** * This will set a JavaScript action to be performed * before saving a document. * The name WS stands for "will save". * * @param ws The action to be performed. */ public void setWS( PDAction ws ) { actions.setItem( "WS", ws ); } /** * This will get a JavaScript action to be performed * after saving a document. * The name DS stands for "did save". * * @return The DS entry of document catalog's additional actions dictionary. */ public PDAction getDS() { COSDictionary ds = (COSDictionary)actions.getDictionaryObject( "DS" ); PDAction retval = null; if( ds != null ) { retval = PDActionFactory.createAction( ds ); } return retval; } /** * This will set a JavaScript action to be performed * after saving a document. * The name DS stands for "did save". * * @param ds The action to be performed. */ public void setDS( PDAction ds ) { actions.setItem( "DS", ds ); } /** * This will get a JavaScript action to be performed * before printing a document. * The name WP stands for "will print". * * @return The WP entry of document catalog's additional actions dictionary. */ public PDAction getWP() { COSDictionary wp = (COSDictionary)actions.getDictionaryObject( "WP" ); PDAction retval = null; if( wp != null ) { retval = PDActionFactory.createAction( wp ); } return retval; } /** * This will set a JavaScript action to be performed * before printing a document. * The name WP stands for "will print". * * @param wp The action to be performed. */ public void setWP( PDAction wp ) { actions.setItem( "WP", wp ); } /** * This will get a JavaScript action to be performed * after printing a document. * The name DP stands for "did print". * * @return The DP entry of document catalog's additional actions dictionary. */ public PDAction getDP() { COSDictionary dp = (COSDictionary)actions.getDictionaryObject( "DP" ); PDAction retval = null; if( dp != null ) { retval = PDActionFactory.createAction( dp ); } return retval; } /** * This will set a JavaScript action to be performed * after printing a document. * The name DP stands for "did print". * * @param dp The action to be performed. */ public void setDP( PDAction dp ) { actions.setItem( "DP", dp ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionFactory.java0000644000000000000000000000577312645757432032077 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionGoTo; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionJavaScript; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionLaunch; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionNamed; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionRemoteGoTo; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionURI; /** * This class will take a dictionary and determine which type of action to create. * * @author Ben Litchfield * @version $Revision: 1.5 $ */ public class PDActionFactory { /** * Utility Class. */ private PDActionFactory() { //utility class } /** * This will create the correct type of action based on the type specified * in the dictionary. * * @param action An action dictionary. * * @return An action of the correct type. */ public static PDAction createAction( COSDictionary action ) { PDAction retval = null; if( action != null ) { String type = action.getNameAsString( "S" ); if( PDActionJavaScript.SUB_TYPE.equals( type ) ) { retval = new PDActionJavaScript( action ); } else if( PDActionGoTo.SUB_TYPE.equals( type ) ) { retval = new PDActionGoTo( action ); } else if( PDActionLaunch.SUB_TYPE.equals( type ) ) { retval = new PDActionLaunch( action ); } else if( PDActionRemoteGoTo.SUB_TYPE.equals( type ) ) { retval = new PDActionRemoteGoTo( action ); } else if( PDActionURI.SUB_TYPE.equals( type ) ) { retval = new PDActionURI( action ); } else if (PDActionNamed.SUB_TYPE.equals(type)) { retval = new PDActionNamed(action); } } return retval; } } ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAnnotationAdditionalActions.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAnnotationAddition0000644000000000000000000002454012645757432032171 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; /** * This class represents an annotation's dictionary of actions * that occur due to events. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.2 $ */ public class PDAnnotationAdditionalActions implements COSObjectable { private COSDictionary actions; /** * Default constructor. */ public PDAnnotationAdditionalActions() { actions = new COSDictionary(); } /** * Constructor. * * @param a The action dictionary. */ public PDAnnotationAdditionalActions( COSDictionary a ) { actions = a; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return actions; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return actions; } /** * This will get an action to be performed when the cursor * enters the annotation's active area. * * @return The E entry of annotation's additional actions dictionary. */ public PDAction getE() { COSDictionary e = (COSDictionary)actions.getDictionaryObject( "E" ); PDAction retval = null; if( e != null ) { retval = PDActionFactory.createAction( e ); } return retval; } /** * This will set an action to be performed when the cursor * enters the annotation's active area. * * @param e The action to be performed. */ public void setE( PDAction e ) { actions.setItem( "E", e ); } /** * This will get an action to be performed when the cursor * exits the annotation's active area. * * @return The X entry of annotation's additional actions dictionary. */ public PDAction getX() { COSDictionary x = (COSDictionary)actions.getDictionaryObject( "X" ); PDAction retval = null; if( x != null ) { retval = PDActionFactory.createAction( x ); } return retval; } /** * This will set an action to be performed when the cursor * exits the annotation's active area. * * @param x The action to be performed. */ public void setX( PDAction x ) { actions.setItem( "X", x ); } /** * This will get an action to be performed when the mouse button * is pressed inside the annotation's active area. * The name D stands for "down". * * @return The d entry of annotation's additional actions dictionary. */ public PDAction getD() { COSDictionary d = (COSDictionary)actions.getDictionaryObject( "D" ); PDAction retval = null; if( d != null ) { retval = PDActionFactory.createAction( d ); } return retval; } /** * This will set an action to be performed when the mouse button * is pressed inside the annotation's active area. * The name D stands for "down". * * @param d The action to be performed. */ public void setD( PDAction d ) { actions.setItem( "D", d ); } /** * This will get an action to be performed when the mouse button * is released inside the annotation's active area. * The name U stands for "up". * * @return The U entry of annotation's additional actions dictionary. */ public PDAction getU() { COSDictionary u = (COSDictionary)actions.getDictionaryObject( "U" ); PDAction retval = null; if( u != null ) { retval = PDActionFactory.createAction( u ); } return retval; } /** * This will set an action to be performed when the mouse button * is released inside the annotation's active area. * The name U stands for "up". * * @param u The action to be performed. */ public void setU( PDAction u ) { actions.setItem( "U", u ); } /** * This will get an action to be performed when the annotation * receives the input focus. * * @return The Fo entry of annotation's additional actions dictionary. */ public PDAction getFo() { COSDictionary fo = (COSDictionary)actions.getDictionaryObject( "Fo" ); PDAction retval = null; if( fo != null ) { retval = PDActionFactory.createAction( fo ); } return retval; } /** * This will set an action to be performed when the annotation * receives the input focus. * * @param fo The action to be performed. */ public void setFo( PDAction fo ) { actions.setItem( "Fo", fo ); } /** * This will get an action to be performed when the annotation * loses the input focus. * The name Bl stands for "blurred". * * @return The Bl entry of annotation's additional actions dictionary. */ public PDAction getBl() { COSDictionary bl = (COSDictionary)actions.getDictionaryObject( "Bl" ); PDAction retval = null; if( bl != null ) { retval = PDActionFactory.createAction( bl ); } return retval; } /** * This will set an action to be performed when the annotation * loses the input focus. * The name Bl stands for "blurred". * * @param bl The action to be performed. */ public void setBl( PDAction bl ) { actions.setItem( "Bl", bl ); } /** * This will get an action to be performed when the page containing * the annotation is opened. The action is executed after the O action * in the page's additional actions dictionary and the OpenAction entry * in the document catalog, if such actions are present. * * @return The PO entry of annotation's additional actions dictionary. */ public PDAction getPO() { COSDictionary po = (COSDictionary)actions.getDictionaryObject( "PO" ); PDAction retval = null; if( po != null ) { retval = PDActionFactory.createAction( po ); } return retval; } /** * This will set an action to be performed when the page containing * the annotation is opened. The action is executed after the O action * in the page's additional actions dictionary and the OpenAction entry * in the document catalog, if such actions are present. * * @param po The action to be performed. */ public void setPO( PDAction po ) { actions.setItem( "PO", po ); } /** * This will get an action to be performed when the page containing * the annotation is closed. The action is executed before the C action * in the page's additional actions dictionary, if present. * * @return The PC entry of annotation's additional actions dictionary. */ public PDAction getPC() { COSDictionary pc = (COSDictionary)actions.getDictionaryObject( "PC" ); PDAction retval = null; if( pc != null ) { retval = PDActionFactory.createAction( pc ); } return retval; } /** * This will set an action to be performed when the page containing * the annotation is closed. The action is executed before the C action * in the page's additional actions dictionary, if present. * * @param pc The action to be performed. */ public void setPC( PDAction pc ) { actions.setItem( "PC", pc ); } /** * This will get an action to be performed when the page containing * the annotation becomes visible in the viewer application's user interface. * * @return The PV entry of annotation's additional actions dictionary. */ public PDAction getPV() { COSDictionary pv = (COSDictionary)actions.getDictionaryObject( "PV" ); PDAction retval = null; if( pv != null ) { retval = PDActionFactory.createAction( pv ); } return retval; } /** * This will set an action to be performed when the page containing * the annotation becomes visible in the viewer application's user interface. * * @param pv The action to be performed. */ public void setPV( PDAction pv ) { actions.setItem( "PV", pv ); } /** * This will get an action to be performed when the page containing the annotation * is no longer visible in the viewer application's user interface. * * @return The PI entry of annotation's additional actions dictionary. */ public PDAction getPI() { COSDictionary pi = (COSDictionary)actions.getDictionaryObject( "PI" ); PDAction retval = null; if( pi != null ) { retval = PDActionFactory.createAction( pi ); } return retval; } /** * This will set an action to be performed when the page containing the annotation * is no longer visible in the viewer application's user interface. * * @param pi The action to be performed. */ public void setPI( PDAction pi ) { actions.setItem( "PI", pi ); } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDFormFieldAdditionalActions.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDFormFieldAdditiona0000644000000000000000000001413012645757432032061 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; /** * This class represents a form field's dictionary of actions * that occur due to events. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.2 $ */ public class PDFormFieldAdditionalActions implements COSObjectable { private COSDictionary actions; /** * Default constructor. */ public PDFormFieldAdditionalActions() { actions = new COSDictionary(); } /** * Constructor. * * @param a The action dictionary. */ public PDFormFieldAdditionalActions( COSDictionary a ) { actions = a; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return actions; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return actions; } /** * This will get a JavaScript action to be performed when the user * types a keystroke into a text field or combo box or modifies the * selection in a scrollable list box. This allows the keystroke to * be checked for validity and rejected or modified. * * @return The K entry of form field's additional actions dictionary. */ public PDAction getK() { COSDictionary k = (COSDictionary)actions.getDictionaryObject( "K" ); PDAction retval = null; if( k != null ) { retval = PDActionFactory.createAction( k ); } return retval; } /** * This will set a JavaScript action to be performed when the user * types a keystroke into a text field or combo box or modifies the * selection in a scrollable list box. This allows the keystroke to * be checked for validity and rejected or modified. * * @param k The action to be performed. */ public void setK( PDAction k ) { actions.setItem( "K", k ); } /** * This will get a JavaScript action to be performed before * the field is formatted to display its current value. This * allows the field's value to be modified before formatting. * * @return The F entry of form field's additional actions dictionary. */ public PDAction getF() { COSDictionary f = (COSDictionary)actions.getDictionaryObject( "F" ); PDAction retval = null; if( f != null ) { retval = PDActionFactory.createAction( f ); } return retval; } /** * This will set a JavaScript action to be performed before * the field is formatted to display its current value. This * allows the field's value to be modified before formatting. * * @param f The action to be performed. */ public void setF( PDAction f ) { actions.setItem( "F", f ); } /** * This will get a JavaScript action to be performed * when the field's value is changed. This allows the * new value to be checked for validity. * The name V stands for "validate". * * @return The V entry of form field's additional actions dictionary. */ public PDAction getV() { COSDictionary v = (COSDictionary)actions.getDictionaryObject( "V" ); PDAction retval = null; if( v != null ) { retval = PDActionFactory.createAction( v ); } return retval; } /** * This will set a JavaScript action to be performed * when the field's value is changed. This allows the * new value to be checked for validity. * The name V stands for "validate". * * @param v The action to be performed. */ public void setV( PDAction v ) { actions.setItem( "V", v ); } /** * This will get a JavaScript action to be performed in order to recalculate * the value of this field when that of another field changes. The order in which * the document's fields are recalculated is defined by the CO entry in the * interactive form dictionary. * The name C stands for "calculate". * * @return The C entry of form field's additional actions dictionary. */ public PDAction getC() { COSDictionary c = (COSDictionary)actions.getDictionaryObject( "C" ); PDAction retval = null; if( c != null ) { retval = PDActionFactory.createAction( c ); } return retval; } /** * This will set a JavaScript action to be performed in order to recalculate * the value of this field when that of another field changes. The order in which * the document's fields are recalculated is defined by the CO entry in the * interactive form dictionary. * The name C stands for "calculate". * * @param c The action to be performed. */ public void setC( PDAction c ) { actions.setItem( "C", c ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/package.html0000644000000000000000000000172612645757432030516 0ustar rootroot This package represents actions that can be performed in a PDF document. ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDPageAdditionalActions.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDPageAdditionalActi0000644000000000000000000000766412645757432032061 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; /** * This class represents a page object's dictionary of actions * that occur due to events. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.2 $ */ public class PDPageAdditionalActions implements COSObjectable { private COSDictionary actions; /** * Default constructor. */ public PDPageAdditionalActions() { actions = new COSDictionary(); } /** * Constructor. * * @param a The action dictionary. */ public PDPageAdditionalActions( COSDictionary a ) { actions = a; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return actions; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return actions; } /** * This will get an action to be performed when the page * is opened. This action is independent of any that may be * defined by the OpenAction entry in the document catalog, * and is executed after such an action. * * @return The O entry of page object's additional actions dictionary. */ public PDAction getO() { COSDictionary o = (COSDictionary)actions.getDictionaryObject( "O" ); PDAction retval = null; if( o != null ) { retval = PDActionFactory.createAction( o ); } return retval; } /** * This will set an action to be performed when the page * is opened. This action is independent of any that may be * defined by the OpenAction entry in the document catalog, * and is executed after such an action. * * @param o The action to be performed. */ public void setO( PDAction o ) { actions.setItem( "O", o ); } /** * This will get an action to be performed when the page * is closed. This action applies to the page being closed, * and is executed before any other page opened. * * @return The C entry of page object's additional actions dictionary. */ public PDAction getC() { COSDictionary c = (COSDictionary)actions.getDictionaryObject( "C" ); PDAction retval = null; if( c != null ) { retval = PDActionFactory.createAction( c ); } return retval; } /** * This will set an action to be performed when the page * is closed. This action applies to the page being closed, * and is executed before any other page opened. * * @param c The action to be performed. */ public void setC( PDAction c ) { actions.setItem( "C", c ); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAdditionalActions.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAdditionalActions.0000644000000000000000000000464012645757432032051 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; /** * This represents a dictionary of actions that occur due to events. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDAdditionalActions implements COSObjectable { private COSDictionary actions; /** * Default constructor. */ public PDAdditionalActions() { actions = new COSDictionary(); } /** * Constructor. * * @param a The action dictionary. */ public PDAdditionalActions( COSDictionary a ) { actions = a; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return actions; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return actions; } /** * Get the F action. * * @return The F action. */ public PDAction getF() { return PDActionFactory.createAction( (COSDictionary)actions.getDictionaryObject("F" ) ); } /** * Set the F action. * * @param action Get the F action. */ public void setF( PDAction action ) { actions.setItem( "F", action ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/0000755000000000000000000000000012645757432027210 5ustar rootroot././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionGoTo.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionGoTo.ja0000644000000000000000000000614312645757432031762 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination; /** * This represents a go-to action that can be executed in a PDF document. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.2 $ */ public class PDActionGoTo extends PDAction { /** * This type of action this object represents. */ public static final String SUB_TYPE = "GoTo"; /** * Default constructor. */ public PDActionGoTo() { super(); setSubType( SUB_TYPE ); } /** * Constructor. * * @param a The action dictionary. */ public PDActionGoTo( COSDictionary a ) { super( a ); } /** * This will get the destination to jump to. * * @return The D entry of the specific go-to action dictionary. * * @throws IOException If there is an error creating the destination. */ public PDDestination getDestination() throws IOException { return PDDestination.create(getCOSDictionary().getDictionaryObject(COSName.D)); } /** * This will set the destination to jump to. * * @param d The destination. * * @IllegalArgumentException if the destination is not a page dictionary object. */ public void setDestination( PDDestination d ) { if (d instanceof PDPageDestination) { PDPageDestination pageDest = (PDPageDestination) d; COSArray destArray = pageDest.getCOSArray(); if (destArray.size() >= 1) { COSBase page = destArray.getObject(0); if (!(page instanceof COSDictionary)) { throw new IllegalArgumentException("Destination of a GoTo action must be " + "a page dictionary object"); } } } getCOSDictionary().setItem(COSName.D, d); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionLaunch.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionLaunch.0000644000000000000000000001655012645757432032014 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import java.io.IOException; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.filespecification.PDFileSpecification; /** * This represents a launch action that can be executed in a PDF document. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.5 $ */ public class PDActionLaunch extends PDAction { /** * This type of action this object represents. */ public static final String SUB_TYPE = "Launch"; /** * Default constructor. */ public PDActionLaunch() { super(); setSubType( SUB_TYPE ); } /** * Constructor. * * @param a The action dictionary. */ public PDActionLaunch( COSDictionary a ) { super( a ); } /** * This will get the application to be launched or the document * to be opened or printed. It is required if none of the entries * Win, Mac or Unix is present. If this entry is absent and the * viewer application does not understand any of the alternative * entries it should do nothing. * * @return The F entry of the specific launch action dictionary. * * @throws IOException If there is an error creating the file spec. */ public PDFileSpecification getFile() throws IOException { return PDFileSpecification.createFS( getCOSDictionary().getDictionaryObject( "F" ) ); } /** * This will set the application to be launched or the document * to be opened or printed. It is required if none of the entries * Win, Mac or Unix is present. If this entry is absent and the * viewer application does not understand any of the alternative * entries it should do nothing. * * @param fs The file specification. */ public void setFile( PDFileSpecification fs ) { getCOSDictionary().setItem( "F", fs ); } /** * This will get a dictionary containing Windows-specific launch parameters. * * @return The Win entry of of the specific launch action dictionary. */ public PDWindowsLaunchParams getWinLaunchParams() { COSDictionary win = (COSDictionary)action.getDictionaryObject( "Win" ); PDWindowsLaunchParams retval = null; if( win != null ) { retval = new PDWindowsLaunchParams( win ); } return retval; } /** * This will set a dictionary containing Windows-specific launch parameters. * * @param win The action to be performed. */ public void setWinLaunchParams( PDWindowsLaunchParams win ) { action.setItem( "Win", win ); } /** * This will get the file name to be launched or the document to be opened * or printed, in standard Windows pathname format. If the name string includes * a backslash character (\), the backslash must itself be preceded by a backslash. * This value must be a single string; it is not a file specification. * * @return The F entry of the specific Windows launch parameter dictionary. */ public String getF() { return action.getString( "F" ); } /** * This will set the file name to be launched or the document to be opened * or printed, in standard Windows pathname format. If the name string includes * a backslash character (\), the backslash must itself be preceded by a backslash. * This value must be a single string; it is not a file specification. * * @param f The file name to be launched. */ public void setF( String f ) { action.setString( "F", f ); } /** * This will get the string specifying the default directory in standard DOS syntax. * * @return The D entry of the specific Windows launch parameter dictionary. */ public String getD() { return action.getString( "D" ); } /** * This will set the string specifying the default directory in standard DOS syntax. * * @param d The default directory. */ public void setD( String d ) { action.setString( "D", d ); } /** * This will get the string specifying the operation to perform: * open to open a document * print to print a document * If the F entry designates an application instead of a document, this entry * is ignored and the application is launched. Default value: open. * * @return The O entry of the specific Windows launch parameter dictionary. */ public String getO() { return action.getString( "O" ); } /** * This will set the string specifying the operation to perform: * open to open a document * print to print a document * If the F entry designates an application instead of a document, this entry * is ignored and the application is launched. Default value: open. * * @param o The operation to perform. */ public void setO( String o ) { action.setString( "O", o ); } /** * This will get a parameter string to be passed to the application designated by the F entry. * This entry should be omitted if F designates a document. * * @return The P entry of the specific Windows launch parameter dictionary. */ public String getP() { return action.getString( "P" ); } /** * This will set a parameter string to be passed to the application designated by the F entry. * This entry should be omitted if F designates a document. * * @param p The parameter string. */ public void setP( String p ) { action.setString( "P", p ); } /** * This will specify whether to open the destination document in a new window. * If this flag is false, the destination document will replace the current * document in the same window. If this entry is absent, the viewer application * should behave in accordance with the current user preference. This entry is * ignored if the file designated by the F entry is not a PDF document. * * @return A flag specifying whether to open the destination document in a new window. */ public boolean shouldOpenInNewWindow() { return action.getBoolean( "NewWindow", true ); } /** * This will specify the destination document to open in a new window. * * @param value The flag value. */ public void setOpenInNewWindow( boolean value ) { action.setBoolean( "NewWindow", value ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDAction.java0000644000000000000000000001204212645757432031513 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.PDDestinationOrAction; import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory; /** * This represents an action that can be executed in a PDF document. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.3 $ */ public abstract class PDAction implements PDDestinationOrAction { /** * The type of PDF object. */ public static final String TYPE = "Action"; /** * The action dictionary. */ protected COSDictionary action; /** * Default constructor. */ public PDAction() { action = new COSDictionary(); setType( TYPE ); } /** * Constructor. * * @param a The action dictionary. */ public PDAction( COSDictionary a ) { action = a; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return action; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return action; } /** * This will get the type of PDF object that the actions dictionary describes. * If present must be Action for an action dictionary. * * @return The Type of PDF object. */ public String getType() { return action.getNameAsString( "Type" ); } /** * This will set the type of PDF object that the actions dictionary describes. * If present must be Action for an action dictionary. * * @param type The new Type for the PDF object. */ public void setType( String type ) { action.setName( "Type", type ); } /** * This will get the type of action that the actions dictionary describes. * If present, must be Action for an action dictionary. * * @return The S entry of actions dictionary. */ public String getSubType() { return action.getNameAsString( "S" ); } /** * This will set the type of action that the actions dictionary describes. * If present, must be Action for an action dictionary. * * @param s The new type of action. */ public void setSubType( String s ) { action.setName( "S", s ); } /** * This will get the next action, or sequence of actions, to be performed after this one. * The value is either a single action dictionary or an array of action dictionaries * to be performed in order. * * @return The Next action or sequence of actions. */ public List getNext() { List retval = null; COSBase next = action.getDictionaryObject( "Next" ); if( next instanceof COSDictionary ) { PDAction pdAction = PDActionFactory.createAction( (COSDictionary) next ); retval = new COSArrayList(pdAction, next, action, COSName.getPDFName( "Next" )); } else if( next instanceof COSArray ) { COSArray array = (COSArray)next; List actions = new ArrayList(); for( int i=0; i This package contains all of the available PDF action types. ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionJavaScript.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionJavaScr0000644000000000000000000000427312645757432032054 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.PDTextStream; /** * This represents a JavaScript action. * * @author Michael Schwarzenberger (mi2kee@gmail.com) * @version $Revision: 1.1 $ */ public class PDActionJavaScript extends PDAction { /** * This type of action this object represents. */ public static final String SUB_TYPE = "JavaScript"; /** * Constructor #1. */ public PDActionJavaScript() { super(); setSubType( SUB_TYPE ); } /** * Constructor. * * @param js Some javascript code. */ public PDActionJavaScript( String js ) { this(); setAction( js ); } /** * Constructor #2. * * @param a The action dictionary. */ public PDActionJavaScript(COSDictionary a) { super(a); } /** * @param sAction The JavaScript. */ public void setAction(PDTextStream sAction) { action.setItem("JS", sAction); } /** * @param sAction The JavaScript. */ public void setAction(String sAction) { action.setString("JS", sAction); } /** * @return The Javascript Code. */ public PDTextStream getAction() { return PDTextStream.createTextStream( action.getDictionaryObject("JS") ); } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionRemoteGoTo.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionRemoteG0000644000000000000000000001215712645757432032065 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import java.io.IOException; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.filespecification.PDFileSpecification; /** * This represents a remote go-to action that can be executed in a PDF document. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.4 $ */ public class PDActionRemoteGoTo extends PDAction { /** * This type of action this object represents. */ public static final String SUB_TYPE = "GoToR"; /** * Default constructor. */ public PDActionRemoteGoTo() { action = new COSDictionary(); setSubType( SUB_TYPE ); } /** * Constructor. * * @param a The action dictionary. */ public PDActionRemoteGoTo( COSDictionary a ) { super( a ); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return action; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return action; } /** * This will get the type of action that the actions dictionary describes. * It must be GoToR for a remote go-to action. * * @return The S entry of the specific remote go-to action dictionary. */ public String getS() { return action.getNameAsString( "S" ); } /** * This will set the type of action that the actions dictionary describes. * It must be GoToR for a remote go-to action. * * @param s The remote go-to action. */ public void setS( String s ) { action.setName( "S", s ); } /** * This will get the file in which the destination is located. * * @return The F entry of the specific remote go-to action dictionary. * * @throws IOException If there is an error creating the file spec. */ public PDFileSpecification getFile() throws IOException { return PDFileSpecification.createFS( action.getDictionaryObject( "F" ) ); } /** * This will set the file in which the destination is located. * * @param fs The file specification. */ public void setFile( PDFileSpecification fs ) { action.setItem( "F", fs ); } /** * This will get the destination to jump to. * If the value is an array defining an explicit destination, * its first element must be a page number within the remote * document rather than an indirect reference to a page object * in the current document. The first page is numbered 0. * * @return The D entry of the specific remote go-to action dictionary. */ // Array or String. public COSBase getD() { return action.getDictionaryObject( "D" ); } /** * This will set the destination to jump to. * If the value is an array defining an explicit destination, * its first element must be a page number within the remote * document rather than an indirect reference to a page object * in the current document. The first page is numbered 0. * * @param d The destination. */ // In case the value is an array. public void setD( COSBase d ) { action.setItem( "D", d ); } /** * This will specify whether to open the destination document in a new window. * If this flag is false, the destination document will replace the current * document in the same window. If this entry is absent, the viewer application * should behave in accordance with the current user preference. * * @return A flag specifying whether to open the destination document in a new window. */ public boolean shouldOpenInNewWindow() { return action.getBoolean( "NewWindow", true ); } /** * This will specify the destination document to open in a new window. * * @param value The flag value. */ public void setOpenInNewWindow( boolean value ) { action.setBoolean( "NewWindow", value ); } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionURI.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionURI.jav0000644000000000000000000001250512645757432031736 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; /** * This represents a URI action that can be executed in a PDF document. * * @author Ben Litchfield * @author Panagiotis Toumasis (ptoumasis@mail.gr) * @version $Revision: 1.3 $ */ public class PDActionURI extends PDAction { /** * This type of action this object represents. */ public static final String SUB_TYPE = "URI"; /** * Default constructor. */ public PDActionURI() { action = new COSDictionary(); setSubType( SUB_TYPE ); } /** * Constructor. * * @param a The action dictionary. */ public PDActionURI( COSDictionary a ) { super( a ); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return action; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return action; } /** * This will get the type of action that the actions dictionary describes. * It must be URI for a URI action. * * @return The S entry of the specific URI action dictionary. */ public String getS() { return action.getNameAsString( "S" ); } /** * This will set the type of action that the actions dictionary describes. * It must be URI for a URI action. * * @param s The URI action. */ public void setS( String s ) { action.setName( "S", s ); } /** * This will get the uniform resource identifier to resolve, encoded in 7-bit ASCII. * * @return The URI entry of the specific URI action dictionary. */ public String getURI() { return action.getString( "URI" ); } /** * This will set the uniform resource identifier to resolve, encoded in 7-bit ASCII. * * @param uri The uniform resource identifier. */ public void setURI( String uri ) { action.setString( "URI", uri ); } /** * This will specify whether to track the mouse position when the URI is resolved. * Default value: false. * This entry applies only to actions triggered by the user's clicking an annotation; * it is ignored for actions associated with outline items or with a document's OpenAction entry. * * @return A flag specifying whether to track the mouse position when the URI is resolved. */ public boolean shouldTrackMousePosition() { return this.action.getBoolean("IsMap", false); } /** * This will specify whether to track the mouse position when the URI is resolved. * * @param value The flag value. */ public void setTrackMousePosition( boolean value ) { this.action.setBoolean("IsMap", value); } // TODO this must go into PDURIDictionary /** * This will get the base URI to be used in resolving relative URI references. * URI actions within the document may specify URIs in partial form, to be interpreted * relative to this base address. If no base URI is specified, such partial URIs * will be interpreted relative to the location of the document itself. * The use of this entry is parallel to that of the body element <BASE>, as described * in the HTML 4.01 Specification. * * @return The URI entry of the specific URI dictionary. * @deprecated use {@link PDURIDictionary#getBase()} instead */ public String getBase() { return action.getString( "Base" ); } // TODO this must go into PDURIDictionary /** * This will set the base URI to be used in resolving relative URI references. * URI actions within the document may specify URIs in partial form, to be interpreted * relative to this base address. If no base URI is specified, such partial URIs * will be interpreted relative to the location of the document itself. * The use of this entry is parallel to that of the body element <BASE>, as described * in the HTML 4.01 Specification. * * @param base The the base URI to be used. * @deprecated use {@link PDURIDictionary#setBase(String)} instead */ public void setBase( String base ) { action.setString( "Base", base ); } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDWindowsLaunchParams.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDWindowsLaunch0000644000000000000000000001001512645757432032141 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * Launch paramaters for the windows OS. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDWindowsLaunchParams implements COSObjectable { /** * The open operation for the launch. */ public static final String OPERATION_OPEN = "open"; /** * The print operation for the lanuch. */ public static final String OPERATION_PRINT = "print"; /** * The params dictionary. */ protected COSDictionary params; /** * Default constructor. */ public PDWindowsLaunchParams() { params = new COSDictionary(); } /** * Constructor. * * @param p The params dictionary. */ public PDWindowsLaunchParams( COSDictionary p ) { params = p; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return params; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getCOSDictionary() { return params; } /** * The file to launch. * * @return The executable/document to launch. */ public String getFilename() { return params.getString( "F" ); } /** * Set the file to launch. * * @param file The executable/document to launch. */ public void setFilename( String file ) { params.setString( "F", file ); } /** * The dir to launch from. * * @return The dir of the executable/document to launch. */ public String getDirectory() { return params.getString( "D" ); } /** * Set the dir to launch from. * * @param dir The dir of the executable/document to launch. */ public void setDirectory( String dir ) { params.setString( "D", dir ); } /** * Get the operation to perform on the file. This method will not return null, * OPERATION_OPEN is the default. * * @return The operation to perform for the file. * @see PDWindowsLaunchParams#OPERATION_OPEN * @see PDWindowsLaunchParams#OPERATION_PRINT */ public String getOperation() { return params.getString( "O", OPERATION_OPEN ); } /** * Set the operation to perform.. * * @param op The operation to perform on the file. */ public void setOperation( String op ) { params.setString( "D", op ); } /** * A parameter to pass the executable. * * @return The parameter to pass the executable. */ public String getExecuteParam() { return params.getString( "P" ); } /** * Set the parameter to pass the executable. * * @param param The parameter for the executable. */ public void setExecuteParam( String param ) { params.setString( "P", param ); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionNamed.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDActionNamed.j0000644000000000000000000000452412645757432031776 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; /** * This represents a named action in a PDF document. */ public class PDActionNamed extends PDAction { /** * This type of action this object represents. */ public static final String SUB_TYPE = "Named"; /** * Default constructor. */ public PDActionNamed() { action = new COSDictionary(); setSubType(SUB_TYPE); } /** * Constructor. * * @param a The action dictionary. */ public PDActionNamed(COSDictionary a) { super(a); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ @Override public COSBase getCOSObject() { return action; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ @Override public COSDictionary getCOSDictionary() { return action; } /** * This will get the name of the action to be performed. * * @return The name of the action to be performed. */ public String getN() { return action.getNameAsString("N"); } /** * This will set the name of the action to be performed. * * @param name The name of the action to be performed. */ public void setN(String name) { action.setName("N", name); } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDURIDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/type/PDURIDictionary0000644000000000000000000000607412645757432032053 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.action.type; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This is the implementation of an URI dictionary. * * @version $Revision: 1.0 $ * */ public class PDURIDictionary implements COSObjectable { private COSDictionary uriDictionary; /** * Constructor. * */ public PDURIDictionary() { this.uriDictionary = new COSDictionary(); } /** * Constructor. * * @param dictionary the corresponding dictionary */ public PDURIDictionary(COSDictionary dictionary) { this.uriDictionary = dictionary; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return this.uriDictionary; } /** * Returns the corresponding dictionary. * @return the dictionary */ public COSDictionary getDictionary() { return this.uriDictionary; } /** * This will get the base URI to be used in resolving relative URI references. * URI actions within the document may specify URIs in partial form, to be interpreted * relative to this base address. If no base URI is specified, such partial URIs * will be interpreted relative to the location of the document itself. * The use of this entry is parallel to that of the body element <BASE>, as described * in the HTML 4.01 Specification. * * @return The URI entry of the specific URI dictionary. */ public String getBase() { return this.getDictionary().getString("Base"); } /** * This will set the base URI to be used in resolving relative URI references. * URI actions within the document may specify URIs in partial form, to be interpreted * relative to this base address. If no base URI is specified, such partial URIs * will be interpreted relative to the location of the document itself. * The use of this entry is parallel to that of the body element <BASE>, as described * in the HTML 4.01 Specification. * * @param base The the base URI to be used. */ public void setBase(String base) { this.getDictionary().setString("Base", base); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/0000755000000000000000000000000012645757432027746 5ustar rootroot././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDThread.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDThread.jav0000644000000000000000000000706612645757432032114 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.pagenavigation; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This a single thread in a PDF document. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDThread implements COSObjectable { private COSDictionary thread; /** * Constructor that is used for a preexisting dictionary. * * @param t The underlying dictionary. */ public PDThread( COSDictionary t ) { thread = t; } /** * Default constructor. * */ public PDThread() { thread = new COSDictionary(); thread.setName( "Type", "Thread" ); } /** * This will get the underlying dictionary that this object wraps. * * @return The underlying info dictionary. */ public COSDictionary getDictionary() { return thread; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return thread; } /** * Get info about the thread, or null if there is nothing. * * @return The thread information. */ public PDDocumentInformation getThreadInfo() { PDDocumentInformation retval = null; COSDictionary info = (COSDictionary)thread.getDictionaryObject( "I" ); if( info != null ) { retval = new PDDocumentInformation( info ); } return retval; } /** * Set the thread info, can be null. * * @param info The info dictionary about this thread. */ public void setThreadInfo( PDDocumentInformation info ) { thread.setItem( "I", info ); } /** * Get the first bead in the thread, or null if it has not been set yet. This * is a required field for this object. * * @return The first bead in the thread. */ public PDThreadBead getFirstBead() { PDThreadBead retval = null; COSDictionary bead = (COSDictionary)thread.getDictionaryObject( "F" ); if( bead != null ) { retval = new PDThreadBead( bead ); } return retval; } /** * This will set the first bead in the thread. When this is set it will * also set the thread property of the bead object. * * @param bead The first bead in the thread. */ public void setFirstBead( PDThreadBead bead ) { if( bead != null ) { bead.setThread( this ); } thread.setItem( "F", bead ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/package.html0000644000000000000000000000172512645757432032234 0ustar rootroot A package to allow provide access to PDF page navigation functionality. ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDThreadBead.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDThreadBead0000644000000000000000000001411112645757432032076 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.pagenavigation; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * This a single bead in a thread in a PDF document. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDThreadBead implements COSObjectable { private COSDictionary bead; /** * Constructor that is used for a preexisting dictionary. * * @param b The underlying dictionary. */ public PDThreadBead( COSDictionary b ) { bead = b; } /** * Default constructor. * */ public PDThreadBead() { bead = new COSDictionary(); bead.setName( "Type", "Bead" ); setNextBead( this ); setPreviousBead( this ); } /** * This will get the underlying dictionary that this object wraps. * * @return The underlying info dictionary. */ public COSDictionary getDictionary() { return bead; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return bead; } /** * This will get the thread that this bead is part of. This is only required * for the first bead in a thread, so other beads 'may' return null. * * @return The thread that this bead is part of. */ public PDThread getThread() { PDThread retval = null; COSDictionary dic = (COSDictionary)bead.getDictionaryObject( "T" ); if( dic != null ) { retval = new PDThread( dic ); } return retval; } /** * Set the thread that this bead is part of. This is only required for the * first bead in a thread. Note: This property is set for you by the PDThread.setFirstBead() method. * * @param thread The thread that this bead is part of. */ public void setThread( PDThread thread ) { bead.setItem( "T", thread ); } /** * This will get the next bead. If this bead is the last bead in the list then this * will return the first bead. * * @return The next bead in the list or the first bead if this is the last bead. */ public PDThreadBead getNextBead() { return new PDThreadBead( (COSDictionary) bead.getDictionaryObject( "N" ) ); } /** * Set the next bead in the thread. * * @param next The next bead. */ protected void setNextBead( PDThreadBead next ) { bead.setItem( "N", next ); } /** * This will get the previous bead. If this bead is the first bead in the list then this * will return the last bead. * * @return The previous bead in the list or the last bead if this is the first bead. */ public PDThreadBead getPreviousBead() { return new PDThreadBead( (COSDictionary) bead.getDictionaryObject( "V" ) ); } /** * Set the previous bead in the thread. * * @param previous The previous bead. */ protected void setPreviousBead( PDThreadBead previous ) { bead.setItem( "V", previous ); } /** * Append a bead after this bead. This will correctly set the next/previous beads in the * linked list. * * @param append The bead to insert. */ public void appendBead( PDThreadBead append ) { PDThreadBead nextBead = getNextBead(); nextBead.setPreviousBead( append ); append.setNextBead( nextBead ); setNextBead( append ); append.setPreviousBead( this ); } /** * Get the page that this bead is part of. * * @return The page that this bead is part of. */ public PDPage getPage() { PDPage page = null; COSDictionary dic = (COSDictionary)bead.getDictionaryObject( "P" ); if( dic != null ) { page = new PDPage( dic ); } return page; } /** * Set the page that this bead is part of. This is a required property and must be * set when creating a new bead. The PDPage object also has a list of beads in the natural * reading order. It is recommended that you add this object to that list as well. * * @param page The page that this bead is on. */ public void setPage( PDPage page ) { bead.setItem( "P", page ); } /** * The rectangle on the page that this bead is part of. * * @return The part of the page that this bead covers. */ public PDRectangle getRectangle() { PDRectangle rect = null; COSArray array = (COSArray)bead.getDictionaryObject( COSName.R ); if( array != null ) { rect = new PDRectangle( array ); } return rect; } /** * Set the rectangle on the page that this bead covers. * * @param rect The portion of the page that this bead covers. */ public void setRectangle( PDRectangle rect ) { bead.setItem( COSName.R, rect ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/0000755000000000000000000000000012645757432025715 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDUnknownField.java0000644000000000000000000000331012645757432031404 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import java.io.IOException; import org.apache.pdfbox.cos.COSDictionary; /** * This class represents a form field with an unknown type. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDUnknownField extends PDField { /** * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#PDField(PDAcroForm, COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The field's dictionary. */ public PDUnknownField( PDAcroForm theAcroForm, COSDictionary field) { super( theAcroForm, field); } /** * {@inheritDoc} */ public void setValue(String value) throws IOException { //do nothing } /** * {@inheritDoc} */ public String getValue() throws IOException { return null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignatureField.java0000644000000000000000000001424512645757432031717 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSeedValue; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; /** * A class for handling the PDF field as a signature. * * @author Ben Litchfield * @author Thomas Chojecki * @version $Revision: 1.5 $ */ public class PDSignatureField extends PDField { /** * @see PDField#PDField(PDAcroForm,COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The dictionary for the signature. * @throws IOException If there is an error while resolving partital name for the signature field */ public PDSignatureField( PDAcroForm theAcroForm, COSDictionary field) throws IOException { super(theAcroForm,field); // dirty hack to avoid npe caused through getWidget() method getDictionary().setItem( COSName.TYPE, COSName.ANNOT ); getDictionary().setName( COSName.SUBTYPE, PDAnnotationWidget.SUB_TYPE); } /** * @see PDField#PDField(PDAcroForm) * * @param theAcroForm The acroForm for this field. * @throws IOException If there is an error while resolving partial name for the signature field * or getting the widget object. */ public PDSignatureField( PDAcroForm theAcroForm) throws IOException { super( theAcroForm ); getDictionary().setItem(COSName.FT, COSName.SIG); getWidget().setLocked(true); getWidget().setPrinted(true); setPartialName(generatePartialName()); getDictionary().setItem( COSName.TYPE, COSName.ANNOT ); getDictionary().setName( COSName.SUBTYPE, PDAnnotationWidget.SUB_TYPE); } /** * Generate a unique name for the signature. * @return the unique name for the signature * @throws IOException If there is an error while getting the list of fields. */ private String generatePartialName() throws IOException { PDAcroForm acroForm = getAcroForm(); List fields = acroForm.getFields(); String fieldName = "Signature"; int i = 1; Set sigNames = new HashSet(); for ( Object object : fields ) { if(object instanceof PDSignatureField) { sigNames.add(((PDSignatureField)object).getPartialName()); } } while(sigNames.contains(fieldName+i)) { ++i; } return fieldName+i; } /** * @see PDField#setValue(java.lang.String) * * @param value The new value for the field. * * @throws IOException If there is an error creating the appearance stream. * @deprecated use setSignature(PDSignature) instead */ @Override @Deprecated public void setValue(String value) throws IOException { throw new RuntimeException( "Can't set signature as String, use setSignature(PDSignature) instead" ); } /** * @see PDField#setValue(java.lang.String) * * @return The string value of this field. * * @throws IOException If there is an error creating the appearance stream. * @deprecated use getSignature() instead */ @Override @Deprecated public String getValue() throws IOException { throw new RuntimeException( "Can't get signature as String, use getSignature() instead." ); } /** * Return a string rep of this object. * * @return A string rep of this object. */ @Override public String toString() { return "PDSignature"; } /** * Add a signature dictionary to the signature field. * * @param value is the PDSignature */ public void setSignature(PDSignature value) { getDictionary().setItem(COSName.V, value); } /** * Get the signature dictionary. * * @return the signature dictionary * */ public PDSignature getSignature() { COSBase dictionary = getDictionary().getDictionaryObject(COSName.V); if (dictionary == null) { return null; } return new PDSignature((COSDictionary)dictionary); } /** *

    (Optional; PDF 1.5) A seed value dictionary containing information * that constrains the properties of a signature that is applied to the * field.

    * * @return the seed value dictionary as PDSeedValue */ public PDSeedValue getSeedValue() { COSDictionary dict = (COSDictionary)getDictionary().getDictionaryObject(COSName.SV); PDSeedValue sv = null; if (dict != null) { sv = new PDSeedValue(dict); } return sv; } /** *

    (Optional; PDF 1.) A seed value dictionary containing information * that constrains the properties of a signature that is applied to the * field.

    * * @param sv is the seed value dictionary as PDSeedValue */ public void setSeedValue(PDSeedValue sv) { if (sv != null) { getDictionary().setItem(COSName.SV, sv.getCOSObject()); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDVariableText.java0000644000000000000000000002024112645757432031375 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.util.BitFlagHelper; import java.io.IOException; /** * A class for handling PDF fields that display text. * * @author Ben Litchfield * @version $Revision: 1.7 $ */ public abstract class PDVariableText extends PDField { /** * A Ff flag. */ public static final int FLAG_MULTILINE = 1 << 12; /** * A Ff flag. */ public static final int FLAG_PASSWORD = 1 << 13; /** * A Ff flag. */ public static final int FLAG_FILE_SELECT = 1 << 20; /** * A Ff flag. */ public static final int FLAG_DO_NOT_SPELL_CHECK = 1 << 22; /** * A Ff flag. */ public static final int FLAG_DO_NOT_SCROLL = 1 << 23; /** * A Ff flag. */ public static final int FLAG_COMB = 1 << 24; /** * A Ff flag. */ public static final int FLAG_RICH_TEXT = 1 << 25; /** * DA Default appearance. */ private COSString da; private PDAppearance appearance; /** * A Q value. */ public static final int QUADDING_LEFT = 0; /** * A Q value. */ public static final int QUADDING_CENTERED = 1; /** * A Q value. */ public static final int QUADDING_RIGHT = 2; /** * @see PDField#PDField(PDAcroForm,COSDictionary) * * @param theAcroForm The acroform. */ public PDVariableText( PDAcroForm theAcroForm ) { super( theAcroForm ); } /** * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#PDField(PDAcroForm,COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The field's dictionary. */ public PDVariableText( PDAcroForm theAcroForm, COSDictionary field) { super( theAcroForm, field); da = (COSString) field.getDictionaryObject(COSName.DA); } /** * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#setValue(java.lang.String) * * @param value The new value for this text field. * * @throws IOException If there is an error calculating the appearance stream. */ public void setValue(String value) throws IOException { COSString fieldValue = new COSString(value); getDictionary().setItem( COSName.V, fieldValue ); //hmm, not sure what the case where the DV gets set to the field //value, for now leave blank until we can come up with a case //where it needs to be in there //getDictionary().setItem( COSName.getPDFName( "DV" ), fieldValue ); if(appearance == null) { this.appearance = new PDAppearance( getAcroForm(), this ); } appearance.setAppearanceValue(value); } /** * getValue gets the fields value to as a string. * * @return The string value of this field. * * @throws IOException If there is an error getting the value. */ public String getValue() throws IOException { return getDictionary().getString( COSName.V ); } /** * @return true if the field is multiline */ public boolean isMultiline() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_MULTILINE ); } /** * Set the multiline bit. * * @param multiline The value for the multiline. */ public void setMultiline( boolean multiline ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_MULTILINE, multiline ); } /** * @return true if the field is a password field. */ public boolean isPassword() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_PASSWORD ); } /** * Set the password bit. * * @param password The value for the password. */ public void setPassword( boolean password ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_PASSWORD, password ); } /** * @return true if the field is a file select field. */ public boolean isFileSelect() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_FILE_SELECT ); } /** * Set the file select bit. * * @param fileSelect The value for the fileSelect. */ public void setFileSelect( boolean fileSelect ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_FILE_SELECT, fileSelect ); } /** * @return true if the field is not suppose to spell check. */ public boolean doNotSpellCheck() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_DO_NOT_SPELL_CHECK ); } /** * Set the doNotSpellCheck bit. * * @param doNotSpellCheck The value for the doNotSpellCheck. */ public void setDoNotSpellCheck( boolean doNotSpellCheck ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_DO_NOT_SPELL_CHECK, doNotSpellCheck ); } /** * @return true if the field is not suppose to scroll. */ public boolean doNotScroll() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_DO_NOT_SCROLL ); } /** * Set the doNotScroll bit. * * @param doNotScroll The value for the doNotScroll. */ public void setDoNotScroll( boolean doNotScroll ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_DO_NOT_SCROLL, doNotScroll ); } /** * @return true if the field is supposed to comb the text display. */ public boolean shouldComb() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_COMB ); } /** * Set the comb bit. * * @param comb The value for the comb. */ public void setComb( boolean comb ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_COMB, comb ); } /** * @return true if the field is a rich text field. */ public boolean isRichText() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_RICH_TEXT ); } /** * Set the richText bit. * * @param richText The value for the richText. */ public void setRichText( boolean richText ) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_RICH_TEXT, richText ); } /** * @return the DA element of the dictionary object */ protected COSString getDefaultAppearance() { return da; } /** * This will get the 'quadding' or justification of the text to be displayed. * 0 - Left(default)
    * 1 - Centered
    * 2 - Right
    * Please see the QUADDING_CONSTANTS. * * @return The justification of the text strings. */ public int getQ() { int retval = 0; COSNumber number = (COSNumber)getDictionary().getDictionaryObject( COSName.Q ); if( number != null ) { retval = number.intValue(); } return retval; } /** * This will set the quadding/justification of the text. See QUADDING constants. * * @param q The new text justification. */ public void setQ( int q ) { getDictionary().setInt( COSName.Q, q ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoiceField.java0000644000000000000000000001506412645757432031150 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; /** * A class for handling the PDF field as a choicefield. * * @author sug * @version $Revision: 1.7 $ */ public class PDChoiceField extends PDVariableText { /** * A Ff flag. */ public static final int FLAG_COMBO = 1 << 17; /** * A Ff flag. */ public static final int FLAG_EDIT = 1 << 18; private PDAppearance appearance; /** * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#PDField(PDAcroForm,COSDictionary) * * @param theAcroForm * The acroForm for this field. * @param field * The field for this choice field. */ public PDChoiceField(PDAcroForm theAcroForm, COSDictionary field) { super(theAcroForm, field); } private void setListboxValue(String value) throws IOException { COSString fieldValue = new COSString(value); getDictionary().setItem(COSName.V, fieldValue); // hmm, not sure what the case where the DV gets set to the field // value, for now leave blank until we can come up with a case // where it needs to be in there // getDictionary().setItem( COSName.getPDFName( "DV" ), fieldValue ); if (appearance == null) { this.appearance = new PDAppearance(getAcroForm(), this); } appearance.setAppearanceValue(value); } /** * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#setValue(java.lang.String) * * @param optionValue * The new value for this text field. * * @throws IOException * If there is an error calculating the appearance stream or the value in not one of the existing * options. */ public void setValue(String optionValue) throws IOException { int indexSelected = -1; COSArray options = (COSArray) getDictionary().getDictionaryObject(COSName.OPT); int fieldFlags = getFieldFlags(); boolean isEditable = (FLAG_COMBO & fieldFlags) != 0 && (FLAG_EDIT & fieldFlags) != 0; if (options.size() == 0 && !isEditable) { throw new IOException("Error: You cannot set a value for a choice field if there are no options."); } else { // YXJ: Changed the order of the loops. Acrobat produces PDF's // where sometimes there is 1 string and the rest arrays. // This code works either way. for (int i = 0; i < options.size() && indexSelected == -1; i++) { COSBase option = options.getObject(i); if (option instanceof COSArray) { COSArray keyValuePair = (COSArray) option; COSString key = (COSString) keyValuePair.getObject(0); COSString value = (COSString) keyValuePair.getObject(1); if (optionValue.equals(key.getString()) || optionValue.equals(value.getString())) { // have the parent draw the appearance stream with the value if ((FLAG_COMBO & fieldFlags) != 0) { super.setValue(value.getString()); } else { COSArray indexEntries = new COSArray(); indexEntries.add(COSInteger.get((long) i)); getDictionary().setItem(COSName.I, indexEntries); setListboxValue(value.getString()); } // but then use the key as the V entry getDictionary().setItem(COSName.V, key); indexSelected = i; } } else { COSString value = (COSString) option; if (optionValue.equals(value.getString())) { super.setValue(optionValue); indexSelected = i; } } } } if (indexSelected == -1 && isEditable) { super.setValue(optionValue); } else if (indexSelected == -1) { throw new IOException("Error: '" + optionValue + "' was not an available option."); } else { COSArray indexArray = (COSArray) getDictionary().getDictionaryObject(COSName.I); if (indexArray != null) { indexArray.clear(); indexArray.add(COSInteger.get(indexSelected)); } } } /** * This will get the indices of the selected options "I". * * @return COSArray containing the indices of all selected options. */ public COSArray getSelectedOptions() { return (COSArray) getDictionary().getDictionaryObject(COSName.I); } /** * This will get the top index "TI" value. * * The value returned will be the first item to display in the listbox. * * @return the top index, default value 0. */ public int getTopIndex() { return getDictionary().getInt(COSName.getPDFName("TI"), 0); } /** * This will get the option values "Opt". * * @return COSArray containing all options. */ public COSArray getOptions() { return (COSArray) getDictionary().getDictionaryObject(COSName.OPT); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDPushButton.java0000644000000000000000000000432012645757432031116 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import java.io.IOException; /** * A class for handling the PDF field as a PDPushButton. * * @author sug * @version $Revision: 1.3 $ */ public class PDPushButton extends PDField { /** * @see PDField#PDField(PDAcroForm, COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The field for this push button. */ public PDPushButton( PDAcroForm theAcroForm, COSDictionary field) { super(theAcroForm, field); } /** * @see PDField#setValue(java.lang.String) * * @param value The new value for the field. * * @throws IOException If there is an error creating the appearance stream. */ public void setValue(String value) throws IOException { COSString fieldValue = new COSString(value); getDictionary().setItem( COSName.getPDFName( "V" ), fieldValue ); getDictionary().setItem( COSName.getPDFName( "DV" ), fieldValue ); } /** * getValue gets the fields value to as a string. * * @return The string value of this field. * * @throws IOException If there is an error getting the value. */ public String getValue() throws IOException { return getDictionary().getString( "V" ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/package.html0000644000000000000000000000177512645757432030210 0ustar rootroot The interactive package contains classes that deal with interactive annotations such as textfields and buttons. pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignature.java0000644000000000000000000000477212645757432030757 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSDictionary; import java.io.IOException; /** * A class for handling the PDF field as a signature. * * @author Ben Litchfield * @version $Revision: 1.5 $ * * @deprecated Use {@link PDSignatureField} instead (see PDFBOX-1513). */ public class PDSignature extends PDField { /** * @see PDField#PDField(PDAcroForm,COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The dictionary for the signature. */ public PDSignature( PDAcroForm theAcroForm, COSDictionary field) { super(theAcroForm,field); throw new RuntimeException( "The usage of " + getClass().getName() + " is deprecated. Please use " + PDSignatureField.class.getName() + " instead (see PDFBOX-1513)" ); } /** * @see PDField#setValue(java.lang.String) * * @param value The new value for the field. * * @throws IOException If there is an error creating the appearance stream. */ public void setValue(String value) throws IOException { throw new RuntimeException( "Not yet implemented" ); } /** * @see PDField#setValue(java.lang.String) * * @return The string value of this field. * * @throws IOException If there is an error creating the appearance stream. */ public String getValue() throws IOException { throw new RuntimeException( "Not yet implemented" ); } /** * Return a string rep of this object. * * @return A string rep of this object. */ public String toString() { return "PDSignature"; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDRadioCollection.java0000644000000000000000000001233112645757432032056 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.util.BitFlagHelper; /** * A class for handling the PDF field as a Radio Collection. * This class automatically keeps track of the child radio buttons * in the collection. * * @see PDCheckbox * @author sug * @version $Revision: 1.13 $ */ public class PDRadioCollection extends PDChoiceButton { /** * A Ff flag. */ public static final int FLAG_RADIOS_IN_UNISON = 1 << 25; /** * @param theAcroForm The acroForm for this field. * @param field The field that makes up the radio collection. * * {@inheritDoc} */ public PDRadioCollection( PDAcroForm theAcroForm, COSDictionary field) { super(theAcroForm,field); } /** * From the PDF Spec
    * If set, a group of radio buttons within a radio button field that * use the same value for the on state will turn on and off in unison; that is if * one is checked, they are all checked. If clear, the buttons are mutually exclusive * (the same behavior as HTML radio buttons). * * @param radiosInUnison The new flag for radiosInUnison. */ public void setRadiosInUnison(boolean radiosInUnison) { BitFlagHelper.setFlag( getDictionary(), COSName.FF, FLAG_RADIOS_IN_UNISON, radiosInUnison ); } /** * * @return true If the flag is set for radios in unison. */ public boolean isRadiosInUnison() { return BitFlagHelper.getFlag( getDictionary(), COSName.FF, FLAG_RADIOS_IN_UNISON ); } /** * This setValue method iterates the collection of radiobuttons * and checks or unchecks each radiobutton according to the * given value. * If the value is not represented by any of the radiobuttons, * then none will be checked. * * {@inheritDoc} */ public void setValue(String value) throws IOException { getDictionary().setString( COSName.V, value ); List kids = getKids(); for (int i = 0; i < kids.size(); i++) { PDField field = (PDField)kids.get(i); if ( field instanceof PDCheckbox ) { PDCheckbox btn = (PDCheckbox)field; if( btn.getOnValue().equals(value) ) { btn.check(); } else { btn.unCheck(); } } } } /** * getValue gets the fields value to as a string. * * @return The string value of this field. * * @throws IOException If there is an error getting the value. */ public String getValue()throws IOException { String retval = null; List kids = getKids(); for (int i = 0; i < kids.size(); i++) { PDField kid = (PDField)kids.get(i); if ( kid instanceof PDCheckbox ) { PDCheckbox btn = (PDCheckbox)kid; if( btn.isChecked() ) { retval = btn.getOnValue(); } } } if( retval == null ) { retval = getDictionary().getNameAsString( COSName.V ); } return retval; } /** * This will return a list of PDField objects that are part of this radio collection. * * @see PDField#getWidget() * @return A list of PDWidget objects. * @throws IOException if there is an error while creating the children objects. */ @SuppressWarnings("unchecked") public List getKids() throws IOException { COSArray kids = (COSArray)getDictionary().getDictionaryObject(COSName.KIDS); if( kids != null ) { List kidsList = new ArrayList(); for (int i = 0; i < kids.size(); i++) { PDField field = PDFieldFactory.createField( getAcroForm(), (COSDictionary)kids.getObject(i) ); if( field != null ) { kidsList.add( field ); } } return new COSArrayList( kidsList, kids ); } else { return new ArrayList(); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAppearance.java0000644000000000000000000012061612645757432031051 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdfparser.PDFStreamParser; import org.apache.pdfbox.pdfwriter.ContentStreamWriter; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFontDescriptor; import org.apache.pdfbox.pdmodel.font.PDSimpleFont; import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.util.PDFOperator; /** * This one took me a while, but i'm proud to say that it handles the appearance of a textbox. This allows you to apply * a value to a field in the document and handle the appearance so that the value is actually visible too. The problem * was described by Ben Litchfield, the author of the example: org.apache.pdfbox.examlpes.fdf.ImportFDF. So Ben, here is * the solution. * * @author sug * @author Ben Litchfield * @version $Revision: 1.20 $ */ public class PDAppearance { private final PDVariableText parent; private String value; private final COSString defaultAppearance; private final PDAcroForm acroForm; private List widgets = new ArrayList(); /** * The highlight color * * The color setting is used by Adobe to display the highlight box for selected entries in a list box. * * Regardless of other settings in an existing appearance stream Adobe will always use this value. */ private static final String HIGHLIGHT_COLOR = "0.600006 0.756866 0.854904 rg"; /** * The default padding. * * Adobe adds a default padding of 1 to the widgets bounding box. * */ private static final int DEFAULT_PADDING = 1; /** * The padding area. * * The box from where he padding into the content area will be calculated. * * The default value is to do a padding of 1 on each side of the widgets bounding box. * * This might be overwritten by a new setting within the BMC/EMC sequence */ private PDRectangle paddingEdge = null; /** * The content area. * * The inner box where the content will be printed The default value is to do a padding of 1 on each side of the * paddingEdge. * * This might be overwritten by a new setting within the BMC/EMC sequence */ private PDRectangle contentArea = null; /** * Constructs a COSAppearnce from the given field. * * @param theAcroForm * the acro form that this field is part of. * @param field * the field which you wish to control the appearance of * @throws IOException * If there is an error creating the appearance. */ public PDAppearance(PDAcroForm theAcroForm, PDVariableText field) throws IOException { acroForm = theAcroForm; parent = field; widgets = field.getKids(); if (widgets == null) { widgets = new ArrayList(); widgets.add(field.getWidget()); } defaultAppearance = getDefaultAppearance(); } /** * Returns the default appearance of a textbox. If the textbox does not have one, then it will be taken from the * AcroForm. * * @return The DA element */ private COSString getDefaultAppearance() { COSString dap = parent.getDefaultAppearance(); if (dap == null) { COSArray kids = (COSArray) parent.getDictionary().getDictionaryObject(COSName.KIDS); if (kids != null && kids.size() > 0) { COSDictionary firstKid = (COSDictionary) kids.getObject(0); dap = (COSString) firstKid.getDictionaryObject(COSName.DA); } if (dap == null) { dap = (COSString) acroForm.getDictionary().getDictionaryObject(COSName.DA); } } return dap; } private int getQ() { int q = parent.getQ(); if (parent.getDictionary().getDictionaryObject(COSName.Q) == null) { COSArray kids = (COSArray) parent.getDictionary().getDictionaryObject(COSName.KIDS); if (kids != null && kids.size() > 0) { COSDictionary firstKid = (COSDictionary) kids.getObject(0); COSNumber qNum = (COSNumber) firstKid.getDictionaryObject(COSName.Q); if (qNum != null) { q = qNum.intValue(); } } } return q; } /** * Extracts the original appearance stream into a list of tokens. * * @return The tokens in the original appearance stream */ private List getStreamTokens(PDAppearanceStream appearanceStream) throws IOException { List tokens = null; if (appearanceStream != null) { tokens = getStreamTokens(appearanceStream.getStream()); } return tokens; } private List getStreamTokens(COSString string) throws IOException { PDFStreamParser parser; List tokens = null; if (string != null) { ByteArrayInputStream stream = new ByteArrayInputStream(string.getBytes()); parser = new PDFStreamParser(stream, acroForm.getDocument().getDocument().getScratchFile()); parser.parse(); tokens = parser.getTokens(); } return tokens; } private List getStreamTokens(COSStream stream) throws IOException { PDFStreamParser parser; List tokens = null; if (stream != null) { parser = new PDFStreamParser(stream); parser.parse(); tokens = parser.getTokens(); } return tokens; } /** * Tests if the apperance stream already contains content. * * @return true if it contains any content */ private boolean containsMarkedContent(List stream) { return stream.contains(PDFOperator.getOperator("BMC")); } /** * Apply padding to a rectangle. * * Padding is used to create different boxes within the widgets 'box model'. * * @return a new rectangle with padding applied */ private PDRectangle applyPadding(PDRectangle bbox, float padding) { PDRectangle area = new PDRectangle(bbox.getCOSArray()); area.setLowerLeftX(area.getLowerLeftX() + padding); area.setLowerLeftY(area.getLowerLeftY() + padding); area.setUpperRightX(area.getUpperRightX() - padding); area.setUpperRightY(area.getUpperRightY() - padding); return area; } /** * This is the public method for setting the appearance stream. * * @param apValue * the String value which the appearance should represent * * @throws IOException * If there is an error creating the stream. */ public void setAppearanceValue(String apValue) throws IOException { value = apValue; Iterator widgetIter = widgets.iterator(); while (widgetIter.hasNext()) { COSObjectable next = widgetIter.next(); PDField field = null; PDAnnotationWidget widget; if (next instanceof PDField) { field = (PDField) next; widget = field.getWidget(); } else { widget = (PDAnnotationWidget) next; } PDFormFieldAdditionalActions actions = null; if (field != null) { actions = field.getActions(); } if (actions != null && actions.getF() != null && widget.getDictionary().getDictionaryObject(COSName.AP) == null) { // do nothing because the field will be formatted by acrobat // when it is opened. See FreedomExpressions.pdf for an example of this. } else { PDAppearanceDictionary appearance = widget.getAppearance(); if (appearance == null) { appearance = new PDAppearanceDictionary(); widget.setAppearance(appearance); } Map normalAppearance = appearance.getNormalAppearance(); PDAppearanceStream appearanceStream = (PDAppearanceStream) normalAppearance.get("default"); if (appearanceStream == null) { COSStream cosStream = acroForm.getDocument().getDocument().createCOSStream(); appearanceStream = new PDAppearanceStream(cosStream); appearanceStream.setBoundingBox(widget.getRectangle().createRetranslatedRectangle()); appearance.setNormalAppearance(appearanceStream); } List tokens = getStreamTokens(appearanceStream); List daTokens = getStreamTokens(getDefaultAppearance()); PDFont pdFont = getFontAndUpdateResources(tokens, appearanceStream); // Special handling for listboxes to address PDFBOX-2249 // TODO: Shall be addressed properly in a future release if (parent instanceof PDChoiceField && (parent.getFieldFlags() & ((PDChoiceField) parent).FLAG_COMBO) == 0) { generateListboxAppearance(widget, pdFont, tokens, daTokens, appearanceStream, value); } else { if (!containsMarkedContent(tokens)) { ByteArrayOutputStream output = new ByteArrayOutputStream(); // BJL 9/25/2004 Must prepend existing stream // because it might have operators to draw things like // rectangles and such ContentStreamWriter writer = new ContentStreamWriter(output); writer.writeTokens(tokens); output.write(" /Tx BMC\n".getBytes("ISO-8859-1")); insertGeneratedAppearance(widget, output, pdFont, tokens, appearanceStream); output.write(" EMC".getBytes("ISO-8859-1")); writeToStream(output.toByteArray(), appearanceStream); } else { if (tokens != null) { if (daTokens != null) { int bmcIndex = tokens.indexOf(PDFOperator.getOperator("BMC")); int emcIndex = tokens.indexOf(PDFOperator.getOperator("EMC")); if (bmcIndex != -1 && emcIndex != -1 && emcIndex == bmcIndex + 1) { // if the EMC immediately follows the BMC index then should // insert the daTokens inbetween the two markers. tokens.addAll(emcIndex, daTokens); } } ByteArrayOutputStream output = new ByteArrayOutputStream(); ContentStreamWriter writer = new ContentStreamWriter(output); float fontSize = calculateFontSize(pdFont, appearanceStream.getBoundingBox(), tokens, daTokens); boolean foundString = false; int indexOfString = -1; int setFontIndex = tokens.indexOf(PDFOperator.getOperator("Tf")); tokens.set(setFontIndex - 1, new COSFloat(fontSize)); int bmcIndex = tokens.indexOf(PDFOperator.getOperator("BMC")); int emcIndex = tokens.indexOf(PDFOperator.getOperator("EMC")); if (bmcIndex != -1) { writer.writeTokens(tokens, 0, bmcIndex + 1); } else { writer.writeTokens(tokens); } output.write("\n".getBytes("ISO-8859-1")); insertGeneratedAppearance(widget, output, pdFont, tokens, appearanceStream); if (emcIndex != -1) { writer.writeTokens(tokens, emcIndex, tokens.size()); } writeToStream(output.toByteArray(), appearanceStream); } else { // hmm? } } } } } } private void generateListboxAppearance(PDAnnotationWidget fieldWidget, PDFont pdFont, List tokens, List daTokens, PDAppearanceStream appearanceStream, String fieldValue) throws IOException { // create paddingEdge and contentArea from bounding box // Default the contentArea to the boundingBox // taking the padding into account paddingEdge = applyPadding(appearanceStream.getBoundingBox(), DEFAULT_PADDING); contentArea = applyPadding(paddingEdge, DEFAULT_PADDING); if (!containsMarkedContent(tokens)) { ByteArrayOutputStream output = new ByteArrayOutputStream(); // BJL 9/25/2004 Must prepend existing stream // because it might have operators to draw things like // rectangles and such ContentStreamWriter writer = new ContentStreamWriter(output); writer.writeTokens(tokens); output.write(" /Tx BMC\n".getBytes("ISO-8859-1")); insertGeneratedListboxAppearance(fieldWidget, output, pdFont, tokens, appearanceStream); output.write(" EMC".getBytes("ISO-8859-1")); writeToStream(output.toByteArray(), appearanceStream); } else { if (tokens != null) { if (daTokens != null) { int bmcIndex = tokens.indexOf(PDFOperator.getOperator("BMC")); int emcIndex = tokens.indexOf(PDFOperator.getOperator("EMC")); if (bmcIndex != -1 && emcIndex != -1 && emcIndex == bmcIndex + 1) { // if the EMC immediately follows the BMC index then should // insert the daTokens inbetween the two markers. tokens.addAll(emcIndex, daTokens); } } ByteArrayOutputStream output = new ByteArrayOutputStream(); ContentStreamWriter writer = new ContentStreamWriter(output); float fontSize = calculateListboxFontSize(pdFont, appearanceStream.getBoundingBox(), tokens, daTokens); boolean foundString = false; int setFontIndex = tokens.indexOf(PDFOperator.getOperator("Tf")); tokens.set(setFontIndex - 1, new COSFloat(fontSize)); int bmcIndex = tokens.indexOf(PDFOperator.getOperator("BMC")); /* * Get the contentArea. * * There might be an inner box defined which defines the area where the text is printed. This typically * looks like ... q 1 1 98 70 re W ... */ { int beginTextIndex = tokens.indexOf(PDFOperator.getOperator("BT")); if (beginTextIndex != -1) { ListIterator innerTokens = tokens.listIterator(bmcIndex); while (innerTokens.hasNext()) { if (innerTokens.next() == PDFOperator.getOperator("re") && innerTokens.next() == PDFOperator.getOperator("W")) { COSArray array = new COSArray(); array.add((COSNumber) tokens.get(innerTokens.previousIndex() - 5)); array.add((COSNumber) tokens.get(innerTokens.previousIndex() - 4)); array.add((COSNumber) tokens.get(innerTokens.previousIndex() - 3)); array.add((COSNumber) tokens.get(innerTokens.previousIndex() - 2)); paddingEdge = new PDRectangle(array); // as the re operator is using start and width/height adjust the generated // dimensions paddingEdge.setUpperRightX(paddingEdge.getLowerLeftX() + paddingEdge.getUpperRightX()); paddingEdge.setUpperRightY(paddingEdge.getLowerLeftY() + paddingEdge.getUpperRightY()); contentArea = applyPadding(paddingEdge, paddingEdge.getLowerLeftX() - appearanceStream.getBoundingBox().getLowerLeftX()); break; } } } } int emcIndex = tokens.indexOf(PDFOperator.getOperator("EMC")); if (bmcIndex != -1) { writer.writeTokens(tokens, 0, bmcIndex + 1); } else { writer.writeTokens(tokens); } output.write("\n".getBytes("ISO-8859-1")); insertGeneratedListboxAppearance(fieldWidget, output, pdFont, tokens, appearanceStream); if (emcIndex != -1) { writer.writeTokens(tokens, emcIndex, tokens.size()); } writeToStream(output.toByteArray(), appearanceStream); } else { // hmm? } } } private void insertGeneratedAppearance(PDAnnotationWidget fieldWidget, OutputStream output, PDFont pdFont, List tokens, PDAppearanceStream appearanceStream) throws IOException { PrintWriter printWriter = new PrintWriter(output, true); float fontSize = 0.0f; PDRectangle boundingBox = appearanceStream.getBoundingBox(); if (boundingBox == null) { boundingBox = fieldWidget.getRectangle().createRetranslatedRectangle(); } // Handle a field with the comb flag being set differently to // address PDFBOX-91 // TODO: Shall be addressed properly in a future release if (parent.shouldComb()) { insertGeneratedPaddingEdge(printWriter, appearanceStream); } printWriter.println("BT"); if (defaultAppearance != null) { String daString = defaultAppearance.getString(); PDFStreamParser daParser = new PDFStreamParser(new ByteArrayInputStream(daString.getBytes("ISO-8859-1")), null); daParser.parse(); List daTokens = daParser.getTokens(); fontSize = calculateFontSize(pdFont, boundingBox, tokens, daTokens); int fontIndex = daTokens.indexOf(PDFOperator.getOperator("Tf")); if (fontIndex != -1) { daTokens.set(fontIndex - 1, new COSFloat(fontSize)); } ContentStreamWriter daWriter = new ContentStreamWriter(output); daWriter.writeTokens(daTokens); } // Handle a field with the comb flag being set differently to // address PDFBOX-91 // TODO: Shall be addressed properly in a future release if (parent.shouldComb() && parent.getDictionary().getInt("MaxLen") != -1) { insertGeneratedCombAppearance(printWriter, pdFont, appearanceStream, fontSize); } else { printWriter.println(getTextPosition(boundingBox, pdFont, fontSize, tokens)); int q = getQ(); if (q == PDTextbox.QUADDING_LEFT) { // do nothing because left is default } else if (q == PDTextbox.QUADDING_CENTERED || q == PDTextbox.QUADDING_RIGHT) { float fieldWidth = boundingBox.getWidth(); float stringWidth = (pdFont.getStringWidth(value) / 1000) * fontSize; float adjustAmount = fieldWidth - stringWidth - 4; if (q == PDTextbox.QUADDING_CENTERED) { adjustAmount = adjustAmount / 2.0f; } printWriter.println(adjustAmount + " 0 Td"); } else { throw new IOException("Error: Unknown justification value:" + q); } // add the value as hex string to deal with non ISO-8859-1 data values if (!isMultiLineValue(value)) { printWriter.println("<" + new COSString(value).getHexString() + "> Tj"); } else { String[] lines = value.split("\n"); for (int i = 0; i < lines.length; i++) { boolean lastLine = i == (lines.length - 1); String endingTag = lastLine ? "> Tj\n" : "> Tj 0 -13 Td"; printWriter.print("<" + new COSString(lines[i]).getHexString() + endingTag); } } } printWriter.println("ET"); printWriter.flush(); } private void insertGeneratedPaddingEdge(PrintWriter printWriter, PDAppearanceStream appearanceStream) { // create paddingEdge and contentArea from bounding box // Default the contentArea to the boundingBox // taking the padding into account paddingEdge = applyPadding(appearanceStream.getBoundingBox(), DEFAULT_PADDING); // print the paddingEdge printWriter.println("q"); printWriter.println(paddingEdge.getLowerLeftX() + " " + paddingEdge.getLowerLeftY() + " " + paddingEdge.getWidth() + " " + paddingEdge.getHeight() + " " + " re"); printWriter.println("W"); printWriter.println("n"); } private void insertGeneratedCombAppearance(PrintWriter printWriter, PDFont pdFont, PDAppearanceStream appearanceStream, float fontSize) throws IOException { // TODO: Currently the quadding is not taken into account // so the comb is always filled from left to right. int maxLen = parent.getDictionary().getInt("MaxLen"); int numChars = maxLen; if (value.length() < maxLen) { numChars = value.length(); } float combWidth = appearanceStream.getBoundingBox().getWidth() / maxLen; float ascentAtFontSize = pdFont.getFontDescriptor().getAscent() / 1000 * fontSize; float baselineOffset = paddingEdge.getLowerLeftY() + (appearanceStream.getBoundingBox().getHeight() - ascentAtFontSize)/2; float prevCharWidth = 0f; float currCharWidth = 0f; float xOffset = combWidth/2; String combString = ""; for (int i = 0; i < numChars; i++) { combString = value.substring(i, i+1); currCharWidth = pdFont.getStringWidth(combString) / 1000 * fontSize/2; xOffset = xOffset + prevCharWidth/2 - currCharWidth/2; printWriter.println(xOffset + " " + baselineOffset + " Td"); printWriter.println("<" + new COSString(combString).getHexString() + "> Tj"); baselineOffset = 0; prevCharWidth = currCharWidth; xOffset = combWidth; } } private void insertGeneratedListboxAppearance(PDAnnotationWidget fieldWidget, OutputStream output, PDFont pdFont, List tokens, PDAppearanceStream appearanceStream) throws IOException { PrintWriter printWriter = new PrintWriter(output, true); float fontSize = 0.0f; PDRectangle boundingBox = appearanceStream.getBoundingBox(); if (boundingBox == null) { boundingBox = fieldWidget.getRectangle().createRetranslatedRectangle(); } List daTokens = null; if (defaultAppearance != null) { String daString = defaultAppearance.getString(); PDFStreamParser daParser = new PDFStreamParser(new ByteArrayInputStream(daString.getBytes("ISO-8859-1")), null); daParser.parse(); daTokens = daParser.getTokens(); fontSize = calculateListboxFontSize(pdFont, contentArea, tokens, daTokens); int fontIndex = daTokens.indexOf(PDFOperator.getOperator("Tf")); if (fontIndex != -1) { daTokens.set(fontIndex - 1, new COSFloat(fontSize)); } } // print the paddingEdge printWriter.println("q"); printWriter.println(paddingEdge.getLowerLeftX() + " " + paddingEdge.getLowerLeftY() + " " + paddingEdge.getWidth() + " " + paddingEdge.getHeight() + " " + " re"); printWriter.println("W"); printWriter.println("n"); // print the highlight color printWriter.println(HIGHLIGHT_COLOR); /* * for a listbox output the rectangle highlighting the selected value */ COSArray indexEntries = ((PDChoiceField) parent).getSelectedOptions(); int selectedIndex = ((COSInteger) indexEntries.get(0)).intValue(); // The first entry which shall be presented might be adjusted by the optional TI key // If this entry is present the first entry to be displayed is the keys value otherwise // display starts with the first entry in Opt. int topIndex = ((PDChoiceField) parent).getTopIndex(); float highlightBoxHeight = pdFont.getFontBoundingBox().getHeight() / 1000 * fontSize; printWriter.println(paddingEdge.getLowerLeftX() + " " + (paddingEdge.getUpperRightY() - highlightBoxHeight * (selectedIndex - topIndex + 1)) + " " + paddingEdge.getWidth() + " " + (highlightBoxHeight) + " re"); printWriter.println("f"); printWriter.println("0 g"); printWriter.println("0 G"); printWriter.println("1 w"); // start of text output printWriter.println("BT"); if (defaultAppearance != null) { ContentStreamWriter daWriter = new ContentStreamWriter(output); daWriter.writeTokens(daTokens); } int q = getQ(); if (q == PDTextbox.QUADDING_LEFT) { // do nothing because left is default } else if (q == PDTextbox.QUADDING_CENTERED || q == PDTextbox.QUADDING_RIGHT) { float fieldWidth = boundingBox.getWidth(); float stringWidth = (pdFont.getStringWidth(value) / 1000) * fontSize; float adjustAmount = fieldWidth - stringWidth - 4; if (q == PDTextbox.QUADDING_CENTERED) { adjustAmount = adjustAmount / 2.0f; } printWriter.println(adjustAmount + " 0 Td"); } else { throw new IOException("Error: Unknown justification value:" + q); } COSArray options = ((PDChoiceField) parent).getOptions(); float yTextPos = contentArea.getUpperRightY(); for (int i = topIndex; i < options.size(); i++) { COSBase option = options.getObject(i); COSArray optionPair = (COSArray) option; COSString optionKey = (COSString) optionPair.getObject(0); COSString optionValue = (COSString) optionPair.getObject(1); if (i == topIndex) { yTextPos = yTextPos - pdFont.getFontDescriptor().getAscent() / 1000 * fontSize; } else { yTextPos = yTextPos - pdFont.getFontBoundingBox().getHeight() / 1000 * fontSize; printWriter.println("BT"); } printWriter.println(contentArea.getLowerLeftX() + " " + yTextPos + " Td"); printWriter.println("<" + optionValue.getHexString() + "> Tj"); if (i - topIndex != (options.size() - 1)) { printWriter.println("ET"); } } printWriter.println("ET"); printWriter.println("Q"); printWriter.flush(); } private PDFont getFontAndUpdateResources(List tokens, PDAppearanceStream appearanceStream) throws IOException { PDFont retval = null; PDResources streamResources = appearanceStream.getResources(); PDResources formResources = acroForm.getDefaultResources(); if (formResources != null) { if (streamResources == null) { streamResources = new PDResources(); appearanceStream.setResources(streamResources); } COSString da = getDefaultAppearance(); if (da != null) { String data = da.getString(); PDFStreamParser streamParser = new PDFStreamParser( new ByteArrayInputStream(data.getBytes("ISO-8859-1")), null); streamParser.parse(); tokens = streamParser.getTokens(); } int setFontIndex = tokens.indexOf(PDFOperator.getOperator("Tf")); COSName cosFontName = (COSName) tokens.get(setFontIndex - 2); String fontName = cosFontName.getName(); retval = (PDFont) streamResources.getFonts().get(fontName); if (retval == null) { retval = (PDFont) formResources.getFonts().get(fontName); streamResources.addFont(retval, fontName); } } return retval; } private boolean isMultiLineValue(String value) { return (parent.isMultiline() && value.contains("\n")); } /** * Writes the stream to the actual stream in the COSStream. * * @throws IOException * If there is an error writing to the stream */ private void writeToStream(byte[] data, PDAppearanceStream appearanceStream) throws IOException { OutputStream out = appearanceStream.getStream().createUnfilteredStream(); out.write(data); out.flush(); } /** * w in an appearance stream represents the lineWidth. * * @return the linewidth */ private float getLineWidth(List tokens) { float retval = 1; if (tokens != null) { int btIndex = tokens.indexOf(PDFOperator.getOperator("BT")); int wIndex = tokens.indexOf(PDFOperator.getOperator("w")); // the w should only be used if it is before the first BT. if ((wIndex > 0) && (wIndex < btIndex)) { retval = ((COSNumber) tokens.get(wIndex - 1)).floatValue(); } } return retval; } private PDRectangle getSmallestDrawnRectangle(PDRectangle boundingBox, List tokens) { PDRectangle smallest = boundingBox; for (int i = 0; i < tokens.size(); i++) { Object next = tokens.get(i); if (next == PDFOperator.getOperator("re")) { COSNumber x = (COSNumber) tokens.get(i - 4); COSNumber y = (COSNumber) tokens.get(i - 3); COSNumber width = (COSNumber) tokens.get(i - 2); COSNumber height = (COSNumber) tokens.get(i - 1); PDRectangle potentialSmallest = new PDRectangle(); potentialSmallest.setLowerLeftX(x.floatValue()); potentialSmallest.setLowerLeftY(y.floatValue()); potentialSmallest.setUpperRightX(x.floatValue() + width.floatValue()); potentialSmallest.setUpperRightY(y.floatValue() + height.floatValue()); if (smallest == null || smallest.getLowerLeftX() < potentialSmallest.getLowerLeftX() || smallest.getUpperRightY() > potentialSmallest.getUpperRightY()) { smallest = potentialSmallest; } } } return smallest; } /** * My "not so great" method for calculating the fontsize. It does not work superb, but it handles ok. * * @return the calculated font-size * * @throws IOException * If there is an error getting the font height. */ private float calculateFontSize(PDFont pdFont, PDRectangle boundingBox, List tokens, List daTokens) throws IOException { float fontSize = 0; if (daTokens != null) { // daString looks like "BMC /Helv 3.4 Tf EMC" // use the fontsize of the default existing apperance stream int fontIndex = daTokens.indexOf(PDFOperator.getOperator("Tf")); if (fontIndex != -1) { fontSize = ((COSNumber) daTokens.get(fontIndex - 1)).floatValue(); } } float widthBasedFontSize = Float.MAX_VALUE; if (parent.doNotScroll()) { // if we don't scroll then we will shrink the font to fit into the text area. float widthAtFontSize1 = pdFont.getStringWidth(value) / 1000.f; float availableWidth = getAvailableWidth(boundingBox, getLineWidth(tokens)); widthBasedFontSize = availableWidth / widthAtFontSize1; } else if (fontSize == 0) { float lineWidth = getLineWidth(tokens); float stringWidth = pdFont.getStringWidth(value); float height = 0; if (pdFont instanceof PDSimpleFont) { height = ((PDSimpleFont) pdFont).getFontBoundingBox().getHeight(); } else { // now much we can do, so lets assume font is square and use width // as the height height = pdFont.getAverageFontWidth(); } height = height / 1000f; float availHeight = getAvailableHeight(boundingBox, lineWidth); fontSize = Math.min((availHeight / height), widthBasedFontSize); } return fontSize; } /** * Calculate the fontsize if autosizing was set. * * @return the calculated font-size * * @throws IOException * If there is an error getting the font height. */ private float calculateListboxFontSize(PDFont pdFont, PDRectangle contentArea, List tokens, List daTokens) throws IOException { float fontSize = 0; if (daTokens != null) { // daString looks like "BMC /Helv 3.4 Tf EMC" int fontIndex = daTokens.indexOf(PDFOperator.getOperator("Tf")); if (fontIndex != -1) { fontSize = ((COSNumber) daTokens.get(fontIndex - 1)).floatValue(); } } // font size of 0 means that the font size has to be calculated // dependent on the strings length so that the string with the // largest width fits into the box available. if (fontSize == 0) { COSArray options = ((PDChoiceField) parent).getOptions(); float maxOptWidth = 0; for (int i = 0; i < options.size(); i++) { COSBase option = options.getObject(i); COSArray optionPair = (COSArray) option; COSString optionValue = (COSString) optionPair.getObject(1); maxOptWidth = Math.max(pdFont.getStringWidth(optionValue.getString()) / 1000.f, maxOptWidth); } float availableWidth = getAvailableWidth(contentArea, getLineWidth(tokens)); fontSize = availableWidth / maxOptWidth; } return fontSize; } /** * Calculates where to start putting the text in the box. The positioning is not quite as accurate as when Acrobat * places the elements, but it works though. * * @return the sting for representing the start position of the text * * @throws IOException * If there is an error calculating the text position. */ private String getTextPosition(PDRectangle boundingBox, PDFont pdFont, float fontSize, List tokens) throws IOException { float lineWidth = getLineWidth(tokens); float pos = 0.0f; if (parent.isMultiline()) { int rows = (int) (getAvailableHeight(boundingBox, lineWidth) / ((int) fontSize)); pos = ((rows) * fontSize) - fontSize; } else { if (pdFont instanceof PDSimpleFont) { // BJL 9/25/2004 // This algorithm is a little bit of black magic. It does // not appear to be documented anywhere. Through examining a few // PDF documents and the value that Acrobat places in there I // have determined that the below method of computing the position // is correct for certain documents, but maybe not all. It does // work f1040ez.pdf and Form_1.pdf PDFontDescriptor fd = ((PDSimpleFont) pdFont).getFontDescriptor(); float bBoxHeight = boundingBox.getHeight(); float fontHeight = fd.getFontBoundingBox().getHeight() + 2 * fd.getDescent(); fontHeight = (fontHeight / 1000) * fontSize; pos = (bBoxHeight - fontHeight) / 2; } else { throw new IOException("Error: Don't know how to calculate the position for non-simple fonts"); } } PDRectangle innerBox = getSmallestDrawnRectangle(boundingBox, tokens); float xInset = 2 + 2 * (boundingBox.getWidth() - innerBox.getWidth()); return Math.round(xInset) + " " + pos + " Td"; } /** * calculates the available width of the box. * * @return the calculated available width of the box */ private float getAvailableWidth(PDRectangle boundingBox, float lineWidth) { return boundingBox.getWidth() - 2 * lineWidth; } /** * calculates the available height of the box. * * @return the calculated available height of the box */ private float getAvailableHeight(PDRectangle boundingBox, float lineWidth) { return boundingBox.getHeight() - 2 * lineWidth; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java0000644000000000000000000005276312645757432030044 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDTextStream; import org.apache.pdfbox.pdmodel.fdf.FDFField; import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.util.BitFlagHelper; /** * This is the superclass for a Field element in a PDF. Based on the COS object model from PDFBox. * * @author sug * */ public abstract class PDField implements COSObjectable { /** * A Ff flag. */ public static final int FLAG_READ_ONLY = 1; /** * A Ff flag. */ public static final int FLAG_REQUIRED = 1 << 1; /** * A Ff flag. */ public static final int FLAG_NO_EXPORT = 1 << 2; private PDAcroForm acroForm; private COSDictionary dictionary; /** * Constructor. * * @param theAcroForm The form that this field is part of. */ public PDField(PDAcroForm theAcroForm) { acroForm = theAcroForm; dictionary = new COSDictionary(); // no required fields in base field class } /** * Creates a COSField from a COSDictionary, expected to be a correct object definition for a field in PDF. * * @param theAcroForm The form that this field is part of. * @param field the PDF objet to represent as a field. */ public PDField(PDAcroForm theAcroForm, COSDictionary field) { acroForm = theAcroForm; dictionary = field; } /** * Returns the partial name of the field. * * @return the name of the field */ public String getPartialName() { return getDictionary().getString(COSName.T); } /** * This will set the partial name of the field. * * @param name The new name for the field. */ public void setPartialName(String name) { getDictionary().setString(COSName.T, name); } /** * Returns the fully qualified name of the field, which is a concatenation of the names of all the parents fields. * * @return the name of the field * * @throws IOException If there is an error generating the fully qualified name. */ public String getFullyQualifiedName() throws IOException { PDField parent = getParent(); String parentName = null; if (parent != null) { parentName = parent.getFullyQualifiedName(); } String finalName = getPartialName(); if (parentName != null) { if (finalName != null) { finalName = parentName + "." + finalName; } else { finalName = parentName; } } return finalName; } /** * Gets the alternate name of the field. * * @return the alternate name of the field */ public String getAlternateFieldName() { return this.getDictionary().getString(COSName.TU); } /** * This will set the alternate name of the field. * * @param alternateFieldName the alternate name of the field */ public void setAlternateFieldName(String alternateFieldName) { this.getDictionary().setString(COSName.TU, alternateFieldName); } /** * Get the FT entry of the field. This is a read only field and is set depending on the actual type. The field type * is an inheritable attribute. This method will return only the direct value on this object. Use the findFieldType * for an upward recursive search. * * @return The Field type. * * @see PDField#findFieldType() */ public String getFieldType() { return getDictionary().getNameAsString(COSName.FT); } /** * Find the field type and optionally do a recursive upward search. Sometimes the fieldtype will be specified on the * parent instead of the direct object. This will look at this object for the field type, if none is specified then * it will look to the parent if there is a parent. If there is no parent and no field type has been found then this * will return null. * * @return The field type or null if none was found. */ public String findFieldType() { return findFieldType(getDictionary()); } private String findFieldType(COSDictionary dic) { String retval = dic.getNameAsString(COSName.FT); if (retval == null) { COSDictionary parent = (COSDictionary) dic.getDictionaryObject(COSName.PARENT, COSName.P); if (parent != null) { retval = findFieldType(parent); } } return retval; } /** * setValue sets the fields value to a given string. * * @param value the string value * * @throws IOException If there is an error creating the appearance stream. */ public abstract void setValue(String value) throws IOException; /** * getValue gets the fields value to as a string. * * @return The string value of this field. * * @throws IOException If there is an error getting the value. */ public abstract String getValue() throws IOException; /** * sets the field to be read-only. * * @param readonly The new flag for readonly. */ public void setReadonly(boolean readonly) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_READ_ONLY, readonly); } /** * * @return true if the field is readonly */ public boolean isReadonly() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_READ_ONLY); } /** * sets the field to be required. * * @param required The new flag for required. */ public void setRequired(boolean required) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_REQUIRED, required); } /** * * @return true if the field is required */ public boolean isRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_REQUIRED); } /** * sets the field to be not exported.. * * @param noExport The new flag for noExport. */ public void setNoExport(boolean noExport) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_NO_EXPORT, noExport); } /** * * @return true if the field is not to be exported. */ public boolean isNoExport() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_NO_EXPORT); } /** * This will get the flags for this field. * * @return flags The set of flags. */ public int getFieldFlags() { int retval = 0; COSInteger ff = (COSInteger) getDictionary().getDictionaryObject(COSName.FF); if (ff != null) { retval = ff.intValue(); } return retval; } /** * This will set the flags for this field. * * @param flags The new flags. */ public void setFieldFlags(int flags) { getDictionary().setInt(COSName.FF, flags); } /** * This will import a fdf field from a fdf document. * * @param fdfField The fdf field to import. * * @throws IOException If there is an error importing the data for this field. */ public void importFDF(FDFField fdfField) throws IOException { Object fieldValue = fdfField.getValue(); int fieldFlags = getFieldFlags(); if (fieldValue != null) { if (fieldValue instanceof String) { setValue((String) fieldValue); } else if (fieldValue instanceof PDTextStream) { setValue(((PDTextStream) fieldValue).getAsString()); } else { throw new IOException("Unknown field type:" + fieldValue.getClass().getName()); } } Integer ff = fdfField.getFieldFlags(); if (ff != null) { setFieldFlags(ff.intValue()); } else { // these are suppose to be ignored if the Ff is set. Integer setFf = fdfField.getSetFieldFlags(); if (setFf != null) { int setFfInt = setFf.intValue(); fieldFlags = fieldFlags | setFfInt; setFieldFlags(fieldFlags); } Integer clrFf = fdfField.getClearFieldFlags(); if (clrFf != null) { // we have to clear the bits of the document fields for every bit that is // set in this field. // // Example: // docFf = 1011 // clrFf = 1101 // clrFfValue = 0010; // newValue = 1011 & 0010 which is 0010 int clrFfValue = clrFf.intValue(); clrFfValue ^= 0xFFFFFFFF; fieldFlags = fieldFlags & clrFfValue; setFieldFlags(fieldFlags); } } PDAnnotationWidget widget = getWidget(); if (widget != null) { int annotFlags = widget.getAnnotationFlags(); Integer f = fdfField.getWidgetFieldFlags(); if (f != null && widget != null) { widget.setAnnotationFlags(f.intValue()); } else { // these are suppose to be ignored if the F is set. Integer setF = fdfField.getSetWidgetFieldFlags(); if (setF != null) { annotFlags = annotFlags | setF.intValue(); widget.setAnnotationFlags(annotFlags); } Integer clrF = fdfField.getClearWidgetFieldFlags(); if (clrF != null) { // we have to clear the bits of the document fields for every bit that is // set in this field. // // Example: // docF = 1011 // clrF = 1101 // clrFValue = 0010; // newValue = 1011 & 0010 which is 0010 int clrFValue = clrF.intValue(); clrFValue ^= 0xFFFFFFFFL; annotFlags = annotFlags & clrFValue; widget.setAnnotationFlags(annotFlags); } } } List fdfKids = fdfField.getKids(); List pdKids = getKids(); for (int i = 0; fdfKids != null && i < fdfKids.size(); i++) { FDFField fdfChild = fdfKids.get(i); String fdfName = fdfChild.getPartialFieldName(); for (int j = 0; j < pdKids.size(); j++) { Object pdChildObj = pdKids.get(j); if (pdChildObj instanceof PDField) { PDField pdChild = (PDField) pdChildObj; if (fdfName != null && fdfName.equals(pdChild.getPartialName())) { pdChild.importFDF(fdfChild); } } } } } /** * This will get the single associated widget that is part of this field. This occurs when the Widget is * embedded in the fields dictionary. Sometimes there are multiple sub widgets associated with this field, * in which case you want to use {@link #getWidgets()}. If the kids entry is specified, then only first * entry in that list will be returned. * * @return The widget that is associated with this field. * @throws IOException If there is an error getting the widget object. */ public PDAnnotationWidget getWidget() throws IOException { PDAnnotationWidget retval = null; List kids = getKids(); if (kids == null) { retval = new PDAnnotationWidget(getDictionary()); } else if (kids.size() > 0) { Object firstKid = kids.get(0); if (firstKid instanceof PDAnnotationWidget) { retval = (PDAnnotationWidget) firstKid; } else { retval = ((PDField) firstKid).getWidget(); } } else { retval = null; } return retval; } /** * Returns the widget annotations associated with this field. * * The widget annotations are returned for terminal fields (fields which * do not have other fields as kids). In case of non terminal fields an * empty List is returned. * * @return The list of widget annotations. */ public List getWidgets() { List widgets = new ArrayList(); COSArray kids = (COSArray) getDictionary().getDictionaryObject(COSName.KIDS); if (kids == null) { // the field itself is a widget widgets.add(new PDAnnotationWidget(getDictionary())); } else { for (int i = 0; i < kids.size(); i++) { COSDictionary kidDictionary = (COSDictionary) kids.getObject(i); if (kidDictionary == null) { continue; } if ("Widget".equals(kidDictionary.getNameAsString(COSName.SUBTYPE))) { widgets.add(new PDAnnotationWidget(kidDictionary)); } } } return widgets; } /** * Get the parent field to this field, or null if none exists. * * @return The parent field. * * @throws IOException If there is an error creating the parent field. */ public PDField getParent() throws IOException { PDField parent = null; COSDictionary parentDic = (COSDictionary) getDictionary().getDictionaryObject(COSName.PARENT, COSName.P); if (parentDic != null) { parent = PDFieldFactory.createField(getAcroForm(), parentDic); } return parent; } /** * Set the parent of this field. * * @param parent The parent to this field. */ public void setParent(PDField parent) { getDictionary().setItem("Parent", parent); } /** * This will find one of the child elements. The name array are the components of the name to search down the tree * of names. The nameIndex is where to start in that array. This method is called recursively until it finds the end * point based on the name array. * * @param name An array that picks the path to the field. * @param nameIndex The index into the array. * @return The field at the endpoint or null if none is found. * @throws IOException If there is an error creating the field. */ public PDField findKid(String[] name, int nameIndex) throws IOException { PDField retval = null; COSArray kids = (COSArray) getDictionary().getDictionaryObject(COSName.KIDS); if (kids != null) { for (int i = 0; retval == null && i < kids.size(); i++) { COSDictionary kidDictionary = (COSDictionary) kids.getObject(i); if (name[nameIndex].equals(kidDictionary.getString("T"))) { retval = PDFieldFactory.createField(acroForm, kidDictionary); if (name.length > nameIndex + 1) { retval = retval.findKid(name, nameIndex + 1); } } } } return retval; } /** * This will get all the kids of this field. The values in the list will either be PDWidget or PDField. Normally * they will be PDWidget objects unless this is a non-terminal field and they will be child PDField objects. * * @return A list of either PDWidget or PDField objects. * @throws IOException If there is an error retrieving the kids. */ public List getKids() throws IOException { List retval = null; COSArray kids = (COSArray) getDictionary().getDictionaryObject(COSName.KIDS); if (kids != null) { List kidsList = new ArrayList(); for (int i = 0; i < kids.size(); i++) { COSDictionary kidDictionary = (COSDictionary) kids.getObject(i); if (kidDictionary == null) { continue; } // Decide if the kid is field or a widget annotation. // A field dictionary that does not have a partial field name (T entry) // of its own shall not be considered a field but simply a Widget annotation. if (kidDictionary.getDictionaryObject(COSName.T) != null) { PDField field = PDFieldFactory.createField(acroForm, kidDictionary); if (field != null) { kidsList.add(field); } } else if ("Widget".equals(kidDictionary.getNameAsString(COSName.SUBTYPE))) { kidsList.add(new PDAnnotationWidget(kidDictionary)); } } retval = new COSArrayList(kidsList, kids); } return retval; } /** * This will set the list of kids. * * @param kids The list of child widgets. */ public void setKids(List kids) { COSArray kidsArray = COSArrayList.converterToCOSArray(kids); getDictionary().setItem(COSName.KIDS, kidsArray); } /** * This will return a string representation of this field. * * @return A string representation of this field. */ @Override public String toString() { return "" + getDictionary().getDictionaryObject(COSName.V); } /** * This will get the acroform that this field is part of. * * @return The form this field is on. */ public PDAcroForm getAcroForm() { return acroForm; } /** * This will set the form this field is on. * * @param value The new form to use. */ public void setAcroForm(PDAcroForm value) { acroForm = value; } /** * This will get the dictionary associated with this field. * * @return The dictionary that this class wraps. */ public COSDictionary getDictionary() { return dictionary; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return dictionary; } /** * Get the additional actions for this field. This will return null if there are no additional actions for this * field. * * @return The actions of the field. */ public PDFormFieldAdditionalActions getActions() { COSDictionary aa = (COSDictionary) dictionary.getDictionaryObject(COSName.AA); PDFormFieldAdditionalActions retval = null; if (aa != null) { retval = new PDFormFieldAdditionalActions(aa); } return retval; } /** * Set the actions of the field. * * @param actions The field actions. */ public void setActions(PDFormFieldAdditionalActions actions) { dictionary.setItem(COSName.AA, actions); } /** * Set the field type. * * @param fieldType the field type string must be one of "Btn", "Ch", "Tx", "Sig" */ protected void setFieldType(String fieldType) { if (fieldType.compareTo("Btn") != 0 && fieldType.compareTo("Ch") != 0 && fieldType.compareTo("Tx") != 0 && fieldType.compareTo("Sig") != 0 ) { throw new IllegalArgumentException("Unknown field type given " + fieldType); } else { getDictionary().setName(COSName.FT, fieldType); } } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoiceButton.java0000644000000000000000000000505312645757432031375 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.common.COSArrayList; import java.util.ArrayList; import java.util.List; /** * This holds common functionality for check boxes and radio buttons. * * @author sug * @version $Revision: 1.4 $ */ public abstract class PDChoiceButton extends PDField { /** * @see PDField#PDField(PDAcroForm,org.apache.pdfbox.cos.COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The field for this button. */ public PDChoiceButton( PDAcroForm theAcroForm, COSDictionary field) { super(theAcroForm, field); } /** * This will get the option values "Opt" entry of the pdf button. * * @return A list of java.lang.String values. */ public List getOptions() { List retval = null; COSArray array = (COSArray)getDictionary().getDictionaryObject( COSName.getPDFName( "Opt" ) ); if( array != null ) { List strings = new ArrayList(); for( int i=0; iBen Litchfield * @version $Revision: 1.2 $ */ public class PDXFA implements COSObjectable { private COSBase xfa; /** * Constructor. * * @param xfaBase The xfa resource. */ public PDXFA( COSBase xfaBase ) { xfa = xfaBase; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return xfa; } /** * Get the XFA content as byte array. * * The XFA is either a stream containing the entire XFA resource * or an array specifying individual packets that together make * up the XFA resource. * * A packet is a pair of a string and stream. The string contains * the name of the XML element and the stream contains the complete * text of this XML element. Each packet represents a complete XML * element, with the exception of the first and last packet, * which specify begin and end tags for the xdp:xdp element. * [IS0 32000-1:2008: 12.7.8] * * @return the XFA content * @throws IOException */ public byte[] getBytes() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream is = null; byte[] xfaBytes = null; try { // handle the case if the XFA is split into individual parts if (this.getCOSObject() instanceof COSArray) { xfaBytes = new byte[1024]; COSArray cosArray = (COSArray) this.getCOSObject(); for (int i = 1; i < cosArray.size(); i += 2) { COSBase cosObj = cosArray.getObject(i); if (cosObj instanceof COSStream) { is = ((COSStream) cosObj).getUnfilteredStream(); int nRead = 0; while ((nRead = is.read(xfaBytes, 0, xfaBytes.length)) != -1) { baos.write(xfaBytes, 0, nRead); } baos.flush(); } } // handle the case if the XFA is represented as a single stream } else if (xfa.getCOSObject() instanceof COSStream) { xfaBytes = new byte[1024]; is = ((COSStream) xfa.getCOSObject()).getUnfilteredStream(); int nRead = 0; while ((nRead = is.read(xfaBytes, 0, xfaBytes.length)) != -1) { baos.write(xfaBytes, 0, nRead); } baos.flush(); } } finally { if (is != null) { is.close(); } if (baos != null) { baos.close(); } } return baos.toByteArray(); } /** * Get the XFA content as W3C document. * * @see #getBytes() * * @return the XFA content * * @throws ParserConfigurationException parser exception. * @throws SAXException parser exception. * @throws IOException if something went wrong when reading the XFA content. * */ public Document getDocument() throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document xfaDocument = builder.parse(new ByteArrayInputStream(this.getBytes())); return xfaDocument; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java0000644000000000000000000002766412645757432030533 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.fdf.FDFDictionary; import org.apache.pdfbox.pdmodel.fdf.FDFDocument; import org.apache.pdfbox.pdmodel.fdf.FDFCatalog; import org.apache.pdfbox.pdmodel.fdf.FDFField; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * This class represents the acroform of a PDF document. * * @author Ben Litchfield * @version $Revision: 1.14 $ */ public class PDAcroForm implements COSObjectable { private COSDictionary acroForm; private PDDocument document; private Map fieldCache; /** * Constructor. * * @param doc The document that this form is part of. */ public PDAcroForm( PDDocument doc ) { document = doc; acroForm = new COSDictionary(); COSArray fields = new COSArray(); acroForm.setItem( COSName.getPDFName( "Fields" ), fields ); } /** * Constructor. * * @param doc The document that this form is part of. * @param form The existing acroForm. */ public PDAcroForm( PDDocument doc, COSDictionary form ) { document = doc; acroForm = form; } /** * This will get the document associated with this form. * * @return The PDF document. */ public PDDocument getDocument() { return document; } /** * This will get the dictionary that this form wraps. * * @return The dictionary for this form. */ public COSDictionary getDictionary() { return acroForm; } /** * This method will import an entire FDF document into the PDF document * that this acroform is part of. * * @param fdf The FDF document to import. * * @throws IOException If there is an error doing the import. */ public void importFDF( FDFDocument fdf ) throws IOException { List fields = fdf.getCatalog().getFDF().getFields(); if( fields != null ) { for( int i=0; i 0 ) { fdfDict.setFields( fdfFields ); } return fdf; } private void addFieldAndChildren( PDField docField, List fdfFields ) throws IOException { Object fieldValue = docField.getValue(); FDFField fdfField = new FDFField(); fdfField.setPartialFieldName( docField.getPartialName() ); fdfField.setValue( fieldValue ); List kids = docField.getKids(); List childFDFFields = new ArrayList(); if( kids != null ) { for( int i=0; i 0 ) { fdfField.setKids( childFDFFields ); } } if( fieldValue != null || childFDFFields.size() > 0 ) { fdfFields.add( fdfField ); } } /** * This will return all of the documents root fields. * * A field might have children that are fields (non-terminal field) or does not * have children which are fields (terminal fields). * * The fields within an AcroForm are organized in a tree structure. The documents root fields * might either be terminal fields, non-terminal fields or a mixture of both. Non-terminal fields * mark branches which contents can be retrieved using {@link PDFieldTreeNode#getKids()}. * * @return A list of the documents root fields. */ public List getFields() throws IOException { List retval = null; COSArray fields = (COSArray) acroForm.getDictionaryObject( COSName.getPDFName("Fields")); if( fields != null ) { List actuals = new ArrayList(); for (int i = 0; i < fields.size(); i++) { COSDictionary element = (COSDictionary) fields.getObject(i); if (element != null) { PDField field = PDFieldFactory.createField( this, element ); if( field != null ) { actuals.add(field); } } } retval = new COSArrayList( actuals, fields ); } return retval; } /** * Set the documents root fields. * * @param fields The fields that are part of the documents root fields. */ public void setFields( List fields ) { acroForm.setItem( "Fields", COSArrayList.converterToCOSArray( fields )); } /** * This will tell this form to cache the fields into a Map structure * for fast access via the getField method. The default is false. You would * want this to be false if you were changing the COSDictionary behind the scenes, * otherwise setting this to true is acceptable. * * @param cache A boolean telling if we should cache the fields. * @throws IOException If there is an error while caching the fields. */ public void setCacheFields( boolean cache ) throws IOException { if( cache ) { fieldCache = new HashMap(); List fields = getFields(); Iterator fieldIter = fields.iterator(); while( fieldIter.hasNext() ) { PDField next = (PDField)fieldIter.next(); fieldCache.put( next.getFullyQualifiedName(), next ); } } else { fieldCache = null; } } /** * This will tell if this acro form is caching the fields. * * @return true if the fields are being cached. */ public boolean isCachingFields() { return fieldCache != null; } /** * This will get a field by name, possibly using the cache if setCache is true. * * @param name The name of the field to get. * * @return The field with that name of null if one was not found. * * @throws IOException If there is an error getting the field type. */ public PDField getField( String name ) throws IOException { PDField retval = null; if( fieldCache != null ) { retval = (PDField)fieldCache.get( name ); } else { String[] nameSubSection = name.split( "\\." ); COSArray fields = (COSArray) acroForm.getDictionaryObject( COSName.getPDFName("Fields")); if (fields != null) { for (int i = 0; i < fields.size() && retval == null; i++) { COSDictionary element = (COSDictionary) fields.getObject(i); if( element != null ) { COSString fieldName = (COSString)element.getDictionaryObject( COSName.getPDFName( "T" ) ); if( fieldName.getString().equals( name ) || fieldName.getString().equals( nameSubSection[0] ) ) { PDField root = PDFieldFactory.createField( this, element ); if( nameSubSection.length > 1 ) { PDField kid = root.findKid( nameSubSection, 1 ); if( kid != null ) { retval = kid; } else { retval = root; } } else { retval = root; } } } } } } return retval; } /** * This will get the default resources for the acro form. * * @return The default resources. */ public PDResources getDefaultResources() { PDResources retval = null; COSDictionary dr = (COSDictionary)acroForm.getDictionaryObject( COSName.getPDFName( "DR" ) ); if( dr != null ) { retval = new PDResources( dr ); } return retval; } /** * This will set the default resources for the acroform. * * @param dr The new default resources. */ public void setDefaultResources( PDResources dr ) { COSDictionary drDict = null; if( dr != null ) { drDict = dr.getCOSDictionary(); } acroForm.setItem( COSName.getPDFName( "DR" ), drDict ); } /** * {@inheritDoc} */ public COSBase getCOSObject() { return acroForm; } /** * Get the XFA resource, the XFA resource is only used for PDF 1.5+ forms. * * @return The xfa resource or null if it does not exist. */ public PDXFA getXFA() { PDXFA xfa = null; COSBase base = acroForm.getDictionaryObject( "XFA" ); if( base != null ) { xfa = new PDXFA( base ); } return xfa; } /** * Set the XFA resource, this is only used for PDF 1.5+ forms. * * @param xfa The xfa resource. */ public void setXFA( PDXFA xfa ) { acroForm.setItem( "XFA", xfa ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java0000644000000000000000000001217412645757432031364 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSDictionary; import java.io.IOException; /** * This is the Factory for creating and returning the correct * field elements. * * @author sug * @version $Revision: 1.8 $ */ public class PDFieldFactory { private static final int RADIO_BITMASK = 32768; private static final int PUSHBUTTON_BITMASK = 65536; private static final String FIELD_TYPE_BTN = "Btn"; private static final String FIELD_TYPE_TX = "Tx"; private static final String FIELD_TYPE_CH = "Ch"; private static final String FIELD_TYPE_SIG = "Sig"; /** * Utility class so no constructor. */ private PDFieldFactory() { //do nothing. } /** * This method creates a COSField subclass from the given field. * The field is a PDF Dictionary object that must represent a * field element. - othewise null is returned * * @param acroForm The form that the field will be part of. * @param field The dictionary representing a field element * * @return a subclass to COSField according to the kind of field passed to createField * @throws IOException If there is an error determining the field type. */ public static PDField createField( PDAcroForm acroForm, COSDictionary field) throws IOException { PDField pdField = new PDUnknownField( acroForm, field ); if( isButton(pdField) ) { int flags = pdField.getFieldFlags(); if(isRadio(flags) ) { pdField = new PDRadioCollection( acroForm, field ); } else if( isPushButton( flags ) ) { pdField = new PDPushButton( acroForm, field ); } else { pdField = new PDCheckbox( acroForm, field ); } } else if (isChoiceField(pdField)) { pdField = new PDChoiceField( acroForm, field ); } else if (isTextbox(pdField)) { pdField = new PDTextbox( acroForm, field ); } else if( isSignature( pdField ) ) { pdField = new PDSignatureField( acroForm, field ); } else { //do nothing and return an unknown field type. } return pdField; } /** * This method determines if the given * field is a radiobutton collection. * * @param flags The field flags. * * @return the result of the determination */ private static boolean isRadio( int flags ) { return (flags & RADIO_BITMASK) > 0; } /** * This method determines if the given * field is a pushbutton. * * @param flags The field flags. * * @return the result of the determination */ private static boolean isPushButton( int flags ) { return (flags & PUSHBUTTON_BITMASK) > 0; } /** * This method determines if the given field is a choicefield * Choicefields are either listboxes or comboboxes. * * @param field the field to determine * @return the result of the determination */ private static boolean isChoiceField(PDField field) throws IOException { return FIELD_TYPE_CH.equals(field.findFieldType()); } /** * This method determines if the given field is a button. * * @param field the field to determine * @return the result of the determination * * @throws IOException If there is an error determining the field type. */ private static boolean isButton(PDField field) throws IOException { String ft = field.findFieldType(); return FIELD_TYPE_BTN.equals( ft ); } /** * This method determines if the given field is a signature. * * @param field the field to determine * @return the result of the determination */ private static boolean isSignature(PDField field) throws IOException { return FIELD_TYPE_SIG.equals(field.findFieldType()); } /** * This method determines if the given field is a Textbox. * * @param field the field to determine * @return the result of the determination */ private static boolean isTextbox(PDField field) throws IOException { return FIELD_TYPE_TX.equals(field.findFieldType()); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDCheckbox.java0000644000000000000000000001061612645757432030536 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.form; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import java.io.IOException; import java.util.List; /** * A class for handling the PDF field as a checkbox. * * @author Ben Litchfield * @author sug * @version $Revision: 1.11 $ */ public class PDCheckbox extends PDChoiceButton { private static final COSName KEY = COSName.getPDFName("AS"); private static final COSName OFF_VALUE = COSName.getPDFName("Off"); /** * @see PDField#PDField(PDAcroForm,COSDictionary) * * @param theAcroForm The acroForm for this field. * @param field The checkbox field dictionary */ public PDCheckbox( PDAcroForm theAcroForm, COSDictionary field) { super( theAcroForm, field); } /** * This will tell if this radio button is currently checked or not. * * @return true If the radio button is checked. */ public boolean isChecked() { String v = getDictionary().getNameAsString("V"); if (v == null) { return false; } return v.compareTo(getOnValue()) == 0; } /** * Checks the radiobutton. */ public void check() { setValue(getOnValue()); } /** * Unchecks the radiobutton. */ public void unCheck() { setValue(OFF_VALUE.getName()); } /** * {@inheritDoc} */ public void setValue(String newValue) { getDictionary().setName( "V", newValue ); List widgets = getWidgets(); for (PDAnnotationWidget widget : widgets) { if( newValue == null ) { widget.getDictionary().setItem( KEY, OFF_VALUE ); } else { widget.getDictionary().setName( KEY, newValue ); } } } /** * This will get the value of the radio button. * * @return The value of the radio button. */ public String getOffValue() { return OFF_VALUE.getName(); } /** * This will get the value of the radio button. * * @return The value of the radio button. */ public String getOnValue() { List widgets = getWidgets(); for (PDAnnotationWidget widget : widgets) { COSDictionary ap = (COSDictionary) widget.getDictionary().getDictionaryObject(COSName.getPDFName("AP")); widget.getDictionary().setItem(KEY, COSName.getPDFName("Yes")); COSBase n = ap.getDictionaryObject(COSName.getPDFName("N")); //N can be a COSDictionary or a COSStream if( n instanceof COSDictionary ) { for( COSName key :((COSDictionary)n).keySet() ) { if( !key.equals( OFF_VALUE) ) { return key.getName(); } } } } // normally you would expect to get an empty string but as the // prior implementation returned null keep the behavior. return null; } /** * getValue gets the fields value to as a string. * * @return The string value of this field. * * @throws IOException If there is an error getting the value. */ public String getValue() throws IOException { return getDictionary().getNameAsString( "V" ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/0000755000000000000000000000000012645757432030475 5ustar rootroot././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/package.h0000644000000000000000000000171012645757432032240 0ustar rootroot A package to allow access to document viewing preferences. ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerP0000644000000000000000000003460312645757432032233 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.viewerpreferences; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This is the document viewing preferences. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class PDViewerPreferences implements COSObjectable { /** * From PDF Reference: "Neither document outline nor thumbnail images visible". * * @deprecated use {@link NON_FULL_SCREEN_PAGE_MODE} instead */ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_NONE = "UseNone"; /** * From PDF Reference: "Document outline visible". * * @deprecated use {@link NON_FULL_SCREEN_PAGE_MODE} instead */ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_OUTLINES = "UseOutlines"; /** * From PDF Reference: "Thumbnail images visible". * * @deprecated use {@link NON_FULL_SCREEN_PAGE_MODE} instead */ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_THUMBS = "UseThumbs"; /** * From PDF Reference: "Optional content group panel visible". * * @deprecated use {@link NON_FULL_SCREEN_PAGE_MODE} instead */ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_OPTIONAL_CONTENT = "UseOC"; /** * Enumeration containing all valid values for NonFullScreenPageMode. */ public static enum NON_FULL_SCREEN_PAGE_MODE { /** * From PDF Reference: "Neither document outline nor thumbnail images visible". */ UseNone, /** * From PDF Reference: "Document outline visible". */ UseOutlines, /** * From PDF Reference: "Thumbnail images visible". */ UseThumbs, /** * From PDF Reference: "Optional content group panel visible". */ UseOC } /** * Reading direction. * * @deprecated use {@link READING_DIRECTION} instead */ public static final String READING_DIRECTION_L2R = "L2R"; /** * Reading direction. * * @deprecated use {@link READING_DIRECTION} instead */ public static final String READING_DIRECTION_R2L = "R2L"; /** * Enumeration containing all valid values for ReadingDirection. */ public static enum READING_DIRECTION { /** * left to right. */ L2R, /** * right to left. */ R2L } /** * Boundary constant. * * @deprecated use {@link BOUNDARY} instead */ public static final String BOUNDARY_MEDIA_BOX = "MediaBox"; /** * Boundary constant. * * @deprecated use {@link BOUNDARY} instead */ public static final String BOUNDARY_CROP_BOX = "CropBox"; /** * Boundary constant. * * @deprecated use {@link BOUNDARY} instead */ public static final String BOUNDARY_BLEED_BOX = "BleedBox"; /** * Boundary constant. * * @deprecated use {@link BOUNDARY} instead */ public static final String BOUNDARY_TRIM_BOX = "TrimBox"; /** * Boundary constant. * * @deprecated use {@link BOUNDARY} instead */ public static final String BOUNDARY_ART_BOX = "ArtBox"; /** * Enumeration containing all valid values for boundaries. */ public static enum BOUNDARY { /** * use media box as boundary. */ MediaBox, /** * use crop box as boundary. */ CropBox, /** * use bleed box as boundary. */ BleedBox, /** * use trim box as boundary. */ TrimBox, /** * use art box as boundary. */ ArtBox } /** * Enumeration containing all valid values for duplex. */ public static enum DUPLEX { /** * simplex printing. */ Simplex, /** * duplex printing, flip at short edge. */ DuplexFlipShortEdge, /** * duplex printing, flip at long edge. */ DuplexFlipLongEdge } /** * Enumeration containing all valid values for printscaling. */ public static enum PRINT_SCALING { /** * no scaling. */ None, /** * use app default. */ AppDefault } private COSDictionary prefs; /** * Constructor that is used for a preexisting dictionary. * * @param dic The underlying dictionary. */ public PDViewerPreferences( COSDictionary dic ) { prefs = dic; } /** * This will get the underlying dictionary that this object wraps. * * @return The underlying info dictionary. */ public COSDictionary getDictionary() { return prefs; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return prefs; } /** * Get the toolbar preference. * * @return the toolbar preference. */ public boolean hideToolbar() { return prefs.getBoolean( COSName.HIDE_TOOLBAR, false ); } /** * Set the toolbar preference. * * @param value Set the toolbar preference. */ public void setHideToolbar( boolean value ) { prefs.setBoolean( COSName.HIDE_TOOLBAR, value ); } /** * Get the menubar preference. * * @return the menubar preference. */ public boolean hideMenubar() { return prefs.getBoolean( COSName.HIDE_MENUBAR, false ); } /** * Set the menubar preference. * * @param value Set the menubar preference. */ public void setHideMenubar( boolean value ) { prefs.setBoolean( COSName.HIDE_MENUBAR, value ); } /** * Get the window UI preference. * * @return the window UI preference. */ public boolean hideWindowUI() { return prefs.getBoolean( COSName.HIDE_WINDOWUI, false ); } /** * Set the window UI preference. * * @param value Set the window UI preference. */ public void setHideWindowUI( boolean value ) { prefs.setBoolean( COSName.HIDE_WINDOWUI, value ); } /** * Get the fit window preference. * * @return the fit window preference. */ public boolean fitWindow() { return prefs.getBoolean( COSName.FIT_WINDOW, false ); } /** * Set the fit window preference. * * @param value Set the fit window preference. */ public void setFitWindow( boolean value ) { prefs.setBoolean( COSName.FIT_WINDOW, value ); } /** * Get the center window preference. * * @return the center window preference. */ public boolean centerWindow() { return prefs.getBoolean( COSName.CENTER_WINDOW, false ); } /** * Set the center window preference. * * @param value Set the center window preference. */ public void setCenterWindow( boolean value ) { prefs.setBoolean( COSName.CENTER_WINDOW, value ); } /** * Get the display doc title preference. * * @return the display doc title preference. */ public boolean displayDocTitle() { return prefs.getBoolean( COSName.DISPLAY_DOC_TITLE, false ); } /** * Set the display doc title preference. * * @param value Set the display doc title preference. */ public void setDisplayDocTitle( boolean value ) { prefs.setBoolean( COSName.DISPLAY_DOC_TITLE, value ); } /** * Get the non full screen page mode preference. * * @return the non full screen page mode preference. */ public String getNonFullScreenPageMode() { return prefs.getNameAsString( COSName.NON_FULL_SCREEN_PAGE_MODE, NON_FULL_SCREEN_PAGE_MODE.UseNone.toString()); } /** * Set the non full screen page mode preference. * * @param value Set the non full screen page mode preference. */ public void setNonFullScreenPageMode( NON_FULL_SCREEN_PAGE_MODE value ) { prefs.setName( COSName.NON_FULL_SCREEN_PAGE_MODE, value.toString() ); } /** * Set the non full screen page mode preference. * * @param value Set the non full screen page mode preference. * * @deprecated */ public void setNonFullScreenPageMode( String value ) { prefs.setName( COSName.NON_FULL_SCREEN_PAGE_MODE, value ); } /** * Get the reading direction preference. * * @return the reading direction preference. */ public String getReadingDirection() { return prefs.getNameAsString( COSName.DIRECTION, READING_DIRECTION.L2R.toString()); } /** * Set the reading direction preference. * * @param value Set the reading direction preference. */ public void setReadingDirection( READING_DIRECTION value ) { prefs.setName( COSName.DIRECTION, value.toString() ); } /** * Set the reading direction preference. * * @param value Set the reading direction preference. * * @deprecated */ public void setReadingDirection( String value ) { prefs.setName( COSName.DIRECTION, value.toString() ); } /** * Get the ViewArea preference. See BOUNDARY enumeration. * * @return the ViewArea preference. */ public String getViewArea() { return prefs.getNameAsString( COSName.VIEW_AREA, BOUNDARY.CropBox.toString()); } /** * Set the ViewArea preference. See BOUNDARY_XXX constants. * * @param value Set the ViewArea preference. * * @deprecated */ public void setViewArea( String value ) { prefs.setName( COSName.VIEW_AREA, value ); } /** * Set the ViewArea preference. See BOUNDARY enumeration. * * @param value Set the ViewArea preference. */ public void setViewArea( BOUNDARY value ) { prefs.setName( COSName.VIEW_AREA, value.toString() ); } /** * Get the ViewClip preference. See BOUNDARY enumeration. * * @return the ViewClip preference. */ public String getViewClip() { return prefs.getNameAsString( COSName.VIEW_CLIP, BOUNDARY.CropBox.toString()); } /** * Set the ViewClip preference. See BOUNDARY enumeration. * * @param value Set the ViewClip preference. */ public void setViewClip( BOUNDARY value ) { prefs.setName( COSName.VIEW_CLIP, value.toString() ); } /** * Set the ViewClip preference. See BOUNDARY_XXX constants. * * @param value Set the ViewClip preference. * * @deprecated */ public void setViewClip( String value ) { prefs.setName( COSName.VIEW_CLIP, value ); } /** * Get the PrintArea preference. See BOUNDARY enumeration. * * @return the PrintArea preference. */ public String getPrintArea() { return prefs.getNameAsString( COSName.PRINT_AREA, BOUNDARY.CropBox.toString()); } /** * Set the PrintArea preference. See BOUNDARY_XXX constants. * * @param value Set the PrintArea preference. * * @deprecated */ public void setPrintArea( String value ) { prefs.setName( COSName.PRINT_AREA, value ); } /** * Set the PrintArea preference. See BOUNDARY enumeration. * * @param value Set the PrintArea preference. */ public void setPrintArea( BOUNDARY value ) { prefs.setName( COSName.PRINT_AREA, value.toString() ); } /** * Get the PrintClip preference. See BOUNDARY enumeration. * * @return the PrintClip preference. */ public String getPrintClip() { return prefs.getNameAsString( COSName.PRINT_CLIP, BOUNDARY.CropBox.toString()); } /** * Set the PrintClip preference. See BOUNDARY_XXX constants. * * @param value Set the PrintClip preference. * * @deprecated */ public void setPrintClip( String value ) { prefs.setName( COSName.PRINT_CLIP, value ); } /** * Set the PrintClip preference. See BOUNDARY enumeration. * * @param value Set the PrintClip preference. */ public void setPrintClip( BOUNDARY value ) { prefs.setName( COSName.PRINT_CLIP, value.toString() ); } /** * Get the Duplex preference. See DUPLEX enumeration. * * @return the Duplex preference. */ public String getDuplex() { return prefs.getNameAsString( COSName.DUPLEX ); } /** * Set the Duplex preference. See DUPLEX enumeration. * * @param value Set the Duplex preference. */ public void setDuplex( DUPLEX value ) { prefs.setName( COSName.DUPLEX, value.toString() ); } /** * Get the PrintScaling preference. See PRINT_SCALING enumeration. * * @return the PrintScaling preference. */ public String getPrintScaling() { return prefs.getNameAsString( COSName.PRINT_SCALING , PRINT_SCALING.AppDefault.toString()); } /** * Set the PrintScaling preference. See PRINT_SCALING enumeration. * * @param value Set the PrintScaling preference. */ public void setPrintScaling( PRINT_SCALING value ) { prefs.setName( COSName.PRINT_SCALING, value.toString() ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/0000755000000000000000000000000012645757432030311 5ustar rootroot././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSeedValueMDP.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSeedValu0000644000000000000000000000522612645757432032175 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** *

    This MDP dictionary is a part of the seed value dictionary and define * if a author signature or a certification signature should be use.

    * *

    For more informations, consider the spare documented chapter in the seed * value dictionary in the ISO 32000 specification.

    * * @author Thomas Chojecki * @version $Revision: 1.1 $ */ public class PDSeedValueMDP { private COSDictionary dictionary; /** * Default constructor. */ public PDSeedValueMDP() { dictionary = new COSDictionary(); dictionary.setDirect(true); } /** * Constructor. * * @param dict The signature dictionary. */ public PDSeedValueMDP(COSDictionary dict) { dictionary = dict; dictionary.setDirect(true); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return getDictionary(); } /** * Convert this standard java object to a COS dictionary. * * @return The COS dictionary that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * Return the P value. * * @return the P value */ public int getP() { return dictionary.getInt(COSName.P); } /** * Set the P value. * * @param p the value to be set as P */ public void setP(int p) { if (p < 0 || p > 3) { throw new IllegalArgumentException("Only values between 0 and 3 nare allowed."); } dictionary.setInt(COSName.P, p); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/0000755000000000000000000000000012645757432031746 5ustar rootroot././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PD0000644000000000000000000001644112645757432032202 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.geom.AffineTransform; import java.io.IOException; import java.io.InputStream; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** * That class builds visible signature template * which will be added in our pdf document * @author Vakhtang koroghlishvili (Gogebashvili) * */ public interface PDFTemplateBuilder { /** * In order to create Affine Transform, using parameters * @param params */ public void createAffineTransform(byte[] params); /** * Creates specified size page * * @param properties */ public void createPage(PDVisibleSignDesigner properties); /** * Creates template using page * * @param page * @throws IOException */ public void createTemplate(PDPage page) throws IOException; /** * Creates Acro forms in the template * * @param template */ public void createAcroForm(PDDocument template); /** * Creates signature fields * * @param acroForm * @throws IOException */ public void createSignatureField(PDAcroForm acroForm) throws IOException; /** * Creates PDSignature * * @param pdSignatureField * @param page * @param signatureName * @throws IOException */ public void createSignature(PDSignatureField pdSignatureField, PDPage page, String signatureName) throws IOException; /** * Create AcroForm Dictionary * * @param acroForm * @param signatureField * @throws IOException */ public void createAcroFormDictionary(PDAcroForm acroForm, PDSignatureField signatureField) throws IOException; /** * Creates SingatureRectangle * * @param signatureField * @param properties * @throws IOException */ public void createSignatureRectangle(PDSignatureField signatureField, PDVisibleSignDesigner properties) throws IOException; /** * Creates procSetArray of PDF,Text,ImageB,ImageC,ImageI */ public void createProcSetArray(); /** * Creates signature image * @param template * @param InputStream * @throws IOException */ public void createSignatureImage(PDDocument template, InputStream InputStream) throws IOException; /** * * @param params */ public void createFormaterRectangle(byte[] params); /** * * @param template */ public void createHolderFormStream(PDDocument template); /** * Creates resources of form */ public void createHolderFormResources(); /** * Creates Form * * @param holderFormResources * @param holderFormStream * @param formrect */ public void createHolderForm(PDResources holderFormResources, PDStream holderFormStream, PDRectangle formrect); /** * Creates appearance dictionary * * @param holderForml * @param signatureField * @throws IOException */ public void createAppearanceDictionary(PDXObjectForm holderForml, PDSignatureField signatureField) throws IOException; /** * * @param template */ public void createInnerFormStream(PDDocument template); /** * Creates InnerForm */ public void createInnerFormResource(); /** * * @param innerFormResources * @param innerFormStream * @param formrect */ public void createInnerForm(PDResources innerFormResources, PDStream innerFormStream, PDRectangle formrect); /** * * @param innerForm * @param holderFormResources */ public void insertInnerFormToHolerResources(PDXObjectForm innerForm, PDResources holderFormResources); /** * * @param template */ public void createImageFormStream(PDDocument template); /** * Create resource of image form */ public void createImageFormResources(); /** * Creates Image form * * @param imageFormResources * @param innerFormResource * @param imageFormStream * @param formrect * @param affineTransform * @param img * @throws IOException */ public void createImageForm(PDResources imageFormResources, PDResources innerFormResource, PDStream imageFormStream, PDRectangle formrect, AffineTransform affineTransform, PDJpeg img) throws IOException; /** * Inject procSetArray * * @param innerForm * @param page * @param innerFormResources * @param imageFormResources * @param holderFormResources * @param procSet */ public void injectProcSetArray(PDXObjectForm innerForm, PDPage page, PDResources innerFormResources, PDResources imageFormResources, PDResources holderFormResources, COSArray procSet); /** * injects appearance streams * * @param holderFormStream * @param innterFormStream * @param imageFormStream * @param imageObjectName * @param imageName * @param innerFormName * @param properties * @throws IOException */ public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, PDStream imageFormStream, String imageObjectName, String imageName, String innerFormName, PDVisibleSignDesigner properties) throws IOException; /** * just to create visible signature * * @param template */ public void createVisualSignature(PDDocument template); /** * adds Widget Dictionary * * @param signatureField * @param holderFormResources * @throws IOException */ public void createWidgetDictionary(PDSignatureField signatureField, PDResources holderFormResources) throws IOException; /** * * @return - PDF template Structure */ public PDFTemplateStructure getStructure(); /** * Closes template * * @param template * @throws IOException */ public void closeTemplate(PDDocument template) throws IOException; } ././@LongLink0000644000000000000000000000017300000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PD0000644000000000000000000003475612645757432032213 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.geom.AffineTransform; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** * That's implementation of PDFTemplateBuilder * @see org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDFTemplateBuilder * @author vakhtang koroghlishvili (gogebashvili) * */ public class PDVisibleSigBuilder implements PDFTemplateBuilder { private PDFTemplateStructure pdfStructure; private static final Log logger = LogFactory.getLog(PDVisibleSigBuilder.class); public void createPage(PDVisibleSignDesigner properties) { PDPage page = new PDPage(); page.setMediaBox(new PDRectangle(properties.getPageWidth(), properties.getPageHeight())); pdfStructure.setPage(page); logger.info("PDF page has been created"); } public void createTemplate(PDPage page) throws IOException { PDDocument template = new PDDocument(); template.addPage(page); pdfStructure.setTemplate(template); } public PDVisibleSigBuilder() { pdfStructure = new PDFTemplateStructure(); logger.info("PDF Strucure has been Created"); } public void createAcroForm(PDDocument template) { PDAcroForm theAcroForm = new PDAcroForm(template); template.getDocumentCatalog().setAcroForm(theAcroForm); pdfStructure.setAcroForm(theAcroForm); logger.info("Acro form page has been created"); } public PDFTemplateStructure getStructure() { return pdfStructure; } public void createSignatureField(PDAcroForm acroForm) throws IOException { PDSignatureField sf = new PDSignatureField(acroForm); pdfStructure.setSignatureField(sf); logger.info("Signature field has been created"); } public void createSignature(PDSignatureField pdSignatureField, PDPage page, String signatureName) throws IOException { PDSignature pdSignature = new PDSignature(); pdSignatureField.setSignature(pdSignature); pdSignatureField.getWidget().setPage(page); page.getAnnotations().add(pdSignatureField.getWidget()); pdSignature.setName(signatureName); pdSignature.setByteRange(new int[] { 0, 0, 0, 0 }); pdSignature.setContents(new byte[4096]); pdfStructure.setPdSignature(pdSignature); logger.info("PDSignatur has been created"); } public void createAcroFormDictionary(PDAcroForm acroForm, PDSignatureField signatureField) throws IOException { @SuppressWarnings("unchecked") List acroFormFields = acroForm.getFields(); COSDictionary acroFormDict = acroForm.getDictionary(); acroFormDict.setDirect(true); acroFormDict.setInt(COSName.SIG_FLAGS, 3); acroFormFields.add(signatureField); acroFormDict.setString(COSName.DA, "/sylfaen 0 Tf 0 g"); pdfStructure.setAcroFormFields(acroFormFields); pdfStructure.setAcroFormDictionary(acroFormDict); logger.info("AcroForm dictionary has been created"); } public void createSignatureRectangle(PDSignatureField signatureField, PDVisibleSignDesigner properties) throws IOException { PDRectangle rect = new PDRectangle(); rect.setUpperRightX(properties.getxAxis() + properties.getWidth()); rect.setUpperRightY(properties.getTemplateHeight() - properties.getyAxis()); rect.setLowerLeftY(properties.getTemplateHeight() - properties.getyAxis() - properties.getHeight()); rect.setLowerLeftX(properties.getxAxis()); signatureField.getWidget().setRectangle(rect); pdfStructure.setSignatureRectangle(rect); logger.info("rectangle of signature has been created"); } public void createAffineTransform(byte[] params) { AffineTransform transform = new AffineTransform(params[0], params[1], params[2], params[3], params[4], params[5]); pdfStructure.setAffineTransform(transform); logger.info("Matrix has been added"); } public void createProcSetArray() { COSArray procSetArr = new COSArray(); procSetArr.add(COSName.getPDFName("PDF")); procSetArr.add(COSName.getPDFName("Text")); procSetArr.add(COSName.getPDFName("ImageB")); procSetArr.add(COSName.getPDFName("ImageC")); procSetArr.add(COSName.getPDFName("ImageI")); pdfStructure.setProcSet(procSetArr); logger.info("ProcSet array has been created"); } public void createSignatureImage(PDDocument template, InputStream inputStream) throws IOException { PDJpeg img = new PDJpeg(template, inputStream); pdfStructure.setJpedImage(img); logger.info("Visible Signature Image has been created"); // pdfStructure.setTemplate(template); inputStream.close(); } public void createFormaterRectangle(byte[] params) { PDRectangle formrect = new PDRectangle(); formrect.setUpperRightX(params[0]); formrect.setUpperRightY(params[1]); formrect.setLowerLeftX(params[2]); formrect.setLowerLeftY(params[3]); pdfStructure.setFormaterRectangle(formrect); logger.info("Formater rectangle has been created"); } public void createHolderFormStream(PDDocument template) { PDStream holderForm = new PDStream(template); pdfStructure.setHolderFormStream(holderForm); logger.info("Holder form Stream has been created"); } public void createHolderFormResources() { PDResources holderFormResources = new PDResources(); pdfStructure.setHolderFormResources(holderFormResources); logger.info("Holder form resources have been created"); } public void createHolderForm(PDResources holderFormResources, PDStream holderFormStream, PDRectangle formrect) { PDXObjectForm holderForm = new PDXObjectForm(holderFormStream); holderForm.setResources(holderFormResources); holderForm.setBBox(formrect); holderForm.setFormType(1); pdfStructure.setHolderForm(holderForm); logger.info("Holder form has been created"); } public void createAppearanceDictionary(PDXObjectForm holderForml, PDSignatureField signatureField) throws IOException { PDAppearanceDictionary appearance = new PDAppearanceDictionary(); appearance.getCOSObject().setDirect(true); PDAppearanceStream appearanceStream = new PDAppearanceStream(holderForml.getCOSStream()); appearance.setNormalAppearance(appearanceStream); signatureField.getWidget().setAppearance(appearance); pdfStructure.setAppearanceDictionary(appearance); logger.info("PDF appereance Dictionary has been created"); } public void createInnerFormStream(PDDocument template) { PDStream innterFormStream = new PDStream(template); pdfStructure.setInnterFormStream(innterFormStream); logger.info("Strean of another form (inner form - it would be inside holder form) has been created"); } public void createInnerFormResource() { PDResources innerFormResources = new PDResources(); pdfStructure.setInnerFormResources(innerFormResources); logger.info("Resources of another form (inner form - it would be inside holder form) have been created"); } public void createInnerForm(PDResources innerFormResources, PDStream innerFormStream, PDRectangle formrect) { PDXObjectForm innerForm = new PDXObjectForm(innerFormStream); innerForm.setResources(innerFormResources); innerForm.setBBox(formrect); innerForm.setFormType(1); pdfStructure.setInnerForm(innerForm); logger.info("Another form (inner form - it would be inside holder form) have been created"); } public void insertInnerFormToHolerResources(PDXObjectForm innerForm, PDResources holderFormResources) { String name = holderFormResources.addXObject(innerForm, "FRM"); pdfStructure.setInnerFormName(name); logger.info("Alerady inserted inner form inside holder form"); } public void createImageFormStream(PDDocument template) { PDStream imageFormStream = new PDStream(template); pdfStructure.setImageFormStream(imageFormStream); logger.info("Created image form Stream"); } public void createImageFormResources() { PDResources imageFormResources = new PDResources(); pdfStructure.setImageFormResources(imageFormResources); logger.info("Created image form Resources"); } public void createImageForm(PDResources imageFormResources, PDResources innerFormResource, PDStream imageFormStream, PDRectangle formrect, AffineTransform affineTransform, PDJpeg img) throws IOException { /* * if you need text on the visible signature * * PDFont font = PDTrueTypeFont.loadTTF(this.pdfStructure.getTemplate(), new File("D:\\arial.ttf")); * font.setFontEncoding(new WinAnsiEncoding()); * * Map fonts = new HashMap(); fonts.put("arial", font); */ PDXObjectForm imageForm = new PDXObjectForm(imageFormStream); imageForm.setBBox(formrect); imageForm.setMatrix(affineTransform); imageForm.setResources(imageFormResources); imageForm.setFormType(1); /* * imageForm.getResources().addFont(font); * imageForm.getResources().setFonts(fonts); */ imageFormResources.getCOSObject().setDirect(true); String imageFormName = innerFormResource.addXObject(imageForm, "n"); String imageName = imageFormResources.addXObject(img, "img"); this.pdfStructure.setImageForm(imageForm); this.pdfStructure.setImageFormName(imageFormName); this.pdfStructure.setImageName(imageName); logger.info("Created image form"); } public void injectProcSetArray(PDXObjectForm innerForm, PDPage page, PDResources innerFormResources, PDResources imageFormResources, PDResources holderFormResources, COSArray procSet) { innerForm.getResources().getCOSDictionary().setItem(COSName.PROC_SET, procSet); // page.getCOSDictionary().setItem(COSName.PROC_SET, procSet); innerFormResources.getCOSDictionary().setItem(COSName.PROC_SET, procSet); imageFormResources.getCOSDictionary().setItem(COSName.PROC_SET, procSet); holderFormResources.getCOSDictionary().setItem(COSName.PROC_SET, procSet); logger.info("inserted ProcSet to PDF"); } public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, PDStream imageFormStream, String imageObjectName, String imageName, String innerFormName, PDVisibleSignDesigner properties) throws IOException { // 100 means that document width is 100% via the rectangle. if rectangle // is 500px, images 100% is 500px. // String imgFormComment = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" + // imageName + " Do Q\n" + builder.toString(); String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName + " Do Q\n"; String holderFormComment = "q 1 0 0 1 0 0 cm /" + innerFormName + " Do Q \n"; String innerFormComment = "q 1 0 0 1 0 0 cm /" + imageObjectName + " Do Q\n"; appendRawCommands(pdfStructure.getHolderFormStream().createOutputStream(), holderFormComment); appendRawCommands(pdfStructure.getInnterFormStream().createOutputStream(), innerFormComment); appendRawCommands(pdfStructure.getImageFormStream().createOutputStream(), imgFormComment); logger.info("Injected apereance stream to pdf"); } public void appendRawCommands(OutputStream os, String commands) throws IOException { os.write(commands.getBytes("UTF-8")); os.close(); } public void createVisualSignature(PDDocument template) { this.pdfStructure.setVisualSignature(template.getDocument()); logger.info("Visible signature has been created"); } public void createWidgetDictionary(PDSignatureField signatureField, PDResources holderFormResources) throws IOException { COSDictionary widgetDict = signatureField.getWidget().getDictionary(); widgetDict.setNeedToBeUpdate(true); widgetDict.setItem(COSName.DR, holderFormResources.getCOSObject()); pdfStructure.setWidgetDictionary(widgetDict); logger.info("WidgetDictionary has been crated"); } public void closeTemplate(PDDocument template) throws IOException { template.close(); this.pdfStructure.getTemplate().close(); } } ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/pa0000644000000000000000000000177112645757432032277 0ustar rootroot This is the visual signature part that help creating the visual representation for the digital signature. ././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PD0000644000000000000000000003642412645757432032205 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.geom.AffineTransform; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.pdfwriter.COSWriter; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** * Structure of PDF document with visible signature * * @author vakhtang koroghlishvili (gogebashvili) * */ public class PDFTemplateStructure { private PDPage page; private PDDocument template; private PDAcroForm acroForm; private PDSignatureField signatureField; private PDSignature pdSignature; private COSDictionary acroFormDictionary; private PDRectangle singatureRectangle; private AffineTransform affineTransform; private COSArray procSet; private PDJpeg jpedImage; private PDRectangle formaterRectangle; private PDStream holderFormStream; private PDResources holderFormResources; private PDXObjectForm holderForm; private PDAppearanceDictionary appearanceDictionary; private PDStream innterFormStream; private PDResources innerFormResources; private PDXObjectForm innerForm; private PDStream imageFormStream; private PDResources imageFormResources; private List acroFormFields; private String innerFormName; private String imageFormName; private String imageName; private COSDocument visualSignature; private PDXObjectForm imageForm; private COSDictionary widgetDictionary; /** * Returns document page. * @return the document page. */ public PDPage getPage() { return page; } /** * Sets document page * @param page */ public void setPage(PDPage page) { this.page = page; } /** * Gets PDDocument template. * This represents a digital signature * that can be attached to a document * @return the template to be used. */ public PDDocument getTemplate() { return template; } /** * Wets PDDocument template. * This represents a digital signature * that can be attached to a document * @param template */ public void setTemplate(PDDocument template) { this.template = template; } /** * Gets Acroform * @return the documents AcroForm. */ public PDAcroForm getAcroForm() { return acroForm; } /** * Sets Acroform * @param acroForm */ public void setAcroForm(PDAcroForm acroForm) { this.acroForm = acroForm; } /** * Gets Signature field * @return the signature field to be used. */ public PDSignatureField getSignatureField() { return signatureField; } /** * Sets signature field * @param signatureField */ public void setSignatureField(PDSignatureField signatureField) { this.signatureField = signatureField; } /** * Gets PDSignature * @return the signature object. */ public PDSignature getPdSignature() { return pdSignature; } /** * Sets PDSignature * @param pdSignature */ public void setPdSignature(PDSignature pdSignature) { this.pdSignature = pdSignature; } /** * Gets Dictionary of AcroForm. Thats /DR * entry in the AcroForm * @return the AcroForms dictionary object. */ public COSDictionary getAcroFormDictionary() { return acroFormDictionary; } /** * Acroform have its Dictionary, so we here set * the Dictionary which is in this location: * AcroForm/DR * @param acroFormDictionary */ public void setAcroFormDictionary(COSDictionary acroFormDictionary) { this.acroFormDictionary = acroFormDictionary; } /** * Gets SignatureRectangle * @return the signatures rectangle. */ public PDRectangle getSingatureRectangle() { return singatureRectangle; } /** * Sets SignatureRectangle * @param singatureRectangle */ public void setSignatureRectangle(PDRectangle singatureRectangle) { this.singatureRectangle = singatureRectangle; } /** * Gets AffineTransform * @return the AffineTransform */ public AffineTransform getAffineTransform() { return affineTransform; } /** * Sets AffineTransform * @param affineTransform */ public void setAffineTransform(AffineTransform affineTransform) { this.affineTransform = affineTransform; } /** * Gets ProcSet Array * @return the proc set array */ public COSArray getProcSet() { return procSet; } /** * Sets ProcSet Array * @param procSet */ public void setProcSet(COSArray procSet) { this.procSet = procSet; } /** * Gets the image of visible signature * @return the image used for a visible signature. */ public PDJpeg getJpedImage() { return jpedImage; } /** * Sets the image of visible signature * @param jpedImage */ public void setJpedImage(PDJpeg jpedImage) { this.jpedImage = jpedImage; } /** * Gets formatter rectangle * @return the rectangle used by the formatter. */ public PDRectangle getFormaterRectangle() { return formaterRectangle; } /** * Sets formatter rectangle * @param formaterRectangle */ public void setFormaterRectangle(PDRectangle formaterRectangle) { this.formaterRectangle = formaterRectangle; } /** * Sets HolderFormStream * @return the form stream of the holder. */ public PDStream getHolderFormStream() { return holderFormStream; } /** * Sets stream of holder form Stream * @param holderFormStream */ public void setHolderFormStream(PDStream holderFormStream) { this.holderFormStream = holderFormStream; } /** * Gets Holder form. * That form is here AcroForm/DR/XObject/{holder form name} * By default, name stars with FRM. We also add number of form * to the name. * @return the holder form */ public PDXObjectForm getHolderForm() { return holderForm; } /** * In the structure, form will be contained by XObject in the AcroForm/DR/ * @param holderForm */ public void setHolderForm(PDXObjectForm holderForm) { this.holderForm = holderForm; } /** * Gets Holder form resources * @return the holder forms resources. */ public PDResources getHolderFormResources() { return holderFormResources; } /** * Sets holder form resources * @param holderFormResources */ public void setHolderFormResources(PDResources holderFormResources) { this.holderFormResources = holderFormResources; } /** * Gets AppearanceDictionary * That is /AP entry the appearance dictionary. * @return the appearance directory. */ public PDAppearanceDictionary getAppearanceDictionary() { return appearanceDictionary; } /** * Sets AppearanceDictionary * That is /AP entry the appearance dictionary. * @param appearanceDictionary */ public void setAppearanceDictionary(PDAppearanceDictionary appearanceDictionary) { this.appearanceDictionary = appearanceDictionary; } /** * Gets Inner form Stream. * @return the inner form's stream. */ public PDStream getInnterFormStream() { return innterFormStream; } /** * Sets inner form stream * @param innterFormStream */ public void setInnterFormStream(PDStream innterFormStream) { this.innterFormStream = innterFormStream; } /** * Gets inner form Resource * @return the inner form's resources. */ public PDResources getInnerFormResources() { return innerFormResources; } /** * Sets inner form resource * @param innerFormResources */ public void setInnerFormResources(PDResources innerFormResources) { this.innerFormResources = innerFormResources; } /** * Gets inner form that is in this location: * AcroForm/DR/XObject/{holder form name}/Resources/XObject/{inner name} * By default inner form name starts with "n". Then we add number of form * to the name. * @return the inner form. */ public PDXObjectForm getInnerForm() { return innerForm; } /** * sets inner form to this location: * AcroForm/DR/XObject/{holder form name}/Resources/XObject/{destination} * @param innerForm */ public void setInnerForm(PDXObjectForm innerForm) { this.innerForm = innerForm; } /** * Gets name of inner form * @return the inner form's name. */ public String getInnerFormName() { return innerFormName; } /** * Sets inner form name * @param innerFormName */ public void setInnerFormName(String innerFormName) { this.innerFormName = innerFormName; } /** * Gets Image form stream * @return the inner form's stream. */ public PDStream getImageFormStream() { return imageFormStream; } /** * Sets image form stream * @param imageFormStream */ public void setImageFormStream(PDStream imageFormStream) { this.imageFormStream = imageFormStream; } /** * Gets image form resources * @return the image form's resources. */ public PDResources getImageFormResources() { return imageFormResources; } /** * Sets image form resource * @param imageFormResources */ public void setImageFormResources(PDResources imageFormResources) { this.imageFormResources = imageFormResources; } /** * Gets Image form. Image form is in this structure: * /AcroForm/DR/{holder form}/Resources/XObject /{inner form} * /Resources/XObject/{image form name}. * @return the image form. */ public PDXObjectForm getImageForm() { return imageForm; } /** * Sets Image form. Image form will be in this structure: * /AcroForm/DR/{holder form}/Resources/XObject /{inner form} * /Resources/XObject/{image form name}. By default we start * image form name with "img". Then we add number of image * form to the form name. * Sets image form * @param imageForm */ public void setImageForm(PDXObjectForm imageForm) { this.imageForm = imageForm; } /** * Gets image form name * @return the image form's name. */ public String getImageFormName() { return imageFormName; } /** * Sets image form name * @param imageFormName */ public void setImageFormName(String imageFormName) { this.imageFormName = imageFormName; } /** * Gets visible signature image name * @return the visible signature image's name. */ public String getImageName() { return imageName; } /** * Sets visible signature image name * @param imageName */ public void setImageName(String imageName) { this.imageName = imageName; } /** * Gets COSDocument of visible Signature. * @see org.apache.pdfbox.cos.COSDocument * @return the document representing the visual signature. */ public COSDocument getVisualSignature() { return visualSignature; } /** * * Sets COSDocument of visible Signature. * @see org.apache.pdfbox.cos.COSDocument * @param visualSignature */ public void setVisualSignature(COSDocument visualSignature) { this.visualSignature = visualSignature; } /** * Gets acroFormFields * @return the fields within the AcroForm. */ public List getAcroFormFields() { return acroFormFields; } /** * Sets acroFormFields * @param acroFormFields */ public void setAcroFormFields(List acroFormFields) { this.acroFormFields = acroFormFields; } /** * Gets AP of the created template * @return the apperance stream of the created template. * @throws IOException * @throws COSVisitorException */ public ByteArrayInputStream getTemplateAppearanceStream() throws IOException, COSVisitorException { COSDocument visualSignature = getVisualSignature(); ByteArrayOutputStream memoryOut = new ByteArrayOutputStream(); COSWriter memoryWriter = new COSWriter(memoryOut); memoryWriter.write(visualSignature); ByteArrayInputStream input = new ByteArrayInputStream(memoryOut.toByteArray()); getTemplate().close(); return input; } /** * Gets Widget Dictionary. * {@link org.apache.pdfbox.pdmodel.interactive.form.PDField} * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#getWidget() * @return the dictionary representing the widget. */ public COSDictionary getWidgetDictionary() { return widgetDictionary; } /** * Sets Widget Dictionary. * {@link org.apache.pdfbox.pdmodel.interactive.form.PDField} * @see org.apache.pdfbox.pdmodel.interactive.form.PDField#getWidget() * @param widgetDictionary */ public void setWidgetDictionary(COSDictionary widgetDictionary) { this.widgetDictionary = widgetDictionary; } } ././@LongLink0000644000000000000000000000017500000000000011606 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PD0000644000000000000000000002753012645757432032203 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import javax.imageio.ImageIO; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * * That class is in order to build your * visible signature design. Because of * this is builder, instead of setParam() * we use param() methods. * @author vakhtang koroghlishvili (gogebashvili) */ public class PDVisibleSignDesigner { private Float sigImgWidth; private Float sigImgHeight; private float xAxis; private float yAxis; private float pageHeight; private float pageWidth; private InputStream imgageStream; private String signatureFieldName = "sig"; // default private byte[] formaterRectangleParams = { 0, 0, 100, 50 }; // default private byte[] AffineTransformParams = { 1, 0, 0, 1, 0, 0 }; // default private float imageSizeInPercents; private PDDocument document = null; /** * * @param originalDocumenStream * @param imageStream * @param page the 1-based page number for which the page size should be calculated. * @throws IOException */ public PDVisibleSignDesigner(InputStream originalDocumenStream, InputStream imageStream, int page) throws IOException { signatureImageStream(imageStream); document = PDDocument.load(originalDocumenStream); calculatePageSize(document, page); } /** * * @param documentPath - path of your pdf document * @param imageStream - stream of image * @param page the 1-based page number for which the page size should be calculated. * @throws IOException */ public PDVisibleSignDesigner(String documentPath, InputStream imageStream, int page) throws IOException { // set visible singature image Input stream signatureImageStream(imageStream); // create PD document document = PDDocument.load(documentPath); // calculate height an width of document calculatePageSize(document, page); document.close(); } /** * * @param doc - Already created PDDocument of your PDF document * @param imageStream * @param page the 1-based page number for which the page size should be calculated. * @throws IOException - If we can't read, flush, or can't close stream */ public PDVisibleSignDesigner(PDDocument doc, InputStream imageStream, int page) throws IOException { signatureImageStream(imageStream); calculatePageSize(doc, page); } /** * Each page of document can be different sizes. This method calculates the page size based on * the page media box. * * @param document * @param page the 1-based page number for which the page size should be calculated. */ private void calculatePageSize(PDDocument document, int page) { if (page < 1) { throw new IllegalArgumentException("First page of pdf is 1, not " + page); } List pages = document.getDocumentCatalog().getAllPages(); PDPage firstPage =(PDPage) pages.get(page - 1); PDRectangle mediaBox = firstPage.findMediaBox(); this.pageHeight(mediaBox.getHeight()); this.pageWidth = mediaBox.getWidth(); float x = this.pageWidth; float y = 0; this.pageWidth = this.pageWidth + y; float tPercent = (100 * y / (x + y)); this.imageSizeInPercents = 100 - tPercent; } /** * * @param path of image location * @return image Stream * @throws IOException */ public PDVisibleSignDesigner signatureImage(String path) throws IOException { InputStream fin = new FileInputStream(path); return signatureImageStream(fin); } /** * zoom signature image with some percent. * * @param percent the percentage for zooming the image. * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner zoom(float percent) { sigImgHeight = sigImgHeight + (sigImgHeight * percent) / 100; sigImgWidth = sigImgWidth + (sigImgWidth * percent) / 100; return this; } /** * * @param x the x coordinate * @param y the y coordinate * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner coordinates(float x, float y) { xAxis(x); yAxis(y); return this; } /** * * @return xAxis - gets x coordinates */ public float getxAxis() { return xAxis; } /** * * @param xAxis - x coordinate * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner xAxis(float xAxis) { this.xAxis = xAxis; return this; } /** * * @return yAxis */ public float getyAxis() { return yAxis; } /** * * @param yAxis * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner yAxis(float yAxis) { this.yAxis = yAxis; return this; } /** * * @return signature image width */ public float getWidth() { return sigImgWidth; } /** * * @param signatureImgWidth the signature image width * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner width(float signatureImgWidth) { this.sigImgWidth = signatureImgWidth; return this; } /** * * @return signature image height */ public float getHeight() { return sigImgHeight; } /** * * @param signatureImgHeight the signature image Height * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner height(float signatureImgHeight) { this.sigImgHeight = signatureImgHeight; return this; } /** * * @return template height */ protected float getTemplateHeight() { return getPageHeight(); } /** * * @param templateHeight * @return Visible Signature Configuration Object */ private PDVisibleSignDesigner pageHeight(float templateHeight) { this.pageHeight = templateHeight; return this; } /** * * @return signature field name */ public String getSignatureFieldName() { return signatureFieldName; } /** * * @param signatureFieldName * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner signatureFieldName(String signatureFieldName) { this.signatureFieldName = signatureFieldName; return this; } /** * * @return image Stream */ public InputStream getImageStream() { return imgageStream; } /** * * @param imgageStream- stream of your visible signature image * @return Visible Signature Configuration Object * @throws IOException - If we can't read, flush, or close stream of image */ private PDVisibleSignDesigner signatureImageStream(InputStream imageStream) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = imageStream.read(buffer)) > -1) { baos.write(buffer, 0, len); } baos.flush(); baos.close(); byte[] byteArray = baos.toByteArray(); byte[] byteArraySecond = new byte[byteArray.length]; System.arraycopy(byteArray, 0, byteArraySecond, 0, byteArray.length); InputStream inputForBufferedImage = new ByteArrayInputStream(byteArray); InputStream revertInputStream = new ByteArrayInputStream(byteArraySecond); if (sigImgHeight == null || sigImgWidth == null) { calculateImageSize(inputForBufferedImage); } this.imgageStream = revertInputStream; return this; } /** * calculates image width and height. supported formats: all * * @param fis - input stream of image * @throws IOException - if can't read input stream */ private void calculateImageSize(InputStream fis) throws IOException { BufferedImage bimg = ImageIO.read(fis); int width = bimg.getWidth(); int height = bimg.getHeight(); sigImgHeight = (float) height; sigImgWidth = (float) width; } /** * * @return Affine Transform parameters of for PDF Matrix */ public byte[] getAffineTransformParams() { return AffineTransformParams; } /** * * @param affineTransformParams * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner affineTransformParams(byte[] affineTransformParams) { AffineTransformParams = affineTransformParams; return this; } /** * * @return formatter PDRectanle parameters */ public byte[] getFormaterRectangleParams() { return formaterRectangleParams; } /** * sets formatter PDRectangle; * * @param formaterRectangleParams * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner formaterRectangleParams(byte[] formaterRectangleParams) { this.formaterRectangleParams = formaterRectangleParams; return this; } /** * * @return page width */ public float getPageWidth() { return pageWidth; } /** * * @param pageWidth the pageWidth * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner pageWidth(float pageWidth) { this.pageWidth = pageWidth; return this; } /** * * @return page height */ public float getPageHeight() { return pageHeight; } /** * get image size in percents * @return image size in percent. */ public float getImageSizeInPercents() { return imageSizeInPercents; } /** * * @param imageSizeInPercents */ public void imageSizeInPercents(float imageSizeInPercents) { this.imageSizeInPercents = imageSizeInPercents; } /** * returns visible signature text * @return visible signature text. */ public String getSignatureText() { throw new UnsupportedOperationException("That method is not yet implemented"); } /** * * @param signatureText - adds the text on visible signature * @return Visible Signature Configuration Object */ public PDVisibleSignDesigner signatureText(String signatureText) { throw new UnsupportedOperationException("That method is not yet implemented"); } } ././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PD0000644000000000000000000001607312645757432032203 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.geom.AffineTransform; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** * Using that class, we build pdf template * @author vakhtang koroghlishvili (gogebashvili) */ public class PDFTemplateCreator { PDFTemplateBuilder pdfBuilder; private static final Log logger = LogFactory.getLog(PDFTemplateCreator.class); /** * sets PDFBuilder * * @param bookBuilder */ public PDFTemplateCreator(PDFTemplateBuilder bookBuilder) { this.pdfBuilder = bookBuilder; } /** * that method returns object of PDFStructur * * @return PDFStructure */ public PDFTemplateStructure getPdfStructure() { return this.pdfBuilder.getStructure(); } /** * this method builds pdf step by step, and finally it returns stream of visible signature * @param properties * @return InputStream * @throws IOException * @throws COSVisitorException */ public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException { logger.info("pdf building has been started"); PDFTemplateStructure pdfStructure = pdfBuilder.getStructure(); // we create array of [Text, ImageB, ImageC, ImageI] this.pdfBuilder.createProcSetArray(); //create page this.pdfBuilder.createPage(properties); PDPage page = pdfStructure.getPage(); //create template this.pdfBuilder.createTemplate(page); PDDocument template = pdfStructure.getTemplate(); //create /AcroForm this.pdfBuilder.createAcroForm(template); PDAcroForm acroForm = pdfStructure.getAcroForm(); // AcroForm contains singature fields this.pdfBuilder.createSignatureField(acroForm); PDSignatureField pdSignatureField = pdfStructure.getSignatureField(); // create signature this.pdfBuilder.createSignature(pdSignatureField, page, properties.getSignatureFieldName()); // that is /AcroForm/DR entry this.pdfBuilder.createAcroFormDictionary(acroForm, pdSignatureField); // create AffineTransform this.pdfBuilder.createAffineTransform(properties.getAffineTransformParams()); AffineTransform transform = pdfStructure.getAffineTransform(); // rectangle, formatter, image. /AcroForm/DR/XObject contains that form this.pdfBuilder.createSignatureRectangle(pdSignatureField, properties); this.pdfBuilder.createFormaterRectangle(properties.getFormaterRectangleParams()); PDRectangle formater = pdfStructure.getFormaterRectangle(); this.pdfBuilder.createSignatureImage(template, properties.getImageStream()); // create form stream, form and resource. this.pdfBuilder.createHolderFormStream(template); PDStream holderFormStream = pdfStructure.getHolderFormStream(); this.pdfBuilder.createHolderFormResources(); PDResources holderFormResources = pdfStructure.getHolderFormResources(); this.pdfBuilder.createHolderForm(holderFormResources, holderFormStream, formater); // that is /AP entry the appearance dictionary. this.pdfBuilder.createAppearanceDictionary(pdfStructure.getHolderForm(), pdSignatureField); // inner formstream, form and resource (hlder form containts inner form) this.pdfBuilder.createInnerFormStream(template); this.pdfBuilder.createInnerFormResource(); PDResources innerFormResource = pdfStructure.getInnerFormResources(); this.pdfBuilder.createInnerForm(innerFormResource, pdfStructure.getInnterFormStream(), formater); PDXObjectForm innerForm = pdfStructure.getInnerForm(); // inner form must be in the holder form as we wrote this.pdfBuilder.insertInnerFormToHolerResources(innerForm, holderFormResources); // Image form is in this structure: /AcroForm/DR/FRM0/Resources/XObject/n0 this.pdfBuilder.createImageFormStream(template); PDStream imageFormStream = pdfStructure.getImageFormStream(); this.pdfBuilder.createImageFormResources(); PDResources imageFormResources = pdfStructure.getImageFormResources(); this.pdfBuilder.createImageForm(imageFormResources, innerFormResource, imageFormStream, formater, transform, pdfStructure.getJpedImage()); // now inject procSetArray this.pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, imageFormResources, holderFormResources, pdfStructure.getProcSet()); String imgFormName = pdfStructure.getImageFormName(); String imgName = pdfStructure.getImageName(); String innerFormName = pdfStructure.getInnerFormName(); // now create Streams of AP this.pdfBuilder.injectAppearanceStreams(holderFormStream, imageFormStream, imageFormStream, imgFormName, imgName, innerFormName, properties); this.pdfBuilder.createVisualSignature(template); this.pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources); ByteArrayInputStream in = null; try { in = pdfStructure.getTemplateAppearanceStream(); } catch (COSVisitorException e) { logger.error("COSVisitorException: can't get apereance stream ", e); } logger.info("stream returning started, size= " + in.available()); // we must close the document template.close(); // return result of the stream return in; } } ././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigProperties.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PD0000644000000000000000000001244112645757432032176 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.io.IOException; import java.io.InputStream; /** * This builder class is in order to create visible signature properties. * * @author vakhtang koroghlishvili (gogebashvili) * */ public class PDVisibleSigProperties { private String signerName; private String signerLocation; private String signatureReason; private boolean visualSignEnabled; private int page; private int preferredSize; private InputStream visibleSignature; private PDVisibleSignDesigner pdVisibleSignature; /** * start building of visible signature * * @throws IOException */ public void buildSignature() throws IOException { PDFTemplateBuilder builder = new PDVisibleSigBuilder(); PDFTemplateCreator creator = new PDFTemplateCreator(builder); setVisibleSignature(creator.buildPDF(getPdVisibleSignature())); } /** * * @return - signer name */ public String getSignerName() { return signerName; } /** * Sets signer name * @param signerName * @return the visible signature properties. */ public PDVisibleSigProperties signerName(String signerName) { this.signerName = signerName; return this; } /** * Gets signer locations * @return - location */ public String getSignerLocation() { return signerLocation; } /** * Sets location * @param signerLocation * @return the visible signature properties. */ public PDVisibleSigProperties signerLocation(String signerLocation) { this.signerLocation = signerLocation; return this; } /** * gets reason of signing * @return the reason of signing */ public String getSignatureReason() { return signatureReason; } /** * sets reason of signing * @param signatureReason * @return the visible signature properties. */ public PDVisibleSigProperties signatureReason(String signatureReason) { this.signatureReason = signatureReason; return this; } /** * returns your page * @return the page number. */ public int getPage() { return page; } /** * sets page number * @param page * @return the visible signature properties. */ public PDVisibleSigProperties page(int page) { this.page = page; return this; } /** * gets our preferred size * @return the signature's preferred size. */ public int getPreferredSize() { return preferredSize; } /** * sets our preferred size * @param preferredSize * @return the visible signature properties. */ public PDVisibleSigProperties preferredSize(int preferredSize) { this.preferredSize = preferredSize; return this; } /** * checks if we need to add visible signature * @return state if visible signature is needed. */ public boolean isVisualSignEnabled() { return visualSignEnabled; } /** * sets visible signature to be added or not * @param visualSignEnabled * @return the visible signature properties. */ public PDVisibleSigProperties visualSignEnabled(boolean visualSignEnabled) { this.visualSignEnabled = visualSignEnabled; return this; } /** * this method gets visible signature configuration object * @return the visible signature configuration. */ public PDVisibleSignDesigner getPdVisibleSignature() { return pdVisibleSignature; } /** * Sets visible signature configuration Object * @param pdVisibleSignature * @return the visible signature properties. */ public PDVisibleSigProperties setPdVisibleSignature(PDVisibleSignDesigner pdVisibleSignature) { this.pdVisibleSignature = pdVisibleSignature; return this; } /** * returns visible signature configuration object * @return the input stream representing the visible signature. */ public InputStream getVisibleSignature() { return visibleSignature; } /** * sets configuration object of visible signature * @param visibleSignature */ public void setVisibleSignature(InputStream visibleSignature) { this.visibleSignature = visibleSignature; } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/package.ht0000644000000000000000000000175012645757432032244 0ustar rootroot The digitial signature library will manage signatures that are stored in the PDF document. ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignatur0000644000000000000000000002504412645757432032261 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Calendar; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdfwriter.COSFilterInputStream; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This represents a digital signature that can be attached to a document. * * @author Ben Litchfield * @author Thomas Chojecki * @version $Revision: 1.2 $ */ public class PDSignature implements COSObjectable { private COSDictionary dictionary; /** * A signature filter value. */ public static final COSName FILTER_ADOBE_PPKLITE = COSName.ADOBE_PPKLITE; /** * A signature filter value. */ public static final COSName FILTER_ENTRUST_PPKEF = COSName.ENTRUST_PPKEF; /** * A signature filter value. */ public static final COSName FILTER_CICI_SIGNIT = COSName.CICI_SIGNIT; /** * A signature filter value. */ public static final COSName FILTER_VERISIGN_PPKVS = COSName.VERISIGN_PPKVS; /** * A signature subfilter value. */ public static final COSName SUBFILTER_ADBE_X509_RSA_SHA1 = COSName.ADBE_X509_RSA_SHA1; /** * A signature subfilter value. */ public static final COSName SUBFILTER_ADBE_PKCS7_DETACHED = COSName.ADBE_PKCS7_DETACHED; /** * A signature subfilter value. */ public static final COSName SUBFILTER_ETSI_CADES_DETACHED = COSName.getPDFName("ETSI.CAdES.detached"); /** * A signature subfilter value. */ public static final COSName SUBFILTER_ADBE_PKCS7_SHA1 = COSName.ADBE_PKCS7_SHA1; /** * Default constructor. */ public PDSignature() { dictionary = new COSDictionary(); dictionary.setItem(COSName.TYPE, COSName.SIG); } /** * Constructor. * * @param dict The signature dictionary. */ public PDSignature(COSDictionary dict) { dictionary = dict; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return getDictionary(); } /** * Convert this standard java object to a COS dictionary. * * @return The COS dictionary that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * Set the dictionary type. * * @param type is the dictionary type. */ public void setType(COSName type) { dictionary.setItem(COSName.TYPE, type); } /** * Set the filter. * * @param filter the filter to be used */ public void setFilter(COSName filter) { dictionary.setItem(COSName.FILTER, filter); } /** * Set a subfilter that specify the signature that should be used. * * @param subfilter the subfilter that shall be used. */ public void setSubFilter(COSName subfilter) { dictionary.setItem(COSName.SUBFILTER, subfilter); } /** * Sets the name. * @param name the name to be used */ public void setName(String name) { dictionary.setString(COSName.NAME, name); } /** * Sets the location. * @param location the location to be used */ public void setLocation(String location) { dictionary.setString(COSName.LOCATION, location); } /** * Sets the reason. * * @param reason the reason to be used */ public void setReason(String reason) { dictionary.setString(COSName.REASON, reason); } /** * Sets the contact info. * * @param contactInfo the contact info to be used */ public void setContactInfo(String contactInfo) { dictionary.setString(COSName.CONTACT_INFO, contactInfo); } /** * Set the sign date. * * @param cal the date to be used as sign date */ public void setSignDate(Calendar cal) { dictionary.setDate(COSName.M, cal); } /** * Returns the filter. * @return the filter */ public String getFilter() { return dictionary.getNameAsString(COSName.FILTER); } /** * Returns the subfilter. * * @return the subfilter */ public String getSubFilter() { return dictionary.getNameAsString(COSName.SUBFILTER); } /** * Returns the name. * * @return the name */ public String getName() { return dictionary.getString(COSName.NAME); } /** * Returns the location. * * @return the location */ public String getLocation() { return dictionary.getString(COSName.LOCATION); } /** * Returns the reason. * * @return the reason */ public String getReason() { return dictionary.getString(COSName.REASON); } /** * Returns the contact info. * * @return teh contact info */ public String getContactInfo() { return dictionary.getString(COSName.CONTACT_INFO); } /** * Returns the sign date. * * @return the sign date */ public Calendar getSignDate() { try { return dictionary.getDate(COSName.M); } catch (IOException e) { return null; } } /** * Sets the byte range. * * @param range the byte range to be used */ public void setByteRange(int[] range) { if (range.length!=4) { return; } COSArray ary = new COSArray(); for ( int i : range ) { ary.add(COSInteger.get(i)); } dictionary.setItem(COSName.BYTERANGE, ary); } /** * Read out the byterange from the file. * * @return a integer array with the byterange */ public int[] getByteRange() { COSArray byteRange = (COSArray)dictionary.getDictionaryObject(COSName.BYTERANGE); int[] ary = new int[byteRange.size()]; for (int i = 0; i and ) else if(buffer[c-1]==0x3E || buffer[c-1]==0x29) { byteOS.write(buffer, 0, c-1); } else { byteOS.write(buffer, 0, c); } } fis.close(); return COSString.createFromHexString(byteOS.toString("ISO-8859-1")).getBytes(); } /** * Sets the contents. * * @param bytes contents to be used */ public void setContents(byte[] bytes) { COSString string = new COSString(bytes); string.setForceHexForm(true); dictionary.setItem(COSName.CONTENTS, string); } /** * Will return the signed content of the document. * * @param pdfFile The signed pdf file as InputStream * @return a byte array containing only the signed part of the content * @throws IOException if the pdfFile can't be read */ public byte[] getSignedContent(InputStream pdfFile) throws IOException { COSFilterInputStream fis=null; try { fis = new COSFilterInputStream(pdfFile,getByteRange()); return fis.toByteArray(); } finally { if (fis != null) { fis.close(); } } } /** * Will return the signed content of the document. * * @param pdfFile The signed pdf file as byte array * @return a byte array containing only the signed part of the content * @throws IOException if the pdfFile can't be read */ public byte[] getSignedContent(byte[] pdfFile) throws IOException { COSFilterInputStream fis=null; try { fis = new COSFilterInputStream(pdfFile,getByteRange()); return fis.toByteArray(); } finally { if (fis != null) { fis.close(); } } } /** * PDF signature build dictionary. Provides informations about the signature handler. * * @return the pdf signature build dictionary. */ public PDPropBuild getPropBuild() { PDPropBuild propBuild = null; COSDictionary propBuildDic = (COSDictionary)dictionary.getDictionaryObject(COSName.PROP_BUILD); if (propBuildDic != null) { propBuild = new PDPropBuild(propBuildDic); } return propBuild; } /** * PDF signature build dictionary. Provides informations about the signature handler. * * @param propBuild the prop build */ public void setPropBuild(PDPropBuild propBuild) { dictionary.setItem(COSName.PROP_BUILD, propBuild); } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureO0000644000000000000000000000624612645757432032324 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import java.io.IOException; import java.io.InputStream; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.pdfparser.VisualSignatureParser; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties; public class SignatureOptions { private COSDocument visualSignature; private int preferedSignatureSize; private int pageNo; /** * Set the 1-based page number. * * @param pageNo the page number * */ public void setPage(int pageNo) { this.pageNo = pageNo; } /** * Get the 1-based page number. * * @return the page number */ public int getPage() { return pageNo; } /** * Reads the visual signature from the given input stream. * * @param is the input stream containing the visual signature * * @throws IOException when something went wrong during parsing */ public void setVisualSignature(InputStream is) throws IOException { VisualSignatureParser visParser = new VisualSignatureParser(is); visParser.parse(); visualSignature = visParser.getDocument(); } /** * Reads the visual signature from the given visual signature properties * * @param visSignatureProperties the PDVisibleSigProperties object containing the visual signature * * @throws IOException when something went wrong during parsing * * @since 1.8.3 */ public void setVisualSignature(PDVisibleSigProperties visSignatureProperties) throws IOException { setVisualSignature(visSignatureProperties.getVisibleSignature()); } /** * Get the visual signature. * * @return the visual signature */ public COSDocument getVisualSignature() { return visualSignature; } /** * Get the preferred size of the signature. * * @return the preferred size */ public int getPreferedSignatureSize() { return preferedSignatureSize; } /** * Set the preferred size of the signature. * * @param size the size of the signature */ public void setPreferedSignatureSize(int size) { if (size > 0) { preferedSignatureSize = size; } } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSeedValue.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSeedValu0000644000000000000000000004355012645757432032177 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.util.BitFlagHelper; /** * This represents a pdf signature seed value dictionary. * * @author Thomas Chojecki * @version $Revision: 1.1 $ */ public class PDSeedValue implements COSObjectable { /** * A Ff flag. */ public static final int FLAG_FILTER = 1; /** * A Ff flag. */ public static final int FLAG_SUBFILTER = 1 << 1; /** * A Ff flag. */ public static final int FLAG_V = 1 << 2; /** * A Ff flag. */ public static final int FLAG_REASON = 1 << 3; /** * A Ff flag. */ public static final int FLAG_LEGAL_ATTESTATION = 1 << 4; /** * A Ff flag. */ public static final int FLAG_ADD_REV_INFO = 1 << 5; /** * A Ff flag. */ public static final int FLAG_DIGEST_METHOD = 1 << 6; private COSDictionary dictionary; /** * Default constructor. */ public PDSeedValue() { dictionary = new COSDictionary(); dictionary.setItem(COSName.TYPE, COSName.SV); dictionary.setDirect(true); // the specification claim to use direct objects } /** * Constructor. * * @param dict The signature dictionary. */ public PDSeedValue(COSDictionary dict) { dictionary = dict; dictionary.setDirect(true); // the specification claim to use direct objects } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return getDictionary(); } /** * Convert this standard java object to a COS dictionary. * * @return The COS dictionary that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * * @return true if the Filter is required */ public boolean isFilterRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_FILTER); } /** * set true if the filter shall be required. * * @param flag if true, the specified Filter shall be used when signing. */ public void setFilterRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_FILTER, flag); } /** * * @return true if the SubFilter is required */ public boolean isSubFilterRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_SUBFILTER); } /** * set true if the subfilter shall be required. * * @param flag if true, the first supported SubFilter in the array shall be used when signing. */ public void setSubFilterRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_SUBFILTER, flag); } /** * * @return true if the DigestMethod is required */ public boolean isDigestMethodRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_DIGEST_METHOD); } /** * set true if the DigestMethod shall be required. * * @param flag if true, one digest from the array shall be used. */ public void setDigestMethodRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_DIGEST_METHOD, flag); } /** * * @return true if the V entry is required */ public boolean isVRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_V); } /** * set true if the V entry shall be required. * * @param flag if true, the V entry shall be used. */ public void setVRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_V, flag); } /** * * @return true if the Reason is required */ public boolean isReasonRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_REASON); } /** * set true if the Reason shall be required. * * @param flag if true, the Reason entry shall be used. */ public void setReasonRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_REASON, flag); } /** * * @return true if the LegalAttestation is required */ public boolean isLegalAttestationRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_LEGAL_ATTESTATION); } /** * set true if the LegalAttestation shall be required. * * @param flag if true, the LegalAttestation entry shall be used. */ public void setLegalAttestationRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_LEGAL_ATTESTATION, flag); } /** * * @return true if the AddRevInfo is required */ public boolean isAddRevInfoRequired() { return BitFlagHelper.getFlag(getDictionary(), COSName.FF, FLAG_ADD_REV_INFO); } /** * set true if the AddRevInfo shall be required. * * @param flag if true, the AddRevInfo shall be used. */ public void setAddRevInfoRequired(boolean flag) { BitFlagHelper.setFlag(getDictionary(), COSName.FF, FLAG_ADD_REV_INFO, flag); } /** * If Filter is not null and the {@link #isFilterRequired()} indicates this entry is a * required constraint, then the signature handler specified by this entry shall be used when * signing; otherwise, signing shall not take place. If {@link #isFilterRequired()} indicates * that this is an optional constraint, this handler may be used if it is available. If it is * not available, a different handler may be used instead. * * @return the filter that shall be used by the signature handler */ public String getFilter() { return dictionary.getNameAsString(COSName.FILTER); } /** * (Optional) The signature handler that shall be used to sign the signature field. * * @param filter is the filter that shall be used by the signature handler */ public void setFilter(COSName filter) { dictionary.setItem(COSName.FILTER, filter); } /** * If SubFilter is not null and the {@link #isSubFilterRequired()} indicates this * entry is a required constraint, then the first matching encodings shall be used when * signing; otherwise, signing shall not take place. If {@link #isSubFilterRequired()} * indicates that this is an optional constraint, then the first matching encoding shall * be used if it is available. If it is not available, a different encoding may be used * instead. * * @return the subfilter that shall be used by the signature handler */ public List getSubFilter() { List retval = null; COSArray fields = (COSArray)dictionary.getDictionaryObject(COSName.SUBFILTER); if (fields != null) { List actuals = new ArrayList(); for ( int i = 0; i < fields.size(); i++ ) { String element = fields.getName(i); if (element != null) { actuals.add(element); } } retval = new COSArrayList(actuals, fields); } return retval; } /** * (Optional) An array of names indicating encodings to use when signing. The first name * in the array that matches an encoding supported by the signature handler shall be the * encoding that is actually used for signing. * * @param subfilter is the name that shall be used for encoding */ public void setSubFilter(List subfilter) { dictionary.setItem(COSName.SUBFILTER, COSArrayList.converterToCOSArray(subfilter)); } /** * An array of names indicating acceptable digest algorithms to use when * signing. The value shall be one of SHA1, SHA256, SHA384, * SHA512, RIPEMD160. The default value is implementation-specific. * * @return the digest method that shall be used by the signature handler */ public List getDigestMethod() { List retval = null; COSArray fields = (COSArray)dictionary.getDictionaryObject(COSName.DIGEST_METHOD); if (fields != null) { List actuals = new ArrayList(); for ( int i = 0; i < fields.size(); i++ ) { String element = fields.getName(i); if (element != null) { actuals.add(element); } } retval = new COSArrayList(actuals, fields); } return retval; } /** *

    (Optional, PDF 1.7) An array of names indicating acceptable digest * algorithms to use when signing. The value shall be one of SHA1, * SHA256, SHA384, SHA512, RIPEMD160. The default * value is implementation-specific.

    * *

    This property is only applicable if the digital credential signing contains RSA * public/privat keys

    * * @param digestMethod is a list of possible names of the digests, that should be * used for signing. */ public void setDigestMethod(List digestMethod) { // integrity check for ( COSName cosName : digestMethod ) { if (!(cosName.equals(COSName.DIGEST_SHA1) || cosName.equals(COSName.DIGEST_SHA256) || cosName.equals(COSName.DIGEST_SHA384) || cosName.equals(COSName.DIGEST_SHA512) || cosName.equals(COSName.DIGEST_RIPEMD160))) { throw new IllegalArgumentException("Specified digest " + cosName.getName() + " isn't allowed."); } } dictionary.setItem(COSName.DIGEST_METHOD, COSArrayList.converterToCOSArray(digestMethod)); } /** * The minimum required capability of the signature field seed value * dictionary parser. A value of 1 specifies that the parser shall be able to * recognize all seed value dictionary entries in a PDF 1.5 file. A value of 2 * specifies that it shall be able to recognize all seed value dictionary entries * specified. * * @return the minimum required capability of the signature field seed value * dictionary parser */ public float getV() { return dictionary.getFloat(COSName.V); } /** * (Optional) The minimum required capability of the signature field seed value * dictionary parser. A value of 1 specifies that the parser shall be able to * recognize all seed value dictionary entries in a PDF 1.5 file. A value of 2 * specifies that it shall be able to recognize all seed value dictionary entries * specified. * * @param minimumRequiredCapability is the minimum required capability of the * signature field seed value dictionary parser */ public void setV(float minimumRequiredCapability) { dictionary.setFloat(COSName.V, minimumRequiredCapability); } /** * If the Reasons array is provided and {@link #isReasonRequired()} indicates that * Reasons is a required constraint, one of the reasons in the array shall be used * for the signature dictionary; otherwise signing shall not take place. If the * {@link #isReasonRequired()} indicates Reasons is an optional constraint, one of * the reasons in the array may be chose or a custom reason can be provided. * * @return the reasons that should be used by the signature handler */ public List getReasons() { List retval = null; COSArray fields = (COSArray)dictionary.getDictionaryObject(COSName.REASONS); if (fields != null) { List actuals = new ArrayList(); for ( int i = 0; i < fields.size(); i++ ) { String element = fields.getString(i); if (element != null) { actuals.add(element); } } retval = new COSArrayList(actuals, fields); } return retval; } /** * (Optional) An array of text strings that specifying possible reasons for signing * a document. If specified, the reasons supplied in this entry replace those used * by conforming products. * * @param reasons is a list of possible text string that specifying possible reasons */ public void setReasonsd(List reasons) { dictionary.setItem(COSName.REASONS, COSArrayList.converterToCOSArray(reasons)); } /** *

    (Optional; PDF 1.6) A dictionary containing a single entry whose key is P * and whose value is an integer between 0 and 3. A value of 0 defines the * signatures as an author signature. The value 1 through 3 shall be used for * certification signatures and correspond to the value of P in a DocMDP transform * parameters dictionary.

    * *

    If this MDP key is not present or the MDP dictionary does not contain a P * entry, no rules shall be defined regarding the type of signature or its * permissions.

    * * @return the mdp dictionary as PDSeedValueMDP */ public PDSeedValueMDP getMDP() { COSDictionary dict = (COSDictionary)dictionary.getDictionaryObject(COSName.MDP); PDSeedValueMDP mdp = null; if (dict != null) { mdp = new PDSeedValueMDP(dict); } return mdp; } /** *

    (Optional; PDF 1.6) A dictionary containing a single entry whose key is P * and whose value is an integer between 0 and 3. A value of 0 defines the * signatures as an author signature. The value 1 through 3 shall be used for * certification signatures and correspond to the value of P in a DocMDP transform * parameters dictionary.

    * *

    If this MDP key is not present or the MDP dictionary does not contain a P * entry, no rules shall be defined regarding the type of signature or its * permissions.

    * * @param mdp dictionary */ public void setMPD(PDSeedValueMDP mdp) { if (mdp != null) { dictionary.setItem(COSName.MDP, mdp.getCOSObject()); } } /** *

    (Optional; PDF 1.6) A time stamp dictionary containing two entries. URL which * is a ASCII string specifying the URL to a rfc3161 conform timestamp server and Ff * to indicate if a timestamp is required or optional.

    * * @return the timestamp dictionary as PDSeedValueTimeStamp */ public PDSeedValueTimeStamp getTimeStamp() { COSDictionary dict = (COSDictionary)dictionary.getDictionaryObject(COSName.TIME_STAMP); PDSeedValueTimeStamp timestamp = null; if (dict != null) { timestamp = new PDSeedValueTimeStamp(dict); } return timestamp; } /** *

    (Optional; PDF 1.6) A time stamp dictionary containing two entries. URL which * is a ASCII string specifying the URL to a rfc3161 conform timestamp server and Ff * to indicate if a timestamp is required or optional.

    * * @param timestamp dictionary */ public void setTimeStamp(PDSeedValueTimeStamp timestamp) { if (timestamp != null) { dictionary.setItem(COSName.TIME_STAMP, timestamp.getCOSObject()); } } /** * (Optional, PDF 1.6) An array of text strings that specifying possible legal * attestations. * * @return the reasons that should be used by the signature handler */ public List getLegalAttestation() { List retval = null; COSArray fields = (COSArray)dictionary.getDictionaryObject(COSName.LEGAL_ATTESTATION); if (fields != null) { List actuals = new ArrayList(); for ( int i = 0; i < fields.size(); i++ ) { String element = fields.getString(i); if (element != null) { actuals.add(element); } } retval = new COSArrayList(actuals, fields); } return retval; } /** * (Optional, PDF 1.6) An array of text strings that specifying possible legal * attestations. * * @param legalAttestation is a list of possible text string that specifying possible * legal attestations. */ public void setLegalAttestation(List legalAttestation) { dictionary.setItem(COSName.LEGAL_ATTESTATION, COSArrayList.converterToCOSArray(legalAttestation)); } } ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDPropBuildDataDict.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDPropBuil0000644000000000000000000001627012645757432032222 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** *

    This represents the general property dictionaries from the build property dictionary.

    * * @see PDPropBuild * @author Thomas Chojecki * @version $Revision: 1.1 $ */ public class PDPropBuildDataDict implements COSObjectable { private COSDictionary dictionary; /** * Default constructor. */ public PDPropBuildDataDict() { dictionary = new COSDictionary(); dictionary.setDirect(true); // the specification claim to use direct objects } /** * Constructor. * * @param dict The signature dictionary. */ public PDPropBuildDataDict(COSDictionary dict) { dictionary = dict; dictionary.setDirect(true); // the specification claim to use direct objects } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return getDictionary(); } /** * Convert this standard java object to a COS dictionary. * * @return The COS dictionary that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * The name of the software module that was used to create the signature. * @return the name of the software module */ public String getName() { return dictionary.getString(COSName.NAME); } /** * The name of the software module that was used to create the signature. * * @param name is the name of the software module */ public void setName(String name) { dictionary.setName(COSName.NAME, name); } /** * The build date of the software module. * * @return the build date of the software module */ public String getDate() { return dictionary.getString(COSName.DATE); } /** * The build date of the software module. This string is normally produced by the * compiler under C++. * * @param date is the build date of the software module */ public void setDate(String date) { dictionary.setString(COSName.DATE, date); } /** * The software module revision number, corresponding to the Date attribute. * * @return the revision of the software module */ public long getRevision() { return dictionary.getLong(COSName.R); } /** * The software module revision number, corresponding to the Date attribute. * * @param revision is the software module revision number */ public void setRevision(long revision) { dictionary.setLong(COSName.R, revision); } /** * The software module revision number, used to determinate the minimum version * of software that is required in order to process this signature. * * @return the revision of the software module */ public long getMinimumRevision() { return dictionary.getLong(COSName.V); } /** * The software module revision number, used to determinate the minimum version * of software that is required in order to process this signature. * * @param revision is the software module revision number */ public void setMinimumRevision(long revision) { dictionary.setLong(COSName.V, revision); } /** * A flag that can be used by the signature handler or software module to * indicate that this signature was created with unrelease software. * * @return true if the software module or signature handler was a pre release. */ public boolean getPreRelease() { return dictionary.getBoolean(COSName.PRE_RELEASE, false); } /** * A flag that can be used by the signature handler or software module to * indicate that this signature was created with unrelease software. * * @param preRelease is true if the signature was created with a unrelease * software, otherwise false. */ public void setPreRelease(boolean preRelease) { dictionary.setBoolean(COSName.PRE_RELEASE, preRelease); } /** * Indicates the operation system. The format isn't specified yet. * * @return a the operation system id or name. */ public String getOS() { return dictionary.getString(COSName.OS); } /** * Indicates the operation system. The format isn't specified yet. * * @param os is a string with the system id or name. */ public void setOS(String os) { dictionary.setString(COSName.OS, os); } /** * If there is a LegalPDF dictionary in the catalog * of the PDF file and the NonEmbeddedFonts attribute in this dictionary * has a non zero value, and the viewing application has a preference * set to suppress the display of this warning then the value of this * attribute will be set to true. * * @return true if NonEFontNoWarn is set to true */ public boolean getNonEFontNoWarn() { return dictionary.getBoolean(COSName.NON_EFONT_NO_WARN, true); } /* * setNonEFontNoWarn missing. Maybe not needed or should be self * implemented. * * Documentation says: * (Optional; PDF 1.5) If there is a LegalPDF dictionary in the catalog * of the PDF file and the NonEmbeddedFonts attribute in this dictionary * has a non zero value, and the viewing application has a preference * set to suppress the display of this warning then the value of this * attribute will be set to true. */ /** * If true, the application was in trusted mode when signing took place. * * @return true if the application was in trusted mode while signing. * default: false */ public boolean getTrustedMode() { return dictionary.getBoolean(COSName.TRUSTED_MODE, false); } /** * If true, the application was in trusted mode when signing took place. * * @param trustedMode true if the application is in trusted mode. */ public void setTrustedMode(boolean trustedMode) { dictionary.setBoolean(COSName.TRUSTED_MODE, trustedMode); } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureInterface.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureI0000644000000000000000000000266712645757432032321 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import java.io.IOException; import java.io.InputStream; import org.apache.pdfbox.exceptions.SignatureException; /** * Providing an interface for accessing necessary functions for signing a pdf document. * * @author Thomas Chojecki * @version $ */ public interface SignatureInterface { /** * Creates a cms signature for the given content * * @param content is the content as a (Filter)InputStream * @return signature as a byte array */ public byte[] sign (InputStream content) throws SignatureException, IOException; } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDPropBuild.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDPropBuil0000644000000000000000000001153712645757432032223 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** *

    This represents a pdf signature build dictionary as specified in * * http://partners.adobe.com/public/developer/en/acrobat/Acrobat_Signature_BuildDict.pdf

    * *

    The signature build properties dictionary provides signature properties for the software * application that was used to create the signature.

    * * @author Thomas Chojecki * @version $Revision: 1.1 $ */ public class PDPropBuild implements COSObjectable { private COSDictionary dictionary; /** * Default constructor. */ public PDPropBuild() { dictionary = new COSDictionary(); dictionary.setDirect(true); // the specification claim to use direct objects } /** * Constructor. * * @param dict The signature dictionary. */ public PDPropBuild(COSDictionary dict) { dictionary = dict; dictionary.setDirect(true); // the specification claim to use direct objects } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return getDictionary(); } /** * Convert this standard java object to a COS dictionary. * * @return The COS dictionary that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * A build data dictionary for the signature handler that was * used to create the parent signature. * * @return the Filter as PDPropBuildFilter object */ public PDPropBuildDataDict getFilter() { PDPropBuildDataDict filter = null; COSDictionary filterDic = (COSDictionary)dictionary.getDictionaryObject(COSName.FILTER); if (filterDic != null) { filter = new PDPropBuildDataDict(filterDic); } return filter; } /** * Set the build data dictionary for the signature handler. * This entry is optional but is highly recommended for the signatures. * * @param filter is the PDPropBuildFilter */ public void setPDPropBuildFilter(PDPropBuildDataDict filter) { dictionary.setItem(COSName.FILTER, filter); } /** * A build data dictionary for the PubSec software module * that was used to create the parent signature. * * @return the PubSec as PDPropBuildPubSec object */ public PDPropBuildDataDict getPubSec() { PDPropBuildDataDict pubSec = null; COSDictionary pubSecDic = (COSDictionary)dictionary.getDictionaryObject(COSName.PUB_SEC); if (pubSecDic != null) { pubSec = new PDPropBuildDataDict(pubSecDic); } return pubSec; } /** * Set the build data dictionary for the PubSec Software module. * * @param pubSec is the PDPropBuildPubSec */ public void setPDPropBuildPubSec(PDPropBuildDataDict pubSec) { dictionary.setItem(COSName.PUB_SEC, pubSec); } /** * A build data dictionary for the viewing application software * module that was used to create the parent signature. * * @return the App as PDPropBuildApp object */ public PDPropBuildDataDict getApp() { PDPropBuildDataDict app = null; COSDictionary appDic = (COSDictionary)dictionary.getDictionaryObject(COSName.APP); if (appDic != null) { app = new PDPropBuildDataDict(appDic); } return app; } /** * Set the build data dictionary for the viewing application * software module. * * @param app is the PDPropBuildApp */ public void setPDPropBuildApp(PDPropBuildDataDict app) { dictionary.setItem(COSName.APP, app); } } ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSeedValueTimeStamp.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSeedValu0000644000000000000000000000552712645757432032201 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * If exist, it describe where the signature handler can request a rfc3161 * timestamp and if it is a must have for the signature. * * @author Thomas Chojecki * @version $Revision: 1.1 $ */ public class PDSeedValueTimeStamp { private COSDictionary dictionary; /** * Default constructor. */ public PDSeedValueTimeStamp() { dictionary = new COSDictionary(); dictionary.setDirect(true); } /** * Constructor. * * @param dict The signature dictionary. */ public PDSeedValueTimeStamp(COSDictionary dict) { dictionary = dict; dictionary.setDirect(true); } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return getDictionary(); } /** * Convert this standard java object to a COS dictionary. * * @return The COS dictionary that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * Returns the URL. * * @return the URL */ public String getURL() { return dictionary.getString(COSName.URL); } /** * Sets the URL. * @param url the URL to be set as URL */ public void setURL(String url) { dictionary.setString(COSName.URL, url); } /** * Indicates if a timestamp is required. * * @return true if a timestamp is required */ public boolean isTimestampRequired() { return dictionary.getInt(COSName.FT, 0) != 0; } /** * Sets if a timestamp is reuqired or not. * * @param flag true if a timestamp is required */ public void setTimestampRequired(boolean flag) { dictionary.setInt(COSName.FT, flag ? 1 : 0); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/0000755000000000000000000000000012645757432027124 5ustar rootroot././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationLine.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationLine0000644000000000000000000003175712645757432032232 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.color.PDGamma; /** * This is the class that represents a line annotation. * Introduced in PDF 1.3 specification * * @author Paul King * @version $Revision: 1.1 $ */ public class PDAnnotationLine extends PDAnnotationMarkup { /* * The various values for intent (get/setIT, see the PDF 1.6 reference Table * 8.22 */ /** * Constant for annotation intent of Arrow. */ public static final String IT_LINE_ARROW = "LineArrow"; /** * Constant for annotation intent of a dimension line. */ public static final String IT_LINE_DIMENSION = "LineDimension"; /* * The various values for line ending styles, see the PDF 1.6 reference * Table 8.23 */ /** * Constant for a square line ending. */ public static final String LE_SQUARE = "Square"; /** * Constant for a circle line ending. */ public static final String LE_CIRCLE = "Circle"; /** * Constant for a diamond line ending. */ public static final String LE_DIAMOND = "Diamond"; /** * Constant for a open arrow line ending. */ public static final String LE_OPEN_ARROW = "OpenArrow"; /** * Constant for a closed arrow line ending. */ public static final String LE_CLOSED_ARROW = "ClosedArrow"; /** * Constant for no line ending. */ public static final String LE_NONE = "None"; /** * Constant for a butt line ending. */ public static final String LE_BUTT = "Butt"; /** * Constant for a reversed open arrow line ending. */ public static final String LE_R_OPEN_ARROW = "ROpenArrow"; /** * Constant for a revered closed arrow line ending. */ public static final String LE_R_CLOSED_ARROW = "RClosedArrow"; /** * Constant for a slash line ending. */ public static final String LE_SLASH = "Slash"; /** * The type of annotation. */ public static final String SUB_TYPE = "Line"; /** * Constructor. */ public PDAnnotationLine() { super(); getDictionary().setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) ); // Dictionary value L is mandatory, fill in with arbitary value setLine( new float[] { 0, 0, 0, 0 } ); } /** * Creates a Line annotation from a COSDictionary, expected to be a correct * object definition. * * @param field * the PDF object to represent as a field. */ public PDAnnotationLine( COSDictionary field ) { super( field ); } /** * This will set start and end coordinates of the line (or leader line if LL * entry is set). * * @param l * array of 4 floats [x1, y1, x2, y2] line start and end points * in default user space. */ public void setLine( float[] l ) { COSArray newL = new COSArray(); newL.setFloatArray( l ); getDictionary().setItem( "L", newL ); } /** * This will retrieve the start and end coordinates of the line (or leader * line if LL entry is set). * * @return array of floats [x1, y1, x2, y2] line start and end points in * default user space. */ public float[] getLine() { COSArray l = (COSArray) getDictionary().getDictionaryObject( "L" ); return l.toFloatArray(); } /** * This will set the line ending style for the start point, * see the LE_ constants for the possible values. * * @param style The new style. */ public void setStartPointEndingStyle( String style ) { if( style == null ) { style = LE_NONE; } COSArray array = (COSArray)getDictionary().getDictionaryObject( "LE" ); if( array == null ) { array = new COSArray(); array.add( COSName.getPDFName( style ) ); array.add( COSName.getPDFName( LE_NONE ) ); getDictionary().setItem( "LE", array ); } else { array.setName( 0, style ); } } /** * This will retrieve the line ending style for the start point, * possible values shown in the LE_ constants section. * * @return The ending style for the start point. */ public String getStartPointEndingStyle() { String retval = LE_NONE; COSArray array = (COSArray)getDictionary().getDictionaryObject( "LE" ); if( array != null ) { retval = array.getName( 0 ); } return retval; } /** * This will set the line ending style for the end point, * see the LE_ constants for the possible values. * * @param style The new style. */ public void setEndPointEndingStyle( String style ) { if( style == null ) { style = LE_NONE; } COSArray array = (COSArray)getDictionary().getDictionaryObject( "LE" ); if( array == null ) { array = new COSArray(); array.add( COSName.getPDFName( LE_NONE ) ); array.add( COSName.getPDFName( style ) ); getDictionary().setItem( "LE", array ); } else { array.setName( 1, style ); } } /** * This will retrieve the line ending style for the end point, * possible values shown in the LE_ constants section. * * @return The ending style for the end point. */ public String getEndPointEndingStyle() { String retval = LE_NONE; COSArray array = (COSArray)getDictionary().getDictionaryObject( "LE" ); if( array != null ) { retval = array.getName( 1 ); } return retval; } /** * This will set interior colour of the line endings defined in the LE * entry. Colour is in DeviceRGB colourspace. * * @param ic * colour in the DeviceRGB colourspace. * */ public void setInteriorColour( PDGamma ic ) { getDictionary().setItem( "IC", ic ); } /** * This will retrieve the interior colour of the line endings defined in the * LE entry. Colour is in DeviceRGB colourspace. * * * @return PDGamma object representing the colour. * */ public PDGamma getInteriorColour() { COSArray ic = (COSArray) getDictionary().getDictionaryObject( "IC" ); if (ic != null) { return new PDGamma( ic ); } else { return null; } } /** * This will set if the contents are shown as a caption to the line. * * @param cap * Boolean value. */ public void setCaption( boolean cap ) { getDictionary().setBoolean( "Cap", cap ); } /** * This will retrieve if the contents are shown as a caption or not. * * @return boolean if the content is shown as a caption. */ public boolean getCaption() { return getDictionary().getBoolean( "Cap", false ); } /** * This will set the border style dictionary, specifying the width and dash * pattern used in drawing the line. * * @param bs the border style dictionary to set. * */ public void setBorderStyle( PDBorderStyleDictionary bs ) { this.getDictionary().setItem( "BS", bs); } /** * This will retrieve the border style dictionary, specifying the width and * dash pattern used in drawing the line. * * @return the border style dictionary. */ public PDBorderStyleDictionary getBorderStyle() { COSDictionary bs = (COSDictionary) this.getDictionary().getItem( COSName.getPDFName( "BS" ) ); if (bs != null) { return new PDBorderStyleDictionary( bs ); } else { return null; } } /** * This will retrieve the length of the leader line. * * @return the length of the leader line */ public float getLeaderLineLength() { return this.getDictionary().getFloat("LL"); } /** * This will set the length of the leader line. * * @param leaderLineLength length of the leader line */ public void setLeaderLineLength(float leaderLineLength) { this.getDictionary().setFloat("LL", leaderLineLength); } /** * This will retrieve the length of the leader line extensions. * * @return the length of the leader line extensions */ public float getLeaderLineExtensionLength() { return this.getDictionary().getFloat("LLE"); } /** * This will set the length of the leader line extensions. * * @param leaderLineExtensionLength length of the leader line extensions */ public void setLeaderLineExtensionLength(float leaderLineExtensionLength) { this.getDictionary().setFloat("LLE", leaderLineExtensionLength); } /** * This will retrieve the length of the leader line offset. * * @return the length of the leader line offset */ public float getLeaderLineOffsetLength() { return this.getDictionary().getFloat("LLO"); } /** * This will set the length of the leader line offset. * * @param leaderLineOffsetLength length of the leader line offset */ public void setLeaderLineOffsetLength(float leaderLineOffsetLength) { this.getDictionary().setFloat("LLO", leaderLineOffsetLength); } /** * This will retrieve the caption positioning. * * @return the caption positioning */ public String getCaptionPositioning() { return this.getDictionary().getString("CP"); } /** * This will set the caption positioning. * Allowed values are: "Inline" and "Top" * * @param captionPositioning caption positioning */ public void setCaptionPositioning(String captionPositioning) { this.getDictionary().setString("CP", captionPositioning); } /** * This will set the horizontal offset of the caption. * * @param offset the horizontal offset of the caption */ public void setCaptionHorizontalOffset( float offset ) { COSArray array = (COSArray)this.getDictionary().getDictionaryObject( "CO" ); if( array == null ) { array = new COSArray(); array.setFloatArray(new float[] {offset, 0.f}); this.getDictionary().setItem( "CO", array ); } else { array.set(0, new COSFloat(offset) ); } } /** * This will retrieve the horizontal offset of the caption. * * @return the the horizontal offset of the caption */ public float getCaptionHorizontalOffset() { float retval = 0.f; COSArray array = (COSArray)this.getDictionary().getDictionaryObject( "CO" ); if( array != null ) { retval = array.toFloatArray()[0]; } return retval; } /** * This will set the vertical offset of the caption. * * @param offset vertical offset of the caption */ public void setCaptionVerticalOffset( float offset ) { COSArray array = (COSArray)this.getDictionary().getDictionaryObject( "CO" ); if( array == null ) { array = new COSArray(); array.setFloatArray(new float[] {0.f, offset}); this.getDictionary().setItem( "CO", array ); } else { array.set(1, new COSFloat(offset) ); } } /** * This will retrieve the vertical offset of the caption. * * @return the vertical offset of the caption */ public float getCaptionVerticalOffset() { float retval = 0.f; COSArray array = (COSArray)this.getDictionary().getDictionaryObject( "CO" ); if( array != null ) { retval = array.toFloatArray()[1]; } return retval; } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationTextMarkup.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationText0000644000000000000000000001002712645757432032252 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSName; /** * This is the abstract class that represents a text markup annotation * Introduced in PDF 1.3 specification, except Squiggly lines in 1.4. * * @author Paul King * @version $Revision: 1.1 $ */ public class PDAnnotationTextMarkup extends PDAnnotationMarkup { /** * The types of annotation. */ public static final String SUB_TYPE_HIGHLIGHT = "Highlight"; /** * The types of annotation. */ public static final String SUB_TYPE_UNDERLINE = "Underline"; /** * The types of annotation. */ public static final String SUB_TYPE_SQUIGGLY = "Squiggly"; /** * The types of annotation. */ public static final String SUB_TYPE_STRIKEOUT = "StrikeOut"; private PDAnnotationTextMarkup() { // Must be constructed with a subType or dictionary parameter } /** * Creates a TextMarkup annotation of the specified sub type. * * @param subType the subtype the annotation represents */ public PDAnnotationTextMarkup(String subType) { super(); setSubtype( subType ); // Quad points are required, set and empty array setQuadPoints( new float[0] ); } /** * Creates a TextMarkup annotation from a COSDictionary, expected to be a * correct object definition. * * @param field the PDF objet to represent as a field. */ public PDAnnotationTextMarkup( COSDictionary field ) { super( field ); } /** * This will set the set of quadpoints which encompass the areas of this * annotation. * * @param quadPoints * an array representing the set of area covered */ public void setQuadPoints( float[] quadPoints ) { COSArray newQuadPoints = new COSArray(); newQuadPoints.setFloatArray( quadPoints ); getDictionary().setItem( "QuadPoints", newQuadPoints ); } /** * This will retrieve the set of quadpoints which encompass the areas of * this annotation. * * @return An array of floats representing the quad points. */ public float[] getQuadPoints() { COSArray quadPoints = (COSArray) getDictionary().getDictionaryObject( "QuadPoints" ); if (quadPoints != null) { return quadPoints.toFloatArray(); } else { return null; // Should never happen as this is a required item } } /** * This will set the sub type (and hence appearance, AP taking precedence) For * this annotation. See the SUB_TYPE_XXX constants for valid values. * * @param subType The subtype of the annotation */ public void setSubtype( String subType ) { getDictionary().setName( COSName.SUBTYPE, subType ); } /** * This will retrieve the sub type (and hence appearance, AP taking precedence) * For this annotation. * * @return The subtype of this annotation, see the SUB_TYPE_XXX constants. */ public String getSubtype() { return getDictionary().getNameAsString( COSName.SUBTYPE); } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationLink.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationLink0000644000000000000000000001646612645757432032240 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import java.io.IOException; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionURI; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination; /** * This is the class that represents a link annotation. * * @author Ben Litchfield * @author Paul King * @version $Revision: 1.3 $ */ public class PDAnnotationLink extends PDAnnotation { /** * Constant values of the Text as defined in the PDF 1.6 reference Table 8.19. */ public static final String HIGHLIGHT_MODE_NONE = "N"; /** * Constant values of the Text as defined in the PDF 1.6 reference Table 8.19. */ public static final String HIGHLIGHT_MODE_INVERT = "I"; /** * Constant values of the Text as defined in the PDF 1.6 reference Table 8.19. */ public static final String HIGHLIGHT_MODE_OUTLINE = "O"; /** * Constant values of the Text as defined in the PDF 1.6 reference Table 8.19. */ public static final String HIGHLIGHT_MODE_PUSH = "P"; /** * The type of annotation. */ public static final String SUB_TYPE = "Link"; /** * Constructor. */ public PDAnnotationLink() { super(); getDictionary().setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) ); } /** * Creates a Link annotation from a COSDictionary, expected to be * a correct object definition. * * @param field the PDF objet to represent as a field. */ public PDAnnotationLink(COSDictionary field) { super( field ); } /** * Get the action to be performed when this annotation is to be activated. Either this or the * destination entry should be set, but not both. * * @return The action to be performed when this annotation is activated. */ public PDAction getAction() { COSDictionary action = (COSDictionary) this.getDictionary().getDictionaryObject( COSName.A ); return PDActionFactory.createAction( action ); } /** * Set the annotation action. Either this or the destination entry should be set, but not both. * * @param action The annotation action. * */ public void setAction( PDAction action ) { this.getDictionary().setItem( COSName.A, action ); } /** * This will set the border style dictionary, specifying the width and dash * pattern used in drawing the line. * * @param bs the border style dictionary to set. * */ public void setBorderStyle( PDBorderStyleDictionary bs ) { this.getDictionary().setItem(COSName.BS, bs); } /** * This will retrieve the border style dictionary, specifying the width and * dash pattern used in drawing the line. * * @return the border style dictionary. */ public PDBorderStyleDictionary getBorderStyle() { COSBase bs = this.getDictionary().getDictionaryObject(COSName.BS); if (bs instanceof COSDictionary) { return new PDBorderStyleDictionary((COSDictionary) bs); } else { return null; } } /** * Get the destination to be displayed when the annotation is activated. Either this or the * action entry should be set, but not both. * * @return The destination for this annotation. * * @throws IOException If there is an error creating the destination. */ public PDDestination getDestination() throws IOException { COSBase base = getDictionary().getDictionaryObject( COSName.DEST ); PDDestination retval = PDDestination.create( base ); return retval; } /** * The new destination value. Either this or the action entry should be set, but not both. * * @param dest The updated destination. */ public void setDestination( PDDestination dest ) { getDictionary().setItem( COSName.DEST, dest ); } /** * Set the highlight mode for when the mouse is depressed. * See the HIGHLIGHT_MODE_XXX constants. * * @return The string representation of the highlight mode. */ public String getHighlightMode() { return getDictionary().getNameAsString( COSName.H, HIGHLIGHT_MODE_INVERT ); } /** * Set the highlight mode. See the HIGHLIGHT_MODE_XXX constants. * * @param mode The new highlight mode. */ public void setHighlightMode( String mode ) { getDictionary().setName( COSName.H, mode ); } /** * This will set the previous URI action, in case it * needs to be retrieved at later date. * * @param pa The previous URI. */ public void setPreviousURI( PDActionURI pa ) { getDictionary().setItem( "PA", pa ); } /** * This will set the previous URI action, in case it's * needed. * * @return The previous URI. */ public PDActionURI getPreviousURI() { COSDictionary pa = (COSDictionary) getDictionary().getDictionaryObject("PA"); if ( pa != null ) { return new PDActionURI( pa ); } else { return null; } } /** * This will set the set of quadpoints which encompass the areas of this * annotation which will activate. * * @param quadPoints * an array representing the set of area covered. */ public void setQuadPoints( float[] quadPoints ) { COSArray newQuadPoints = new COSArray(); newQuadPoints.setFloatArray( quadPoints ); getDictionary().setItem( "QuadPoints", newQuadPoints ); } /** * This will retrieve the set of quadpoints which encompass the areas of * this annotation which will activate. * * @return An array of floats representing the quad points. */ public float[] getQuadPoints() { COSArray quadPoints = (COSArray) getDictionary().getDictionaryObject( "QuadPoints" ); if (quadPoints != null) { return quadPoints.toFloatArray(); } else { return null; // Should never happen as this is a required item } } } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationWidget.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationWidg0000644000000000000000000001744012645757432032226 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory; import org.apache.pdfbox.pdmodel.interactive.action.PDAnnotationAdditionalActions; import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction; /** * This is the class that represents a widget. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class PDAnnotationWidget extends PDAnnotation { /** * The type of annotation. */ public static final String SUB_TYPE = "Widget"; /** * Constructor. */ public PDAnnotationWidget() { super(); getDictionary().setName( COSName.SUBTYPE, SUB_TYPE); } /** * Creates a PDWidget from a COSDictionary, expected to be * a correct object definition for a field in PDF. * * @param field the PDF objet to represent as a field. */ public PDAnnotationWidget(COSDictionary field) { super( field ); } /** * Returns the highlighting mode. Default value: I *
    *
    N
    *
    (None) No highlighting.
    *
    I
    *
    (Invert) Invert the contents of the annotation rectangle.
    *
    O
    *
    (Outline) Invert the annotation's border.
    *
    P
    *
    (Push) Display the annotation's down appearance, if any. If no * down appearance is defined, the contents of the annotation rectangle * shall be offset to appear as if it were pushed below the surface of * the page
    *
    T
    *
    (Toggle) Same as P (which is preferred).
    *
    * * @return the highlighting mode */ public String getHighlightingMode() { return this.getDictionary().getNameAsString(COSName.H, "I"); } /** * Sets the highlighting mode. *
    *
    N
    *
    (None) No highlighting.
    *
    I
    *
    (Invert) Invert the contents of the annotation rectangle.
    *
    O
    *
    (Outline) Invert the annotation's border.
    *
    P
    *
    (Push) Display the annotation's down appearance, if any. If no * down appearance is defined, the contents of the annotation rectangle * shall be offset to appear as if it were pushed below the surface of * the page
    *
    T
    *
    (Toggle) Same as P (which is preferred).
    *
    * * @param highlightingMode the highlighting mode * the defined values */ public void setHighlightingMode(String highlightingMode) { if ((highlightingMode == null) || "N".equals(highlightingMode) || "I".equals(highlightingMode) || "O".equals(highlightingMode) || "P".equals(highlightingMode) || "T".equals(highlightingMode)) { this.getDictionary().setName(COSName.H, highlightingMode); } else { throw new IllegalArgumentException( "Valid values for highlighting mode are " + "'N', 'N', 'O', 'P' or 'T'" ); } } /** * Returns the appearance characteristics dictionary. * * @return the appearance characteristics dictionary */ public PDAppearanceCharacteristicsDictionary getAppearanceCharacteristics() { COSBase mk = this.getDictionary().getDictionaryObject(COSName.getPDFName("MK")); if (mk instanceof COSDictionary) { return new PDAppearanceCharacteristicsDictionary((COSDictionary) mk); } return null; } /** * Sets the appearance characteristics dictionary. * * @param appearanceCharacteristics the appearance characteristics dictionary */ public void setAppearanceCharacteristics(PDAppearanceCharacteristicsDictionary appearanceCharacteristics) { this.getDictionary().setItem("MK", appearanceCharacteristics); } /** * Get the action to be performed when this annotation is to be activated. * * @return The action to be performed when this annotation is activated. */ public PDAction getAction() { COSDictionary action = (COSDictionary) this.getDictionary().getDictionaryObject( COSName.A ); return PDActionFactory.createAction( action ); } /** * Set the annotation action. * As of PDF 1.6 this is only used for Widget Annotations * @param action The annotation action. */ public void setAction( PDAction action ) { this.getDictionary().setItem( COSName.A, action ); } /** * Get the additional actions for this field. This will return null * if there are no additional actions for this field. * As of PDF 1.6 this is only used for Widget Annotations. * * @return The actions of the field. */ public PDAnnotationAdditionalActions getActions() { COSDictionary aa = (COSDictionary)this.getDictionary().getDictionaryObject( "AA" ); PDAnnotationAdditionalActions retval = null; if( aa != null ) { retval = new PDAnnotationAdditionalActions( aa ); } return retval; } /** * Set the actions of the field. * * @param actions The field actions. */ public void setActions( PDAnnotationAdditionalActions actions ) { this.getDictionary().setItem( "AA", actions ); } /** * This will set the border style dictionary, specifying the width and dash * pattern used in drawing the line. * * @param bs the border style dictionary to set. * */ public void setBorderStyle( PDBorderStyleDictionary bs ) { this.getDictionary().setItem( "BS", bs); } /** * This will retrieve the border style dictionary, specifying the width and * dash pattern used in drawing the line. * * @return the border style dictionary. */ public PDBorderStyleDictionary getBorderStyle() { COSDictionary bs = (COSDictionary) this.getDictionary().getItem( COSName.getPDFName( "BS" ) ); if (bs != null) { return new PDBorderStyleDictionary( bs ); } else { return null; } } // TODO where to get acroForm from? // public PDField getParent() throws IOException // { // COSBase parent = this.getDictionary().getDictionaryObject(COSName.PARENT); // if (parent instanceof COSDictionary) // { // PDAcroForm acroForm = null; // return PDFieldFactory.createField(acroForm, (COSDictionary) parent); // } // return null; // } } ././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceCharacteristicsDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceChar0000644000000000000000000001345212645757432032135 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.graphics.color.PDGamma; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; /** * This class represents an appearance characteristics dictionary. * * @version $Revision: 1.0 $ * */ public class PDAppearanceCharacteristicsDictionary implements COSObjectable { private COSDictionary dictionary; /** * Constructor. * * @param dict dictionary */ public PDAppearanceCharacteristicsDictionary(COSDictionary dict) { this.dictionary = dict; } /** * returns the dictionary. * @return the dictionary */ public COSDictionary getDictionary() { return this.dictionary; } /** * {@inheritDoc} * */ public COSBase getCOSObject() { return this.dictionary; } /** * This will retrieve the rotation of the annotation widget. * It must be a multiple of 90. Default is 0 * @return the rotation */ public int getRotation() { return this.getDictionary().getInt(COSName.R, 0); } /** * This will set the rotation. * * @param rotation the rotation as a multiple of 90 */ public void setRotation(int rotation) { this.getDictionary().setInt(COSName.R, rotation); } /** * This will retrieve the border color. * * @return the border color. */ public PDGamma getBorderColour() { COSBase c = this.getDictionary().getItem(COSName.getPDFName("BC")); if (c instanceof COSArray) { return new PDGamma((COSArray) c); } return null; } /** * This will set the border color. * * @param c the border color */ public void setBorderColour(PDGamma c) { this.getDictionary().setItem("BC", c); } /** * This will retrieve the background color. * * @return the background color. */ public PDGamma getBackground() { COSBase c = this.getDictionary().getItem(COSName.getPDFName("BG")); if (c instanceof COSArray) { return new PDGamma((COSArray) c); } return null; } /** * This will set the background color. * * @param c the background color */ public void setBackground(PDGamma c) { this.getDictionary().setItem("BG", c); } /** * This will retrieve the normal caption. * * @return the normal caption. */ public String getNormalCaption() { return this.getDictionary().getString("CA"); } /** * This will set the normal caption. * * @param caption the normal caption */ public void setNormalCaption(String caption) { this.getDictionary().setString("CA", caption); } /** * This will retrieve the rollover caption. * * @return the rollover caption. */ public String getRolloverCaption() { return this.getDictionary().getString("RC"); } /** * This will set the rollover caption. * * @param caption the rollover caption */ public void setRolloverCaption(String caption) { this.getDictionary().setString("RC", caption); } /** * This will retrieve the alternate caption. * * @return the alternate caption. */ public String getAlternateCaption() { return this.getDictionary().getString("AC"); } /** * This will set the alternate caption. * * @param caption the alternate caption */ public void setAlternateCaption(String caption) { this.getDictionary().setString("AC", caption); } /** * This will retrieve the normal icon. * * @return the normal icon. */ public PDXObjectForm getNormalIcon() { COSBase i = this.getDictionary().getDictionaryObject("I"); if (i instanceof COSStream) { return new PDXObjectForm((COSStream) i); } return null; } /** * This will retrieve the rollover icon. * * @return the rollover icon */ public PDXObjectForm getRolloverIcon() { COSBase i = this.getDictionary().getDictionaryObject("RI"); if (i instanceof COSStream) { return new PDXObjectForm((COSStream) i); } return null; } /** * This will retrieve the alternate icon. * * @return the alternate icon. */ public PDXObjectForm getAlternateIcon() { COSBase i = this.getDictionary().getDictionaryObject("IX"); if (i instanceof COSStream) { return new PDXObjectForm((COSStream) i); } return null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/package.html0000644000000000000000000000173512645757432031413 0ustar rootroot The annotation package contains classes that work with PDF annotation elements. ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationPopup.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationPopu0000644000000000000000000000621212645757432032252 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import java.io.IOException; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This is the class that represents a popup annotation. * Introduced in PDF 1.3 specification * * @author Paul King * @version $Revision: 1.2 $ */ public class PDAnnotationPopup extends PDAnnotation { /** * The type of annotation. */ public static final String SUB_TYPE = "Popup"; /** * Constructor. */ public PDAnnotationPopup() { super(); getDictionary() .setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) ); } /** * Creates a popup annotation from a COSDictionary, expected to be a correct * object definition. * * @param field * the PDF objet to represent as a field. */ public PDAnnotationPopup( COSDictionary field ) { super( field ); } /** * This will set inital state of the annotation, open or closed. * * @param open * Boolean value, true = open false = closed. */ public void setOpen( boolean open ) { getDictionary().setBoolean( "Open" , open ); } /** * This will retrieve the initial state of the annotation, open Or closed * (default closed). * * @return The initial state, true = open false = closed. */ public boolean getOpen() { return getDictionary().getBoolean( "Open" , false ); } /** * This will set the markup annotation which this popup relates to. * * @param annot * the markup annotation. */ public void setParent( PDAnnotationMarkup annot ) { getDictionary().setItem( COSName.PARENT, annot.getDictionary() ); } /** * This will retrieve the markup annotation which this popup relates to. * * @return The parent markup annotation. */ public PDAnnotationMarkup getParent() { PDAnnotationMarkup am = null; try { am = (PDAnnotationMarkup) PDAnnotation.createAnnotation( getDictionary().getDictionaryObject( "Parent", "P" ) ); } catch (IOException ioe) { // Couldn't construct the annotation, so return null i.e. do nothing } return am; } } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDBorderStyleDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDBorderStyleDic0000644000000000000000000001076412645757432032161 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern; /** * This class represents a PDF /BS entry the border style dictionary. * * @author Paul King * @version $Revision: 1.1 $ */ public class PDBorderStyleDictionary implements COSObjectable { /* * The various values of the style for the border as defined in the PDF 1.6 * reference Table 8.13 */ /** * Constant for the name of a solid style. */ public static final String STYLE_SOLID = "S"; /** * Constant for the name of a dashed style. */ public static final String STYLE_DASHED = "D"; /** * Constant for the name of a beveled style. */ public static final String STYLE_BEVELED = "B"; /** * Constant for the name of a inset style. */ public static final String STYLE_INSET = "I"; /** * Constant for the name of a underline style. */ public static final String STYLE_UNDERLINE = "U"; private COSDictionary dictionary; /** * Constructor. */ public PDBorderStyleDictionary() { dictionary = new COSDictionary(); } /** * Constructor. * * @param dict * a border style dictionary. */ public PDBorderStyleDictionary( COSDictionary dict ) { dictionary = dict; } /** * returns the dictionary. * * @return the dictionary */ public COSDictionary getDictionary() { return dictionary; } /** * returns the dictionary. * * @return the dictionary */ public COSBase getCOSObject() { return dictionary; } /** * This will set the border width in points, 0 = no border. * * @param w * float the width in points */ public void setWidth( float w ) { getDictionary().setFloat( "W", w ); } /** * This will retrieve the border width in points, 0 = no border. * * @return flaot the width of the border in points */ public float getWidth() { return getDictionary().getFloat( "W", 1 ); } /** * This will set the border style, see the STYLE_* constants for valid values. * * @param s * the border style to use */ public void setStyle( String s ) { getDictionary().setName( "S", s ); } /** * This will retrieve the border style, see the STYLE_* constants for valid * values. * * @return the style of the border */ public String getStyle() { return getDictionary().getNameAsString( "S", STYLE_SOLID ); } /** * This will set the dash style used for drawing the border. * * @param d * the dash style to use */ public void setDashStyle( PDLineDashPattern d ) { COSArray array = null; if( d != null ) { array = d.getCOSDashPattern(); } getDictionary().setItem( "D", array ); } /** * This will retrieve the dash style used for drawing the border. * * @return the dash style of the border */ public PDLineDashPattern getDashStyle() { COSArray d = (COSArray) getDictionary().getDictionaryObject( "D" ); if (d == null) { d = new COSArray(); d.add( COSInteger.THREE ); getDictionary().setItem( "D", d ); } return new PDLineDashPattern( d, 0 ); } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationText.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationText0000644000000000000000000001150512645757432032254 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This is the class that represents a text annotation. * * @author Paul King * @version $Revision: 1.1 $ */ public class PDAnnotationText extends PDAnnotationMarkup { /* * The various values of the Text as defined in the PDF 1.7 reference Table * 172 */ /** * Constant for the name of a text annotation. */ public static final String NAME_COMMENT = "Comment"; /** * Constant for the name of a text annotation. */ public static final String NAME_KEY = "Key"; /** * Constant for the name of a text annotation. */ public static final String NAME_NOTE = "Note"; /** * Constant for the name of a text annotation. */ public static final String NAME_HELP = "Help"; /** * Constant for the name of a text annotation. */ public static final String NAME_NEW_PARAGRAPH = "NewParagraph"; /** * Constant for the name of a text annotation. */ public static final String NAME_PARAGRAPH = "Paragraph"; /** * Constant for the name of a text annotation. */ public static final String NAME_INSERT = "Insert"; /** * The type of annotation. */ public static final String SUB_TYPE = "Text"; /** * Constructor. */ public PDAnnotationText() { super(); getDictionary() .setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) ); } /** * Creates a Text annotation from a COSDictionary, expected to be a correct * object definition. * * @param field * the PDF object to represent as a field. */ public PDAnnotationText( COSDictionary field ) { super( field ); } /** * This will set initial state of the annotation, open or closed. * * @param open * Boolean value, true = open false = closed */ public void setOpen( boolean open ) { getDictionary().setBoolean( COSName.getPDFName( "Open" ), open ); } /** * This will retrieve the initial state of the annotation, open Or closed * (default closed). * * @return The initial state, true = open false = closed */ public boolean getOpen() { return getDictionary().getBoolean( COSName.getPDFName( "Open" ), false ); } /** * This will set the name (and hence appearance, AP taking precedence) For * this annotation. See the NAME_XXX constants for valid values. * * @param name * The name of the annotation */ public void setName( String name ) { getDictionary().setName( COSName.NAME, name ); } /** * This will retrieve the name (and hence appearance, AP taking precedence) * For this annotation. The default is NOTE. * * @return The name of this annotation, see the NAME_XXX constants. */ public String getName() { return getDictionary().getNameAsString( COSName.NAME, NAME_NOTE ); } /** * This will retrieve the annotation state. * * @return the annotation state */ public String getState() { return this.getDictionary().getString("State"); } /** * This will set the annotation state. * * @param state the annotation state */ public void setState(String state) { this.getDictionary().setString("State", state); } /** * This will retrieve the annotation state model. * * @return the annotation state model */ public String getStateModel() { return this.getDictionary().getString("StateModel"); } /** * This will set the annotation state model. * Allowed values are "Marked" and "Review" * * @param stateModel the annotation state model */ public void setStateModel(String stateModel) { this.getDictionary().setString("StateModel", stateModel); } } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationMarkup.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationMark0000644000000000000000000002227012645757432032223 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.PDTextStream; import org.apache.pdfbox.cos.COSBase; import java.io.IOException; import java.util.Calendar; /** * This class represents the additonal fields of a Markup type Annotation. See * section 12.5.6 of ISO32000-1:2008 (starting with page 390) for details on * annotation types. * * @author Paul King * @version $Revision: 1.1 $ */ public class PDAnnotationMarkup extends PDAnnotation { /** * Constant for a FreeText type of annotation. */ public static final String SUB_TYPE_FREETEXT = "FreeText"; /** * Constant for an Polygon type of annotation. */ public static final String SUB_TYPE_POLYGON = "Polygon"; /** * Constant for an PolyLine type of annotation. */ public static final String SUB_TYPE_POLYLINE = "PolyLine"; /** * Constant for an Caret type of annotation. */ public static final String SUB_TYPE_CARET = "Caret"; /** * Constant for an Ink type of annotation. */ public static final String SUB_TYPE_INK = "Ink"; /** * Constant for an Sound type of annotation. */ public static final String SUB_TYPE_SOUND = "Sound"; /* * The various values of the reply type as defined in the PDF 1.7 reference * Table 170 */ /** * Constant for an annotation reply type. */ public static final String RT_REPLY = "R"; /** * Constant for an annotation reply type. */ public static final String RT_GROUP = "Group"; /** * Constructor. */ public PDAnnotationMarkup() { super(); } /** * Constructor. * * @param dict * The annotations dictionary. */ public PDAnnotationMarkup( COSDictionary dict ) { super( dict ); } /** * Retrieve the string used as the title of the popup window shown when open * and active (by convention this identifies who added the annotation). * * @return The title of the popup. */ public String getTitlePopup() { return getDictionary().getString( "T" ); } /** * Set the string used as the title of the popup window shown when open and * active (by convention this identifies who added the annotation). * * @param t * The title of the popup. */ public void setTitlePopup( String t ) { getDictionary().setString( "T", t ); } /** * This will retrieve the popup annotation used for entering/editing the * text for this annotation. * * @return the popup annotation. */ public PDAnnotationPopup getPopup() { COSDictionary popup = (COSDictionary) getDictionary().getDictionaryObject( "Popup" ); if (popup != null) { return new PDAnnotationPopup( popup ); } else { return null; } } /** * This will set the popup annotation used for entering/editing the text for * this annotation. * * @param popup * the popup annotation. */ public void setPopup( PDAnnotationPopup popup ) { getDictionary().setItem( "Popup", popup ); } /** * This will retrieve the constant opacity value used when rendering the * annotation (excluing any popup). * * @return the constant opacity value. */ public float getConstantOpacity() { return getDictionary().getFloat( "CA", 1 ); } /** * This will set the constant opacity value used when rendering the * annotation (excluing any popup). * * @param ca * the constant opacity value. */ public void setConstantOpacity( float ca ) { getDictionary().setFloat( "CA", ca ); } /** * This will retrieve the rich text stream which is displayed in the popup * window. * * @return the rich text stream. */ public PDTextStream getRichContents() { COSBase rc = getDictionary().getDictionaryObject( "RC" ); if (rc != null) { return PDTextStream.createTextStream( rc ); } else { return null; } } /** * This will set the rich text stream which is displayed in the popup window. * * @param rc * the rich text stream. */ public void setRichContents( PDTextStream rc ) { getDictionary().setItem( "RC", rc); } /** * This will retrieve the date and time the annotation was created. * * @return the creation date/time. * @throws IOException * if there is a format problem when converting the date. */ public Calendar getCreationDate() throws IOException { return getDictionary().getDate( "CreationDate" ); } /** * This will set the the date and time the annotation was created. * * @param creationDate * the date and time the annotation was created. */ public void setCreationDate( Calendar creationDate ) { getDictionary().setDate( "CreationDate", creationDate ); } /** * This will retrieve the annotation to which this one is "In Reply To" the * actual relationship is specified by the RT entry. * * @return the other annotation. * @throws IOException * if there is an error with the annotation. */ public PDAnnotation getInReplyTo() throws IOException { COSBase irt = getDictionary().getDictionaryObject( "IRT" ); return PDAnnotation.createAnnotation( irt ); } /** * This will set the annotation to which this one is "In Reply To" the * actual relationship is specified by the RT entry. * * @param irt the annotation this one is "In Reply To". */ public void setInReplyTo( PDAnnotation irt ) { getDictionary().setItem( "IRT", irt ); } /** * This will retrieve the short description of the subject of the annotation. * * @return the subject. */ public String getSubject() { return getDictionary().getString( "Subj" ); } /** * This will set the short description of the subject of the annotation. * * @param subj short description of the subject. */ public void setSubject( String subj ) { getDictionary().setString( "Subj", subj ); } /** * This will retrieve the Reply Type (relationship) with the annotation in * the IRT entry See the RT_* constants for the available values. * * @return the relationship. */ public String getReplyType() { return getDictionary().getNameAsString( "RT", RT_REPLY ); } /** * This will set the Reply Type (relationship) with the annotation in the * IRT entry See the RT_* constants for the available values. * * @param rt the reply type. */ public void setReplyType( String rt ) { getDictionary().setName( "RT", rt ); } /** * This will retrieve the intent of the annotation The values and meanings * are specific to the actual annotation See the IT_* constants for the * annotation classes. * * @return the intent */ public String getIntent() { return getDictionary().getNameAsString( "IT" ); } /** * This will set the intent of the annotation The values and meanings are * specific to the actual annotation See the IT_* constants for the * annotation classes. * * @param it the intent */ public void setIntent( String it ) { getDictionary().setName( "IT", it ); } /** * This will return the external data dictionary. * * @return the external data dictionary */ public PDExternalDataDictionary getExternalData() { COSBase exData = this.getDictionary().getDictionaryObject("ExData"); if (exData instanceof COSDictionary) { return new PDExternalDataDictionary((COSDictionary) exData); } return null; } /** * This will set the external data dictionary. * * @param externalData the external data dictionary */ public void setExternalData(PDExternalDataDictionary externalData) { this.getDictionary().setItem("ExData", externalData); } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceDict0000644000000000000000000002414512645757432032144 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.COSDictionaryMap; import java.util.HashMap; import java.util.Map; /** * This class represents a PDF /AP entry the appearance dictionary. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDAppearanceDictionary implements COSObjectable { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDAppearanceDictionary.class); private COSDictionary dictionary; /** * Constructor. */ public PDAppearanceDictionary() { dictionary = new COSDictionary(); //the N entry is required. dictionary.setItem( COSName.N, new COSDictionary() ); } /** * Constructor. * * @param dict The annotations dictionary. */ public PDAppearanceDictionary( COSDictionary dict ) { dictionary = dict; } /** * returns the dictionary. * @return the dictionary */ public COSDictionary getDictionary() { return dictionary; } /** * returns the dictionary. * @return the dictionary */ public COSBase getCOSObject() { return dictionary; } /** * This will return a list of appearances. In the case where there is * only one appearance the map will contain one entry whose key is the string * "default". * * @return A list of key(java.lang.String) value(PDAppearanceStream) pairs */ public Map getNormalAppearance() { COSBase ap = dictionary.getDictionaryObject( COSName.N ); if ( ap == null ) { return null; } else if( ap instanceof COSStream ) { COSStream aux = (COSStream) ap; ap = new COSDictionary(); ((COSDictionary)ap).setItem(COSName.DEFAULT, aux ); } COSDictionary map = (COSDictionary)ap; Map actuals = new HashMap(); Map retval = new COSDictionaryMap( actuals, map ); for( COSName asName : map.keySet() ) { COSBase stream = map.getDictionaryObject( asName ); // PDFBOX-1599: this is just a workaround. The given PDF provides "null" as stream // which leads to a COSName("null") value and finally to a ClassCastExcpetion if (stream instanceof COSStream) { COSStream as = (COSStream)stream; actuals.put( asName.getName(), new PDAppearanceStream( as ) ); } else { LOG.debug("non-conformance workaround: ignore null value for appearance stream."); } } return retval; } /** * This will set a list of appearances. If you would like to set the single * appearance then you should use the key "default", and when the PDF is written * back to the filesystem then there will only be one stream. * * @param appearanceMap The updated map with the appearance. */ public void setNormalAppearance( Map appearanceMap ) { dictionary.setItem( COSName.N, COSDictionaryMap.convert( appearanceMap ) ); } /** * This will set the normal appearance when there is only one appearance * to be shown. * * @param ap The appearance stream to show. */ public void setNormalAppearance( PDAppearanceStream ap ) { dictionary.setItem( COSName.N, ap.getStream() ); } /** * This will return a list of appearances. In the case where there is * only one appearance the map will contain one entry whose key is the string * "default". If there is no rollover appearance then the normal appearance * will be returned. Which means that this method will never return null. * * @return A list of key(java.lang.String) value(PDAppearanceStream) pairs */ public Map getRolloverAppearance() { Map retval = null; COSBase ap = dictionary.getDictionaryObject( COSName.R ); if( ap == null ) { retval = getNormalAppearance(); } else { if( ap instanceof COSStream ) { COSStream aux = (COSStream) ap; ap = new COSDictionary(); ((COSDictionary)ap).setItem(COSName.DEFAULT, aux ); } COSDictionary map = (COSDictionary)ap; Map actuals = new HashMap(); retval = new COSDictionaryMap( actuals, map ); for( COSName asName : map.keySet() ) { COSBase stream = map.getDictionaryObject( asName ); // PDFBOX-1599: this is just a workaround. The given PDF provides "null" as stream // which leads to a COSName("null") value and finally to a ClassCastExcpetion if (stream instanceof COSStream) { COSStream as = (COSStream)stream; actuals.put( asName.getName(), new PDAppearanceStream( as ) ); } else { LOG.debug("non-conformance workaround: ignore null value for appearance stream."); } } } return retval; } /** * This will set a list of appearances. If you would like to set the single * appearance then you should use the key "default", and when the PDF is written * back to the filesystem then there will only be one stream. * * @param appearanceMap The updated map with the appearance. */ public void setRolloverAppearance( Map appearanceMap ) { dictionary.setItem( COSName.R, COSDictionaryMap.convert( appearanceMap ) ); } /** * This will set the rollover appearance when there is rollover appearance * to be shown. * * @param ap The appearance stream to show. */ public void setRolloverAppearance( PDAppearanceStream ap ) { dictionary.setItem( COSName.R, ap.getStream() ); } /** * This will return a list of appearances. In the case where there is * only one appearance the map will contain one entry whose key is the string * "default". If there is no rollover appearance then the normal appearance * will be returned. Which means that this method will never return null. * * @return A list of key(java.lang.String) value(PDAppearanceStream) pairs */ public Map getDownAppearance() { Map retval = null; COSBase ap = dictionary.getDictionaryObject( COSName.D ); if( ap == null ) { retval = getNormalAppearance(); } else { if( ap instanceof COSStream ) { COSStream aux = (COSStream) ap; ap = new COSDictionary(); ((COSDictionary)ap).setItem(COSName.DEFAULT, aux ); } COSDictionary map = (COSDictionary)ap; Map actuals = new HashMap(); retval = new COSDictionaryMap( actuals, map ); for( COSName asName : map.keySet() ) { COSBase stream = map.getDictionaryObject( asName ); // PDFBOX-1599: this is just a workaround. The given PDF provides "null" as stream // which leads to a COSName("null") value and finally to a ClassCastExcpetion if (stream instanceof COSStream) { COSStream as = (COSStream)stream; actuals.put( asName.getName(), new PDAppearanceStream( as ) ); } else { LOG.debug("non-conformance workaround: ignore null value for appearance stream."); } } } return retval; } /** * This will set a list of appearances. If you would like to set the single * appearance then you should use the key "default", and when the PDF is written * back to the filesystem then there will only be one stream. * * @param appearanceMap The updated map with the appearance. */ public void setDownAppearance( Map appearanceMap ) { dictionary.setItem( COSName.D, COSDictionaryMap.convert( appearanceMap ) ); } /** * This will set the down appearance when there is down appearance * to be shown. * * @param ap The appearance stream to show. */ public void setDownAppearance( PDAppearanceStream ap ) { dictionary.setItem( COSName.D, ap.getStream() ); } } ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationFileAttachment.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationFile0000644000000000000000000000667112645757432032217 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import java.io.IOException; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.filespecification.PDFileSpecification; /** * This is the class that represents a file attachement. * * @author Ben Litchfield * @version $Revision: 1.2 $ */ public class PDAnnotationFileAttachment extends PDAnnotationMarkup { /** * See get/setAttachmentName. */ public static final String ATTACHMENT_NAME_PUSH_PIN = "PushPin"; /** * See get/setAttachmentName. */ public static final String ATTACHMENT_NAME_GRAPH = "Graph"; /** * See get/setAttachmentName. */ public static final String ATTACHMENT_NAME_PAPERCLIP = "Paperclip"; /** * See get/setAttachmentName. */ public static final String ATTACHMENT_NAME_TAG = "Tag"; /** * The type of annotation. */ public static final String SUB_TYPE = "FileAttachment"; /** * Constructor. */ public PDAnnotationFileAttachment() { super(); getDictionary().setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) ); } /** * Creates a Link annotation from a COSDictionary, expected to be * a correct object definition. * * @param field the PDF objet to represent as a field. */ public PDAnnotationFileAttachment(COSDictionary field) { super( field ); } /** * Return the attached file. * * @return The attached file. * * @throws IOException If there is an error creating the file spec. */ public PDFileSpecification getFile() throws IOException { return PDFileSpecification.createFS( getDictionary().getDictionaryObject( "FS" ) ); } /** * Set the attached file. * * @param file The file that is attached. */ public void setFile( PDFileSpecification file ) { getDictionary().setItem( "FS", file ); } /** * This is the name used to draw the type of attachment. * See the ATTACHMENT_NAME_XXX constants. * * @return The name that describes the visual cue for the attachment. */ public String getAttachmentName() { return getDictionary().getNameAsString( "Name", ATTACHMENT_NAME_PUSH_PIN ); } /** * Set the name used to draw the attachement icon. * See the ATTACHMENT_NAME_XXX constants. * * @param name The name of the visual icon to draw. */ public void setAttachementName( String name ) { getDictionary().setName( "Name", name ); } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationUnknown.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationUnkn0000644000000000000000000000260512645757432032244 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSDictionary; /** * This is the class that represents an arbitary Unknown Annotation type. * * @author Paul King * @version $Revision: 1.1 $ */ public class PDAnnotationUnknown extends PDAnnotation { /** * Creates an arbitary annotation from a COSDictionary, expected to be * a correct object definition for some sort of annotation. * * @param dic The dictionary which represents this Annotation. */ public PDAnnotationUnknown(COSDictionary dic) { super( dic ); } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDExternalDataDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDExternalDataDi0000644000000000000000000000526612645757432032135 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This class represents an external data dictionary. * * @version $Revision: 1.0 $ * */ public class PDExternalDataDictionary implements COSObjectable { private COSDictionary dataDictionary; /** * Constructor. */ public PDExternalDataDictionary() { this.dataDictionary = new COSDictionary(); this.dataDictionary.setName(COSName.TYPE, "ExData"); } /** * Constructor. * * @param dictionary Dictionary */ public PDExternalDataDictionary(COSDictionary dictionary) { this.dataDictionary = dictionary; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return this.dataDictionary; } /** * returns the dictionary. * * @return the dictionary */ public COSDictionary getDictionary() { return this.dataDictionary; } /** * returns the type of the external data dictionary. * It must be "ExData", if present * @return the type of the external data dictionary */ public String getType() { return this.getDictionary().getNameAsString(COSName.TYPE, "ExData"); } /** * returns the subtype of the external data dictionary. * @return the subtype of the external data dictionary */ public String getSubtype() { return this.getDictionary().getNameAsString(COSName.SUBTYPE); } /** * This will set the subtype of the external data dictionary. * @param subtype the subtype of the external data dictionary */ public void setSubtype(String subtype) { this.getDictionary().setName(COSName.SUBTYPE, subtype); } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationSquareCircle.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationSqua0000644000000000000000000001443512645757432032246 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.graphics.color.PDGamma; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** * This is the class that represents a rectangular or eliptical annotation * Introduced in PDF 1.3 specification . * * @author Paul King * @version $Revision: 1.1 $ */ public class PDAnnotationSquareCircle extends PDAnnotationMarkup { /** * Constant for a Rectangular type of annotation. */ public static final String SUB_TYPE_SQUARE = "Square"; /** * Constant for an Eliptical type of annotation. */ public static final String SUB_TYPE_CIRCLE = "Circle"; /** * Creates a Circle or Square annotation of the specified sub type. * * @param subType the subtype the annotation represents. */ public PDAnnotationSquareCircle( String subType ) { super(); setSubtype( subType ); } /** * Creates a Line annotation from a COSDictionary, expected to be a correct * object definition. * * @param field * the PDF objet to represent as a field. */ public PDAnnotationSquareCircle( COSDictionary field ) { super( field ); } /** * This will set interior colour of the drawn area * Colour is in DeviceRGB colourspace. * * @param ic * colour in the DeviceRGB colourspace. * */ public void setInteriorColour( PDGamma ic ) { getDictionary().setItem( "IC", ic ); } /** * This will retrieve the interior colour of the drawn area * Colour is in DeviceRGB colourspace. * * * @return PDGamma object representing the colour. * */ public PDGamma getInteriorColour() { COSArray ic = (COSArray) getDictionary().getItem( COSName.getPDFName( "IC" ) ); if (ic != null) { return new PDGamma( ic ); } else { return null; } } /** * This will set the border effect dictionary, specifying effects to be applied * when drawing the line. * * @param be The border effect dictionary to set. * */ public void setBorderEffect( PDBorderEffectDictionary be ) { getDictionary().setItem( "BE", be ); } /** * This will retrieve the border effect dictionary, specifying effects to be * applied used in drawing the line. * * @return The border effect dictionary */ public PDBorderEffectDictionary getBorderEffect() { COSDictionary be = (COSDictionary) getDictionary().getDictionaryObject( "BE" ); if (be != null) { return new PDBorderEffectDictionary( be ); } else { return null; } } /** * This will set the rectangle difference rectangle. Giving the difference * between the annotations rectangle and where the drawing occurs. * (To take account of any effects applied through the BE entry forexample) * * @param rd the rectangle difference * */ public void setRectDifference( PDRectangle rd ) { getDictionary().setItem( "RD", rd ); } /** * This will get the rectangle difference rectangle. Giving the difference * between the annotations rectangle and where the drawing occurs. * (To take account of any effects applied through the BE entry forexample) * * @return the rectangle difference */ public PDRectangle getRectDifference() { COSArray rd = (COSArray) getDictionary().getDictionaryObject( "RD" ); if (rd != null) { return new PDRectangle( rd ); } else { return null; } } /** * This will set the sub type (and hence appearance, AP taking precedence) For * this annotation. See the SUB_TYPE_XXX constants for valid values. * * @param subType The subtype of the annotation */ public void setSubtype( String subType ) { getDictionary().setName( COSName.SUBTYPE, subType ); } /** * This will retrieve the sub type (and hence appearance, AP taking precedence) * For this annotation. * * @return The subtype of this annotation, see the SUB_TYPE_XXX constants. */ public String getSubtype() { return getDictionary().getNameAsString( COSName.SUBTYPE); } /** * This will set the border style dictionary, specifying the width and dash * pattern used in drawing the line. * * @param bs the border style dictionary to set. * TODO not all annotations may have a BS entry * */ public void setBorderStyle( PDBorderStyleDictionary bs ) { this.getDictionary().setItem( "BS", bs); } /** * This will retrieve the border style dictionary, specifying the width and * dash pattern used in drawing the line. * * @return the border style dictionary. * TODO not all annotations may have a BS entry */ public PDBorderStyleDictionary getBorderStyle() { COSDictionary bs = (COSDictionary) this.getDictionary().getItem( COSName.getPDFName( "BS" ) ); if (bs != null) { return new PDBorderStyleDictionary( bs ); } else { return null; } } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDBorderEffectDictionary.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDBorderEffectDi0000644000000000000000000000627712645757432032116 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.COSObjectable; /** * This class represents a PDF /BE entry the border effect dictionary. * * @author Paul King * @version $Revision: 1.1 $ */ public class PDBorderEffectDictionary implements COSObjectable { /* * The various values of the effect applied to the border as defined in the * PDF 1.6 reference Table 8.14 */ /** * Constant for the name for no effect. */ public static final String STYLE_SOLID = "S"; /** * Constant for the name of a cloudy effect. */ public static final String STYLE_CLOUDY = "C"; private COSDictionary dictionary; /** * Constructor. */ public PDBorderEffectDictionary() { dictionary = new COSDictionary(); } /** * Constructor. * * @param dict * a border style dictionary. */ public PDBorderEffectDictionary( COSDictionary dict ) { dictionary = dict; } /** * returns the dictionary. * * @return the dictionary */ public COSDictionary getDictionary() { return dictionary; } /** * returns the dictionary. * * @return the dictionary */ public COSBase getCOSObject() { return dictionary; } /** * This will set the intensity of the applied effect. * * @param i * the intensity of the effect values 0 to 2 */ public void setIntensity( float i ) { getDictionary().setFloat( "I", i ); } /** * This will retrieve the intensity of the applied effect. * * @return the intensity value 0 to 2 */ public float getIntensity() { return getDictionary().getFloat( "I", 0 ); } /** * This will set the border effect, see the STYLE_* constants for valid values. * * @param s * the border effect to use */ public void setStyle( String s ) { getDictionary().setName( "S", s ); } /** * This will retrieve the border effect, see the STYLE_* constants for valid * values. * * @return the effect of the border */ public String getStyle() { return getDictionary().getNameAsString( "S", STYLE_SOLID ); } } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationRubberStamp.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotationRubb0000644000000000000000000001033212645757432032217 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; /** * This is the class that represents a rubber stamp annotation. * Introduced in PDF 1.3 specification * * @author Paul King * @version $Revision: 1.2 $ */ public class PDAnnotationRubberStamp extends PDAnnotationMarkup { /* * The various values of the rubber stamp as defined in * the PDF 1.6 reference Table 8.28 */ /** * Constant for the name of a rubber stamp. */ public static final String NAME_APPROVED = "Approved"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_EXPERIMENTAL = "Experimental"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_NOT_APPROVED = "NotApproved"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_AS_IS = "AsIs"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_EXPIRED = "Expired"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_NOT_FOR_PUBLIC_RELEASE = "NotForPublicRelease"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_FOR_PUBLIC_RELEASE = "ForPublicRelease"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_DRAFT = "Draft"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_FOR_COMMENT = "ForComment"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_TOP_SECRET = "TopSecret"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_DEPARTMENTAL = "Departmental"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_CONFIDENTIAL = "Confidential"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_FINAL = "Final"; /** * Constant for the name of a rubber stamp. */ public static final String NAME_SOLD = "Sold"; /** * The type of annotation. */ public static final String SUB_TYPE = "Stamp"; /** * Constructor. */ public PDAnnotationRubberStamp() { super(); getDictionary().setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) ); } /** * Creates a Rubber Stamp annotation from a COSDictionary, expected to be * a correct object definition. * * @param field the PDF objet to represent as a field. */ public PDAnnotationRubberStamp(COSDictionary field) { super( field ); } /** * This will set the name (and hence appearance, AP taking precedence) * For this annotation. See the NAME_XXX constants for valid values. * * @param name The name of the rubber stamp. */ public void setName( String name ) { getDictionary().setName(COSName.NAME, name); } /** * This will retrieve the name (and hence appearance, AP taking precedence) * For this annotation. The default is DRAFT. * * @return The name of this rubber stamp, see the NAME_XXX constants. */ public String getName() { return getDictionary().getNameAsString(COSName.NAME, NAME_DRAFT); } } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceStream.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceStre0000644000000000000000000001216612645757432032176 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import java.awt.geom.AffineTransform; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.util.Matrix; /** * This class represents an appearance for an annotation. * * @author Ben Litchfield * @version $Revision: 1.4 $ */ public class PDAppearanceStream implements COSObjectable { private COSStream stream = null; /** * Constructor. * * @param s The cos stream for this appearance. */ public PDAppearanceStream( COSStream s ) { stream = s; } /** * This will return the underlying stream. * * @return The wrapped stream. */ public COSStream getStream() { return stream; } /** * {@inheritDoc} */ public COSBase getCOSObject() { return stream; } /** * Get the bounding box for this appearance. This may return null in which * case the Rectangle from the annotation should be used. * * @return The bounding box for this appearance. */ public PDRectangle getBoundingBox() { PDRectangle box = null; COSArray bbox = (COSArray)stream.getDictionaryObject( COSName.BBOX ); if( bbox != null ) { box = new PDRectangle( bbox ); } return box; } /** * This will set the bounding box for this appearance stream. * * @param rectangle The new bounding box. */ public void setBoundingBox( PDRectangle rectangle ) { COSArray array = null; if( rectangle != null ) { array = rectangle.getCOSArray(); } stream.setItem( COSName.BBOX, array ); } /** * This will get the resources for this appearance stream. * * @return The appearance stream resources. */ public PDResources getResources() { PDResources retval = null; COSDictionary dict = (COSDictionary)stream.getDictionaryObject( COSName.RESOURCES ); if( dict != null ) { retval = new PDResources( dict ); } return retval; } /** * This will set the new resources. * * @param resources The new resources. */ public void setResources( PDResources resources ) { COSDictionary dict = null; if( resources != null ) { dict = resources.getCOSDictionary(); } stream.setItem( COSName.RESOURCES, dict ); } /** * Gets the optional matrix for this appearance. This may return null. * * @return The matrix of this appearance. */ public Matrix getMatrix() { Matrix retval = null; COSArray array = (COSArray)stream.getDictionaryObject( COSName.MATRIX ); if( array != null ) { retval = new Matrix(); retval.setValue(0, 0, ((COSNumber) array.get(0)).floatValue()); retval.setValue(0, 1, ((COSNumber) array.get(1)).floatValue()); retval.setValue(1, 0, ((COSNumber) array.get(2)).floatValue()); retval.setValue(1, 1, ((COSNumber) array.get(3)).floatValue()); retval.setValue(2, 0, ((COSNumber) array.get(4)).floatValue()); retval.setValue(2, 1, ((COSNumber) array.get(5)).floatValue()); } return retval; } /** * Sets the optional Matrix entry for this appearance. * @param transform the transformation matrix */ public void setMatrix(AffineTransform transform) { if (transform != null) { COSArray matrix = new COSArray(); double[] values = new double[6]; transform.getMatrix(values); for (double v : values) { matrix.add(new COSFloat((float)v)); } stream.setItem(COSName.MATRIX, matrix); } else { stream.removeItem(COSName.MATRIX); } } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.jav0000644000000000000000000004550512645757432032175 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.interactive.annotation; import java.io.IOException; import java.util.Calendar; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.graphics.color.PDGamma; import org.apache.pdfbox.util.BitFlagHelper; /** * This class represents a PDF annotation. * * @author Ben Litchfield * */ public abstract class PDAnnotation implements COSObjectable { /** * Log instance. */ private static final Log LOG = LogFactory.getLog(PDAnnotation.class); /** * An annotation flag. */ public static final int FLAG_INVISIBLE = 1 << 0; /** * An annotation flag. */ public static final int FLAG_HIDDEN = 1 << 1; /** * An annotation flag. */ public static final int FLAG_PRINTED = 1 << 2; /** * An annotation flag. */ public static final int FLAG_NO_ZOOM = 1 << 3; /** * An annotation flag. */ public static final int FLAG_NO_ROTATE = 1 << 4; /** * An annotation flag. */ public static final int FLAG_NO_VIEW = 1 << 5; /** * An annotation flag. */ public static final int FLAG_READ_ONLY = 1 << 6; /** * An annotation flag. */ public static final int FLAG_LOCKED = 1 << 7; /** * An annotation flag. */ public static final int FLAG_TOGGLE_NO_VIEW = 1 << 8; private final COSDictionary dictionary; /** * Create the correct annotation from the base COS object. * * @param base The COS object that is the annotation. * @return The correctly typed annotation object. * @throws IOException If there is an error while creating the annotation. */ public static PDAnnotation createAnnotation(COSBase base) throws IOException { PDAnnotation annot = null; if (base instanceof COSDictionary) { COSDictionary annotDic = (COSDictionary) base; String subtype = annotDic.getNameAsString(COSName.SUBTYPE); if (PDAnnotationFileAttachment.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationFileAttachment(annotDic); } else if (PDAnnotationLine.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationLine(annotDic); } else if (PDAnnotationLink.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationLink(annotDic); } else if (PDAnnotationPopup.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationPopup(annotDic); } else if (PDAnnotationRubberStamp.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationRubberStamp(annotDic); } else if (PDAnnotationSquareCircle.SUB_TYPE_SQUARE.equals(subtype) || PDAnnotationSquareCircle.SUB_TYPE_CIRCLE.equals(subtype)) { annot = new PDAnnotationSquareCircle(annotDic); } else if (PDAnnotationText.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationText(annotDic); } else if (PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT.equals(subtype) || PDAnnotationTextMarkup.SUB_TYPE_UNDERLINE.equals(subtype) || PDAnnotationTextMarkup.SUB_TYPE_SQUIGGLY.equals(subtype) || PDAnnotationTextMarkup.SUB_TYPE_STRIKEOUT.equals(subtype)) { annot = new PDAnnotationTextMarkup(annotDic); } else if (PDAnnotationLink.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationLink(annotDic); } else if (PDAnnotationWidget.SUB_TYPE.equals(subtype)) { annot = new PDAnnotationWidget(annotDic); } else if (PDAnnotationMarkup.SUB_TYPE_FREETEXT.equals(subtype) || PDAnnotationMarkup.SUB_TYPE_POLYGON.equals(subtype) || PDAnnotationMarkup.SUB_TYPE_POLYLINE.equals(subtype) || PDAnnotationMarkup.SUB_TYPE_CARET.equals(subtype) || PDAnnotationMarkup.SUB_TYPE_INK.equals(subtype) || PDAnnotationMarkup.SUB_TYPE_SOUND.equals(subtype)) { annot = new PDAnnotationMarkup(annotDic); } else { // TODO not yet implemented: // Movie, Screen, PrinterMark, TrapNet, Watermark, 3D, Redact annot = new PDAnnotationUnknown(annotDic); LOG.debug("Unknown or unsupported annotation subtype " + subtype); } } else { throw new IOException("Error: Unknown annotation type " + base); } return annot; } /** * Constructor. */ public PDAnnotation() { dictionary = new COSDictionary(); dictionary.setItem(COSName.TYPE, COSName.ANNOT); } /** * Constructor. * * @param dict The annotations dictionary. */ public PDAnnotation(COSDictionary dict) { dictionary = dict; } /** * returns the dictionary. * * @return the dictionary */ public COSDictionary getDictionary() { return dictionary; } /** * The annotation rectangle, defining the location of the annotation on the page in default user space units. This * is usually required and should not return null on valid PDF documents. But where this is a parent form field with * children, such as radio button collections then the rectangle will be null. * * @return The Rect value of this annotation. */ public PDRectangle getRectangle() { COSArray rectArray = (COSArray) dictionary.getDictionaryObject(COSName.RECT); PDRectangle rectangle = null; if (rectArray != null) { if (rectArray.size() == 4 && rectArray.get(0) instanceof COSNumber && rectArray.get(1) instanceof COSNumber && rectArray.get(2) instanceof COSNumber && rectArray.get(3) instanceof COSNumber) { rectangle = new PDRectangle(rectArray); } else { LOG.warn(rectArray + " is not a rectangle array, returning null"); } } return rectangle; } /** * This will set the rectangle for this annotation. * * @param rectangle The new rectangle values. */ public void setRectangle(PDRectangle rectangle) { dictionary.setItem(COSName.RECT, rectangle.getCOSArray()); } /** * This will get the flags for this field. * * @return flags The set of flags. */ public int getAnnotationFlags() { return getDictionary().getInt(COSName.F, 0); } /** * This will set the flags for this field. * * @param flags The new flags. */ public void setAnnotationFlags(int flags) { getDictionary().setInt(COSName.F, flags); } /** * Interface method for COSObjectable. * * @return This object as a standard COS object. */ public COSBase getCOSObject() { return getDictionary(); } /** * This will get the name of the current appearance stream if any. * * @return The name of the appearance stream. */ public String getAppearanceStream() { String retval = null; COSName name = (COSName) getDictionary().getDictionaryObject(COSName.AS); if (name != null) { retval = name.getName(); } return retval; } /** * This will set the annotations appearance stream name. * * @param as The name of the appearance stream. */ public void setAppearanceStream(String as) { if (as == null) { getDictionary().removeItem(COSName.AS); } else { getDictionary().setItem(COSName.AS, COSName.getPDFName(as)); } } /** * This will get the appearance dictionary associated with this annotation. This may return null. * * @return This annotations appearance. */ public PDAppearanceDictionary getAppearance() { PDAppearanceDictionary ap = null; COSDictionary apDic = (COSDictionary) dictionary.getDictionaryObject(COSName.AP); if (apDic != null) { ap = new PDAppearanceDictionary(apDic); } return ap; } /** * This will set the appearance associated with this annotation. * * @param appearance The appearance dictionary for this annotation. */ public void setAppearance(PDAppearanceDictionary appearance) { COSDictionary ap = null; if (appearance != null) { ap = appearance.getDictionary(); } dictionary.setItem(COSName.AP, ap); } /** * Get the invisible flag. * * @return The invisible flag. */ public boolean isInvisible() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_INVISIBLE); } /** * Set the invisible flag. * * @param invisible The new invisible flag. */ public void setInvisible(boolean invisible) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_INVISIBLE, invisible); } /** * Get the hidden flag. * * @return The hidden flag. */ public boolean isHidden() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_HIDDEN); } /** * Set the hidden flag. * * @param hidden The new hidden flag. */ public void setHidden(boolean hidden) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_HIDDEN, hidden); } /** * Get the printed flag. * * @return The printed flag. */ public boolean isPrinted() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_PRINTED); } /** * Set the printed flag. * * @param printed The new printed flag. */ public void setPrinted(boolean printed) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_PRINTED, printed); } /** * Get the noZoom flag. * * @return The noZoom flag. */ public boolean isNoZoom() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_NO_ZOOM); } /** * Set the noZoom flag. * * @param noZoom The new noZoom flag. */ public void setNoZoom(boolean noZoom) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_NO_ZOOM, noZoom); } /** * Get the noRotate flag. * * @return The noRotate flag. */ public boolean isNoRotate() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_NO_ROTATE); } /** * Set the noRotate flag. * * @param noRotate The new noRotate flag. */ public void setNoRotate(boolean noRotate) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_NO_ROTATE, noRotate); } /** * Get the noView flag. * * @return The noView flag. */ public boolean isNoView() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_NO_VIEW); } /** * Set the noView flag. * * @param noView The new noView flag. */ public void setNoView(boolean noView) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_NO_VIEW, noView); } /** * Get the readOnly flag. * * @return The readOnly flag. */ public boolean isReadOnly() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_READ_ONLY); } /** * Set the readOnly flag. * * @param readOnly The new readOnly flag. */ public void setReadOnly(boolean readOnly) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_READ_ONLY, readOnly); } /** * Get the locked flag. * * @return The locked flag. */ public boolean isLocked() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_LOCKED); } /** * Set the locked flag. * * @param locked The new locked flag. */ public void setLocked(boolean locked) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_LOCKED, locked); } /** * Get the toggleNoView flag. * * @return The toggleNoView flag. */ public boolean isToggleNoView() { return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_TOGGLE_NO_VIEW); } /** * Set the toggleNoView flag. * * @param toggleNoView The new toggleNoView flag. */ public void setToggleNoView(boolean toggleNoView) { BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_TOGGLE_NO_VIEW, toggleNoView); } /** * Get the "contents" of the field. * * @return the value of the contents. */ public String getContents() { return dictionary.getString(COSName.CONTENTS); } /** * Set the "contents" of the field. * * @param value the value of the contents. */ public void setContents(String value) { dictionary.setString(COSName.CONTENTS, value); } /** * This will retrieve the date and time the annotation was modified. * * @return the modified date/time (often in date format, but can be an arbitary string). */ public String getModifiedDate() { return getDictionary().getString(COSName.M); } /** * This will set the date and time the annotation was modified. * * @param m the date and time the annotation was created. Date values used in a PDF shall * conform to a standard date format, which closely follows that of the international standard * ASN.1 (Abstract Syntax Notation One), defined in ISO/IEC 8824. A date shall be a text string * of the form (D:YYYYMMDDHHmmSSOHH'mm). Alternatively, use * {@link #setModifiedDate(java.util.Calendar)} */ public void setModifiedDate(String m) { getDictionary().setString(COSName.M, m); } /** * This will set the date and time the annotation was modified. * * @param c the date and time the annotation was created. */ public void setModifiedDate(Calendar c) { getDictionary().setDate(COSName.M, c); } /** * This will get the name, a string intended to uniquely identify each annotation within a page. Not to be confused * with some annotations Name entry which impact the default image drawn for them. * * @return The identifying name for the Annotation. */ public String getAnnotationName() { return getDictionary().getString(COSName.NM); } /** * This will set the name, a string intended to uniquely identify each annotation within a page. Not to be confused * with some annotations Name entry which impact the default image drawn for them. * * @param nm The identifying name for the annotation. */ public void setAnnotationName(String nm) { getDictionary().setString(COSName.NM, nm); } /** * This will get the key of this annotation in the structural parent tree. * * @return the integer key of the annotation's entry in the structural parent tree */ public int getStructParent() { return getDictionary().getInt(COSName.STRUCT_PARENT, 0); } /** * This will set the key for this annotation in the structural parent tree. * * @param structParent The new key for this annotation. */ public void setStructParent(int structParent) { getDictionary().setInt(COSName.STRUCT_PARENT, structParent); } /** * This will set the colour used in drawing various elements. As of PDF 1.6 these are : Background of icon when * closed Title bar of popup window Border of a link annotation * * Colour is in DeviceRGB colourspace * * @param c colour in the DeviceRGB colourspace * */ public void setColour(PDGamma c) { getDictionary().setItem(COSName.C, c); } /** * This will retrieve the colour used in drawing various elements. As of PDF 1.6 these are : Background of icon when * closed Title bar of popup window Border of a link annotation * * Colour is in DeviceRGB colourspace * * @return PDGamma object representing the colour * */ public PDGamma getColour() { COSBase obj = getDictionary().getDictionaryObject(COSName.C); if (obj instanceof COSArray) { return new PDGamma((COSArray) obj); } else { return null; } } /** * This will retrieve the subtype of the annotation. * * @return the subtype */ public String getSubtype() { return this.getDictionary().getNameAsString(COSName.SUBTYPE); } /** * This will set the corresponding page for this annotation. * * @param page is the corresponding page */ public void setPage(PDPage page) { this.getDictionary().setItem(COSName.P, page); } /** * This will retrieve the corresponding page of this annotation. * * @return the corresponding page */ public PDPage getPage() { COSDictionary p = (COSDictionary) this.getDictionary().getDictionaryObject(COSName.P); if (p != null) { return new PDPage(p); } return null; } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/0000755000000000000000000000000012645757432026463 5ustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/prepress/0000755000000000000000000000000012645757432030326 5ustar rootroot././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/prepress/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/prepress/package.ht0000644000000000000000000000171312645757432032260 0ustar rootroot This package contains classes for prepress support in PDFBox. ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/prepress/PDBoxStyle.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/prepress/PDBoxStyle0000644000000000000000000001362112645757432032251 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.documentinterchange.prepress; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern; import org.apache.pdfbox.pdmodel.graphics.color.PDColorState; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; /** * The Box Style specifies visual characteristics for displaying box areas. * * @author Ben Litchfield * @version $Revision: 1.3 $ */ public class PDBoxStyle implements COSObjectable { /** * Style for guideline. */ public static final String GUIDELINE_STYLE_SOLID = "S"; /** * Style for guideline. */ public static final String GUIDELINE_STYLE_DASHED = "D"; private COSDictionary dictionary; /** * Default Constructor. * */ public PDBoxStyle() { dictionary = new COSDictionary(); } /** * Constructor for an existing BoxStyle element. * * @param dic The existing dictionary. */ public PDBoxStyle( COSDictionary dic ) { dictionary = dic; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return dictionary; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSDictionary getDictionary() { return dictionary; } /** * Get the color to be used for the guidelines. This is guaranteed to * not return null. The color space will always be DeviceRGB and the * default color is [0,0,0]. * *@return The guideline color. */ public PDColorState getGuidelineColor() { COSArray colorValues = (COSArray)dictionary.getDictionaryObject( "C" ); if( colorValues == null ) { colorValues = new COSArray(); colorValues.add( COSInteger.ZERO ); colorValues.add( COSInteger.ZERO ); colorValues.add( COSInteger.ZERO ); dictionary.setItem( "C", colorValues ); } PDColorState instance = new PDColorState( colorValues ); instance.setColorSpace( PDDeviceRGB.INSTANCE ); return instance; } /** * Set the color space instance for this box style. This must be a * PDDeviceRGB! * * @param color The new colorspace value. */ public void setGuideLineColor( PDColorState color ) { COSArray values = null; if( color != null ) { values = color.getCOSColorSpaceValue(); } dictionary.setItem( "C", values ); } /** * Get the width of the of the guideline in default user space units. * The default is 1. * * @return The width of the guideline. */ public float getGuidelineWidth() { return dictionary.getFloat( "W", 1 ); } /** * Set the guideline width. * * @param width The width in default user space units. */ public void setGuidelineWidth( float width ) { dictionary.setFloat( "W", width ); } /** * Get the style for the guideline. The default is "S" for solid. * * @return The guideline style. * @see PDBoxStyle#GUIDELINE_STYLE_DASHED * @see PDBoxStyle#GUIDELINE_STYLE_SOLID */ public String getGuidelineStyle() { return dictionary.getNameAsString( "S", GUIDELINE_STYLE_SOLID ); } /** * Set the style for the box. * * @param style The style for the box line. * @see PDBoxStyle#GUIDELINE_STYLE_DASHED * @see PDBoxStyle#GUIDELINE_STYLE_SOLID */ public void setGuidelineStyle( String style ) { dictionary.setName( "S", style ); } /** * Get the line dash pattern for this box style. This is guaranteed to not * return null. The default is [3],0. * * @return The line dash pattern. */ public PDLineDashPattern getLineDashPattern() { PDLineDashPattern pattern = null; COSArray d = (COSArray)dictionary.getDictionaryObject( "D" ); if( d == null ) { d = new COSArray(); d.add( COSInteger.THREE ); dictionary.setItem( "D", d ); } COSArray lineArray = new COSArray(); lineArray.add( d ); //dash phase is not specified and assumed to be zero. lineArray.add( COSInteger.ZERO ); pattern = new PDLineDashPattern( lineArray ); return pattern; } /** * Set the line dash pattern associated with this box style. * * @param pattern The patter for this box style. */ public void setLineDashPattern( PDLineDashPattern pattern ) { COSArray array = null; if( pattern != null ) { array = pattern.getCOSDashPattern(); } dictionary.setItem( "D", array ); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/markedcontent/0000755000000000000000000000000012645757432031321 5ustar rootroot././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/markedcontent/package.htmlpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/markedcontent/packa0000644000000000000000000000174412645757432032331 0ustar rootroot The marked content package provides a mechanism for modeling marked-content sequences. ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/markedcontent/PDMarkedContent.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/markedcontent/PDMar0000644000000000000000000001207512645757432032214 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.documentinterchange.markedcontent; import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.documentinterchange.taggedpdf.PDArtifactMarkedContent; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.apache.pdfbox.util.TextPosition; /** * A marked content. * * @author Johannes Koch * @version $Revision: $ */ public class PDMarkedContent { /** * Creates a marked-content sequence. * * @param tag the tag * @param properties the properties * @return the marked-content sequence */ public static PDMarkedContent create(COSName tag, COSDictionary properties) { if (COSName.ARTIFACT.equals(tag)) { new PDArtifactMarkedContent(properties); } return new PDMarkedContent(tag, properties); } private String tag; private COSDictionary properties; private List contents; /** * Creates a new marked content object. * * @param tag the tag * @param properties the properties */ public PDMarkedContent(COSName tag, COSDictionary properties) { this.tag = tag == null ? null : tag.getName(); this.properties = properties; this.contents = new ArrayList(); } /** * Gets the tag. * * @return the tag */ public String getTag() { return this.tag; } /** * Gets the properties. * * @return the properties */ public COSDictionary getProperties() { return this.properties; } /** * Gets the marked-content identifier. * * @return the marked-content identifier, or -1 if it doesn't exist. */ public int getMCID() { return this.getProperties() == null ? -1 : this.getProperties().getInt(COSName.MCID); } /** * Gets the language (Lang). * * @return the language */ public String getLanguage() { return this.getProperties() == null ? null : this.getProperties().getNameAsString(COSName.LANG); } /** * Gets the actual text (ActualText). * * @return the actual text */ public String getActualText() { return this.getProperties() == null ? null : this.getProperties().getString(COSName.ACTUAL_TEXT); } /** * Gets the alternate description (Alt). * * @return the alternate description */ public String getAlternateDescription() { return this.getProperties() == null ? null : this.getProperties().getString(COSName.ALT); } /** * Gets the expanded form (E). * * @return the expanded form */ public String getExpandedForm() { return this.getProperties() == null ? null : this.getProperties().getString(COSName.E); } /** * Gets the contents of the marked content sequence. Can be *
      *
    • {@link TextPosition},
    • *
    • {@link PDMarkedContent}, or
    • *
    • {@link PDXObject}.
    • *
    * * @return the contents of the marked content sequence */ public List getContents() { return this.contents; } /** * Adds a text position to the contents. * * @param text the text position */ public void addText(TextPosition text) { this.getContents().add(text); } /** * Adds a marked content to the contents. * * @param markedContent the marked content */ public void addMarkedContent(PDMarkedContent markedContent) { this.getContents().add(markedContent); } /** * Adds an XObject to the contents. * * @param xobject the XObject */ public void addXObject(PDXObject xobject) { this.getContents().add(xobject); } @Override public String toString() { StringBuilder sb = new StringBuilder("tag=").append(this.tag) .append(", properties=").append(this.properties); sb.append(", contents=").append(this.contents); return sb.toString(); } } pdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/taggedpdf/0000755000000000000000000000000012645757432030410 5ustar rootroot././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootpdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/taggedpdf/PDLayoutAttributeObject.javapdfbox-1.8.11/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/taggedpdf/PDLayoutA0000644000000000000000000015535212645757432032150 0ustar rootroot/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.pdmodel.documentinterchange.taggedpdf; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.graphics.color.PDGamma; /** * A Layout attribute object. * * @author Johannes Koch * @version $Revision: $ */ public class PDLayoutAttributeObject extends PDStandardAttributeObject { /** * standard attribute owner: Layout */ public static final String OWNER_LAYOUT = "Layout"; private static final String PLACEMENT = "Placement"; private static final String WRITING_MODE = "WritingMode"; private static final String BACKGROUND_COLOR = "BackgroundColor"; private static final String BORDER_COLOR = "BorderColor"; private static final String BORDER_STYLE = "BorderStyle"; private static final String BORDER_THICKNESS = "BorderThickness"; private static final String PADDING = "Padding"; private static final String COLOR = "Color"; private static final String SPACE_BEFORE = "SpaceBefore"; private static final String SPACE_AFTER = "SpaceAfter"; private static final String START_INDENT = "StartIndent"; private static final String END_INDENT = "EndIndent"; private static final String TEXT_INDENT = "TextIndent"; private static final String TEXT_ALIGN = "TextAlign"; private static final String BBOX = "BBox"; private static final String WIDTH = "Width"; private static final String HEIGHT = "Height"; private static final String BLOCK_ALIGN = "BlockAlign"; private static final String INLINE_ALIGN = "InlineAlign"; private static final String T_BORDER_STYLE = "TBorderStyle"; private static final String T_PADDING = "TPadding"; private static final String BASELINE_SHIFT = "BaselineShift"; private static final String LINE_HEIGHT = "LineHeight"; private static final String TEXT_DECORATION_COLOR = "TextDecorationColor"; private static final String TEXT_DECORATION_THICKNESS = "TextDecorationThickness"; private static final String TEXT_DECORATION_TYPE = "TextDecorationType"; private static final String RUBY_ALIGN = "RubyAlign"; private static final String RUBY_POSITION = "RubyPosition"; private static final String GLYPH_ORIENTATION_VERTICAL = "GlyphOrientationVertical"; private static final String COLUMN_COUNT = "ColumnCount"; private static final String COLUMN_GAP = "ColumnGap"; private static final String COLUMN_WIDTHS = "ColumnWidths"; /** * Placement: Block: Stacked in the block-progression direction within an * enclosing reference area or parent BLSE. */ public static final String PLACEMENT_BLOCK = "Block"; /** * Placement: Inline: Packed in the inline-progression direction within an * enclosing BLSE. */ public static final String PLACEMENT_INLINE = "Inline"; /** * Placement: Before: Placed so that the before edge of the element's * allocation rectangle coincides with that of the nearest enclosing * reference area. The element may float, if necessary, to achieve the * specified placement. The element shall be treated as a block occupying * the full extent of the enclosing reference area in the inline direction. * Other content shall be stacked so as to begin at the after edge of the * element's allocation rectangle. */ public static final String PLACEMENT_BEFORE = "Before"; /** * Placement: Start: Placed so that the start edge of the element's * allocation rectangle coincides with that of the nearest enclosing * reference area. The element may float, if necessary, to achieve the * specified placement. Other content that would intrude into the element's * allocation rectangle shall be laid out as a runaround. */ public static final String PLACEMENT_START = "Start"; /** * Placement: End: Placed so that the end edge of the element's allocation * rectangle coincides with that of the nearest enclosing reference area. * The element may float, if necessary, to achieve the specified placement. * Other content that would intrude into the element's allocation rectangle * shall be laid out as a runaround. */ public static final String PLACEMENT_END = "End"; /** * WritingMode: LrTb: Inline progression from left to right; block * progression from top to bottom. This is the typical writing mode for * Western writing systems. */ public static final String WRITING_MODE_LRTB = "LrTb"; /** * WritingMode: RlTb: Inline progression from right to left; block * progression from top to bottom. This is the typical writing mode for * Arabic and Hebrew writing systems. */ public static final String WRITING_MODE_RLTB = "RlTb"; /** * WritingMode: TbRl: Inline progression from top to bottom; block * progression from right to left. This is the typical writing mode for * Chinese and Japanese writing systems. */ public static final String WRITING_MODE_TBRL = "TbRl"; /** * BorderStyle: None: No border. Forces the computed value of * BorderThickness to be 0. */ public static final String BORDER_STYLE_NONE = "None"; /** * BorderStyle: Hidden: Same as {@link #BORDER_STYLE_NONE}, except in terms * of border conflict resolution for table elements. */ public static final String BORDER_STYLE_HIDDEN = "Hidden"; /** * BorderStyle: Dotted: The border is a series of dots. */ public static final String BORDER_STYLE_DOTTED = "Dotted"; /** * BorderStyle: Dashed: The border is a series of short line segments. */ public static final String BORDER_STYLE_DASHED = "Dashed"; /** * BorderStyle: Solid: The border is a single line segment. */ public static final String BORDER_STYLE_SOLID = "Solid"; /** * BorderStyle: Double: The border is two solid lines. The sum of the two * lines and the space between them equals the value of BorderThickness. */ public static final String BORDER_STYLE_DOUBLE = "Double"; /** * BorderStyle: Groove: The border looks as though it were carved into the * canvas. */ public static final String BORDER_STYLE_GROOVE = "Groove"; /** * BorderStyle: Ridge: The border looks as though it were coming out of the * canvas (the opposite of {@link #BORDER_STYLE_GROOVE}). */ public static final String BORDER_STYLE_RIDGE = "Ridge"; /** * BorderStyle: Inset: The border makes the entire box look as though it * were embedded in the canvas. */ public static final String BORDER_STYLE_INSET = "Inset"; /** * BorderStyle: Outset: The border makes the entire box look as though it * were coming out of the canvas (the opposite of {@link #BORDER_STYLE_INSET}. */ public static final String BORDER_STYLE_OUTSET = "Outset"; /** * TextAlign: Start: Aligned with the start edge. */ public static final String TEXT_ALIGN_START = "Start"; /** * TextAlign: Center: Centered between the start and end edges. */ public static final String TEXT_ALIGN_CENTER = "Center"; /** * TextAlign: End: Aligned with the end edge. */ public static final String TEXT_ALIGN_END = "End"; /** * TextAlign: Justify: Aligned with both the start and end edges, with * internal spacing within each line expanded, if necessary, to achieve such * alignment. The last (or only) line shall be aligned with the start edge * only. */ public static final String TEXT_ALIGN_JUSTIFY = "Justify"; /** * Width: Auto */ public static final String WIDTH_AUTO = "Auto"; /** * Height: Auto */ public static final String HEIGHT_AUTO = "Auto"; /** * BlockAlign: Before: Before edge of the first child's allocation rectangle * aligned with that of the table cell's content rectangle. */ public static final String BLOCK_ALIGN_BEFORE = "Before"; /** * BlockAlign: Middle: Children centered within the table cell. The distance * between the before edge of the first child's allocation rectangle and * that of the table cell's content rectangle shall be the same as the * distance between the after edge of the last child's allocation rectangle * and that of the table cell's content rectangle. */ public static final String BLOCK_ALIGN_MIDDLE = "Middle"; /** * BlockAlign: After: After edge of the last child's allocation rectangle * aligned with that of the table cell's content rectangle. */ public static final String BLOCK_ALIGN_AFTER = "After"; /** * BlockAlign: Justify: Children aligned with both the before and after * edges of the table cell's content rectangle. The first child shall be * placed as described for {@link #BLOCK_ALIGN_BEFORE} and the last child as * described for {@link #BLOCK_ALIGN_AFTER}, with equal spacing between the * children. If there is only one child, it shall be aligned with the before * edge only, as for {@link #BLOCK_ALIGN_BEFORE}. */ public static final String BLOCK_ALIGN_JUSTIFY = "Justify"; /** * InlineAlign: Start: Start edge of each child's allocation rectangle * aligned with that of the table cell's content rectangle. */ public static final String INLINE_ALIGN_START = "Start"; /** * InlineAlign: Center: Each child centered within the table cell. The * distance between the start edges of the child's allocation rectangle and * the table cell's content rectangle shall be the same as the distance * between their end edges. */ public static final String INLINE_ALIGN_CENTER = "Center"; /** * InlineAlign: End: End edge of each child's allocation rectangle aligned * with that of the table cell's content rectangle. */ public static final String INLINE_ALIGN_END = "End"; /** * LineHeight: NormalAdjust the line height to include any nonzero value * specified for BaselineShift. */ public static final String LINE_HEIGHT_NORMAL = "Normal"; /** * LineHeight: Auto: Adjustment for the value of BaselineShift shall not be * made. */ public static final String LINE_HEIGHT_AUTO = "Auto"; /** * TextDecorationType: None: No text decoration */ public static final String TEXT_DECORATION_TYPE_NONE = "None"; /** * TextDecorationType: Underline: A line below the text */ public static final String TEXT_DECORATION_TYPE_UNDERLINE = "Underline"; /** * TextDecorationType: Overline: A line above the text */ public static final String TEXT_DECORATION_TYPE_OVERLINE = "Overline"; /** * TextDecorationType: LineThrough: A line through the middle of the text */ public static final String TEXT_DECORATION_TYPE_LINE_THROUGH = "LineThrough"; /** * RubyAlign: Start: The content shall be aligned on the start edge in the * inline-progression direction. */ public static final String RUBY_ALIGN_START = "Start"; /** * RubyAlign: Center: The content shall be centered in the * inline-progression direction. */ public static final String RUBY_ALIGN_CENTER = "Center"; /** * RubyAlign: End: The content shall be aligned on the end edge in the * inline-progression direction. */ public static final String RUBY_ALIGN_END = "End"; /** * RubyAlign: Justify: The content shall be expanded to fill the available * width in the inline-progression direction. */ public static final String RUBY_ALIGN_JUSTIFY = "Justify"; /** * RubyAlign: Distribute: The content shall be expanded to fill the * available width in the inline-progression direction. However, space shall * also be inserted at the start edge and end edge of the text. The spacing * shall be distributed using a 1:2:1 (start:infix:end) ratio. It shall be * changed to a 0:1:1 ratio if the ruby appears at the start of a text line * or to a 1:1:0 ratio if the ruby appears at the end of the text line. */ public static final String RUBY_ALIGN_DISTRIBUTE = "Distribute"; /** * RubyPosition: Before: The RT content shall be aligned along the before * edge of the element. */ public static final String RUBY_POSITION_BEFORE = "Before"; /** * RubyPosition: After: The RT content shall be aligned along the after edge * of the element. */ public static final String RUBY_POSITION_AFTER = "After"; /** * RubyPosition: Warichu: The RT and associated RP elements shall be * formatted as a warichu, following the RB element. */ public static final String RUBY_POSITION_WARICHU = "Warichu"; /** * RubyPosition: Inline: The RT and associated RP elements shall be * formatted as a parenthesis comment, following the RB element. */ public static final String RUBY_POSITION_INLINE = "Inline"; /** * GlyphOrientationVertical: Auto */ public static final String GLYPH_ORIENTATION_VERTICAL_AUTO = "Auto"; /** * GlyphOrientationVertical: -180 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_MINUS_180_DEGREES = "-180"; /** * GlyphOrientationVertical: -90 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_MINUS_90_DEGREES = "-90"; /** * GlyphOrientationVertical: 0 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_ZERO_DEGREES = "0"; /** * GlyphOrientationVertical: 90 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_90_DEGREES = "90"; /** * GlyphOrientationVertical: 180 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_180_DEGREES = "180"; /** * GlyphOrientationVertical: 270 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_270_DEGREES = "270"; /** * GlyphOrientationVertical: 360 degrees */ public static final String GLYPH_ORIENTATION_VERTICAL_360_DEGREES = "360"; /** * Default constructor. */ public PDLayoutAttributeObject() { this.setOwner(OWNER_LAYOUT); } /** * Creates a new Layout attribute object with a given dictionary. * * @param dictionary the dictionary */ public PDLayoutAttributeObject(COSDictionary dictionary) { super(dictionary); } /** * Gets the positioning of the element with respect to the enclosing * reference area and other content (Placement). The default value is * {@link #PLACEMENT_INLINE}. * * @return the placement */ public String getPlacement() { return this.getName(PLACEMENT, PLACEMENT_INLINE); } /** * Sets the positioning of the element with respect to the enclosing * reference area and other content (Placement). The value should be one of: *