]> _ Git - cubist_pdf.git/commitdiff
wip #6800 @3.5
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Wed, 20 Mar 2024 10:59:33 +0000 (11:59 +0100)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Wed, 20 Mar 2024 10:59:33 +0000 (11:59 +0100)
23 files changed:
resources/tools/fwstk/.idea/workspace.xml
resources/tools/fwstk/bin/com/fluidbook/fwstk/CustomStripper.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/Main.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/TextsThread.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutStripper.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Page.class
resources/tools/fwstk/fwstk.iml
resources/tools/fwstk/lib/fontbox-1.8.16.jar [deleted file]
resources/tools/fwstk/lib/fontbox-2.0.30.jar [new file with mode: 0644]
resources/tools/fwstk/lib/jempbox-1.8.16.jar [deleted file]
resources/tools/fwstk/lib/pdfbox-1.8.16.jar [deleted file]
resources/tools/fwstk/lib/pdfbox-2.0.30.jar [new file with mode: 0644]
resources/tools/fwstk/lib/pdfbox-tools-2.0.30.jar [new file with mode: 0644]
resources/tools/fwstk/out/artifacts/fwstk_jar/fontbox-1.8.16.jar [deleted file]
resources/tools/fwstk/out/artifacts/fwstk_jar/fwstk.jar
resources/tools/fwstk/out/artifacts/fwstk_jar/jempbox-1.8.16.jar [deleted file]
resources/tools/fwstk/out/artifacts/fwstk_jar/pdfbox-1.8.16.jar [deleted file]
resources/tools/fwstk/src/com/fluidbook/fwstk/CustomStripper.java
resources/tools/fwstk/src/com/fluidbook/fwstk/Main.java
resources/tools/fwstk/src/com/fluidbook/fwstk/TextsThread.java
resources/tools/fwstk/src/com/fluidbook/fwstk/layout/LayoutStripper.java
resources/tools/fwstk/src/com/fluidbook/fwstk/layout/Page.java
resources/tools/fwstk/src/cube/util/ResourceLoader.java [new file with mode: 0644]

index e9c7cda6947476ffcd1a22ed4f82194ff8d2d081..93ea5d643fbe86fc742c90f8df0bfb6cfd3c708d 100644 (file)
@@ -9,9 +9,7 @@
     <option name="autoReloadType" value="SELECTIVE" />
   </component>
   <component name="ChangeListManager">
-    <list default="true" id="f146bc67-2578-4de3-9db2-94d2d43e9e83" name="Default" comment="wip #643">
-      <change beforePath="$PROJECT_DIR$/../../../src/PDFTools.php" beforeDir="false" afterPath="$PROJECT_DIR$/../../../src/PDFTools.php" afterDir="false" />
-    </list>
+    <list default="true" id="f146bc67-2578-4de3-9db2-94d2d43e9e83" name="Default" comment="wip #643" />
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
     <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -99,6 +97,7 @@
   </component>
   <component name="PropertiesComponent"><![CDATA[{
   "keyToString": {
+    "Application.filter texts.executor": "Run",
     "RunOnceActivity.OpenProjectViewOnStart": "true",
     "RunOnceActivity.ShowReadmeOnStart": "true",
     "WebServerToolWindowFactoryState": "true",
     "git-widget-placeholder": "master",
     "ignore.virus.scanning.warn.message": "true",
     "kotlin-language-version-configured": "true",
-    "last_opened_file_path": "D:/Works/cubist_pdf/resources/tools/fwstk",
+    "last_opened_file_path": "D:/Works/cubist_pdf/resources/tools/fwstk/lib/pdfbox-2.0.30.jar",
     "node.js.detected.package.eslint": "true",
     "node.js.detected.package.tslint": "true",
     "node.js.selected.package.eslint": "(autodetect)",
     "node.js.selected.package.tslint": "(autodetect)",
     "nodejs_package_manager_path": "npm",
-    "project.structure.last.edited": "SDKs",
+    "project.structure.last.edited": "Modules",
     "project.structure.proportion": "0.15",
     "project.structure.side.proportion": "0.2",
     "ruby.rails.projectView.checked": "true",
       <recent name="H:\Works\cubeExtranet\fluidbook\tools\fwstk\out\artifacts\fwstk_jar" />
     </key>
     <key name="MoveFile.RECENT_KEYS">
+      <recent name="D:\Works\cubist_pdf\resources\tools\fwstk\lib" />
       <recent name="H:\Works\cubeExtranet\fluidbook\tools\fwstk\out\artifacts\fwstk_jar" />
       <recent name="H:\Works\cubeExtranet\fluidbook\tools\fwstk" />
     </key>
   </component>
-  <component name="RunManager" selected="Application.extract layout">
+  <component name="RunManager" selected="Application.filter texts">
     <configuration default="true" type="AndroidRunConfigurationType" factoryName="Android App">
       <option name="DEPLOY" value="true" />
       <option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
         <option name="Make" enabled="true" />
       </method>
     </configuration>
+    <configuration name="filter texts" type="Application" factoryName="Application">
+      <option name="MAIN_CLASS_NAME" value="com.fluidbook.fwstk.Main" />
+      <module name="fwstk" />
+      <option name="PROGRAM_PARAMETERS" value="--input C:\Users\vince\Desktop\p1.pdf --filterTexts --output C:\Users\vince\Desktop\p1-filter.pdf" />
+      <method v="2">
+        <option name="Make" enabled="true" />
+      </method>
+    </configuration>
     <configuration default="true" type="JUnit" factoryName="JUnit">
       <option name="TEST_OBJECT" value="class" />
       <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
       <item itemvalue="Application.extract links" />
       <item itemvalue="Application.extract texts" />
       <item itemvalue="Application.extract layout" />
+      <item itemvalue="Application.filter texts" />
     </list>
   </component>
   <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
       <workItem from="1697543960076" duration="2149000" />
       <workItem from="1698075842281" duration="1718000" />
       <workItem from="1703087993201" duration="98000" />
+      <workItem from="1710873866183" duration="11834000" />
     </task>
     <task id="LOCAL-00001" summary="wip #1111 @0.5">
       <created>1487172253077</created>
     <MESSAGE value="wip #5410" />
     <option name="LAST_COMMIT_MESSAGE" value="wip #5410" />
   </component>
+  <component name="XDebuggerManager">
+    <breakpoint-manager>
+      <breakpoints>
+        <breakpoint enabled="true" type="java-exception">
+          <properties class="java.io.FileNotFoundException" package="java.io" />
+          <option name="timeStamp" value="1" />
+        </breakpoint>
+      </breakpoints>
+    </breakpoint-manager>
+  </component>
   <component name="antWorkspaceConfiguration">
     <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
     <option name="FILTER_TARGETS" value="false" />
index 2046775b29539a133aff12b4a3d4becf572bb94b..1128faf3f7ddd273f159371c3ef662fe4b596d39 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/CustomStripper.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/CustomStripper.class differ
index 79aeae6eb82f8eb42a3d5a13783712e8988fd94f..c03d0d47ce0670bfb844061a27a7c9a6340a0378 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/Main.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/Main.class differ
index 965dedb9a761d37c996173fc1297edfdf80f0188..25ed8577d67b54e20120997934b8942474787027 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/TextsThread.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/TextsThread.class differ
index 7cb76994710f475f1e3c5571a85e3d3bbbc4b174..481616570fe88c0d80b50336a466f3163ac3fd2a 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutStripper.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutStripper.class differ
index 49dbecde6516c846adc2938293b2863c1bf79fad..f0c85973a39cfee955d3acd02fb2b37b09655d55 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Page.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Page.class differ
index b3a49f9f2fbc81671f759472e77cf55435b64abf..14b360129678d9d530408bb74e5ccbc7bf99a775 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <module type="JAVA_MODULE" version="4">
   <component name="EclipseModuleManager">
-    <varelement var="file://$MODULE_DIR$/../../../../Java/resources" kind="linksrc:" value="resources" />
-    <varelement var="file://$MODULE_DIR$/../../../../Java" kind="linksrc:" value="Java" />
+    <varelement var="file://$MODULE_DIR$/../../../../Java/resources" value="linksrc:resources" />
+    <varelement var="file://$MODULE_DIR$/../../../../Java" value="linksrc:Java" />
     <src_description expected_position="0">
       <src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
       <src_folder value="file://$MODULE_DIR$/project_resources" expected_position="1" />
     </content>
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="inheritedJdk" />
-    <orderEntry type="library" exported="" name="avalon-framework-4.1.4" level="project" />
-    <orderEntry type="library" name="fontbox-1.8.16" level="project" />
-    <orderEntry type="library" name="jempbox-1.8.16" level="project" />
-    <orderEntry type="library" name="pdfbox-1.8.16" level="project" />
+    <orderEntry type="library" name="avalon-framework-4.1.4" level="project" />
     <orderEntry type="library" name="commons-io-2.6" level="project" />
     <orderEntry type="library" name="commons-logging-1.2" level="project" />
     <orderEntry type="library" name="commons-lang3-3.10" level="project" />
     <orderEntry type="library" name="commons-text-1.8" level="project" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/fontbox-2.0.30.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/pdfbox-2.0.30.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
   </component>
 </module>
\ No newline at end of file
diff --git a/resources/tools/fwstk/lib/fontbox-1.8.16.jar b/resources/tools/fwstk/lib/fontbox-1.8.16.jar
deleted file mode 100644 (file)
index 0ebc06b..0000000
Binary files a/resources/tools/fwstk/lib/fontbox-1.8.16.jar and /dev/null differ
diff --git a/resources/tools/fwstk/lib/fontbox-2.0.30.jar b/resources/tools/fwstk/lib/fontbox-2.0.30.jar
new file mode 100644 (file)
index 0000000..b49c911
Binary files /dev/null and b/resources/tools/fwstk/lib/fontbox-2.0.30.jar differ
diff --git a/resources/tools/fwstk/lib/jempbox-1.8.16.jar b/resources/tools/fwstk/lib/jempbox-1.8.16.jar
deleted file mode 100644 (file)
index edd06c5..0000000
Binary files a/resources/tools/fwstk/lib/jempbox-1.8.16.jar and /dev/null differ
diff --git a/resources/tools/fwstk/lib/pdfbox-1.8.16.jar b/resources/tools/fwstk/lib/pdfbox-1.8.16.jar
deleted file mode 100644 (file)
index d1e4c85..0000000
Binary files a/resources/tools/fwstk/lib/pdfbox-1.8.16.jar and /dev/null differ
diff --git a/resources/tools/fwstk/lib/pdfbox-2.0.30.jar b/resources/tools/fwstk/lib/pdfbox-2.0.30.jar
new file mode 100644 (file)
index 0000000..9329942
Binary files /dev/null and b/resources/tools/fwstk/lib/pdfbox-2.0.30.jar differ
diff --git a/resources/tools/fwstk/lib/pdfbox-tools-2.0.30.jar b/resources/tools/fwstk/lib/pdfbox-tools-2.0.30.jar
new file mode 100644 (file)
index 0000000..eb1f45f
Binary files /dev/null and b/resources/tools/fwstk/lib/pdfbox-tools-2.0.30.jar differ
diff --git a/resources/tools/fwstk/out/artifacts/fwstk_jar/fontbox-1.8.16.jar b/resources/tools/fwstk/out/artifacts/fwstk_jar/fontbox-1.8.16.jar
deleted file mode 100644 (file)
index 0ebc06b..0000000
Binary files a/resources/tools/fwstk/out/artifacts/fwstk_jar/fontbox-1.8.16.jar and /dev/null differ
index 161aed6363be3165d373ed84bdd198e6a1c56d93..b3735500ff87a597ceb8c03cff5b9ce488453b90 100644 (file)
Binary files a/resources/tools/fwstk/out/artifacts/fwstk_jar/fwstk.jar and b/resources/tools/fwstk/out/artifacts/fwstk_jar/fwstk.jar differ
diff --git a/resources/tools/fwstk/out/artifacts/fwstk_jar/jempbox-1.8.16.jar b/resources/tools/fwstk/out/artifacts/fwstk_jar/jempbox-1.8.16.jar
deleted file mode 100644 (file)
index edd06c5..0000000
Binary files a/resources/tools/fwstk/out/artifacts/fwstk_jar/jempbox-1.8.16.jar and /dev/null differ
diff --git a/resources/tools/fwstk/out/artifacts/fwstk_jar/pdfbox-1.8.16.jar b/resources/tools/fwstk/out/artifacts/fwstk_jar/pdfbox-1.8.16.jar
deleted file mode 100644 (file)
index d1e4c85..0000000
Binary files a/resources/tools/fwstk/out/artifacts/fwstk_jar/pdfbox-1.8.16.jar and /dev/null differ
index 44571b1e3e4bedc0b66e664eebc28fbfcf914fd6..700c1ce5257144087be14eb67fe5c9944c2ef712 100644 (file)
@@ -4,10 +4,10 @@ import java.io.IOException;
 import java.util.Properties;
 
 import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.util.PDFTextStripper;
+import org.apache.pdfbox.text.PDFTextStripper;
 
 import cube.util.StringUtil;
-import org.apache.pdfbox.util.TextPosition;
+import org.apache.pdfbox.text.TextPosition;
 
 public class CustomStripper extends PDFTextStripper {
 
@@ -29,12 +29,12 @@ public class CustomStripper extends PDFTextStripper {
        }
 
        public CustomStripper(Properties props) throws IOException {
-               super(props);
+               super();
                initProps();
        }
 
        public CustomStripper(String encoding) throws IOException {
-               super(encoding);
+               super();
                initProps();
        }
 
index 9fb35e13e1d9c6281324b6e0bdc32be687462e8a..da3e88cbb04eec37b2158c71e4f934f2b151cd01 100644 (file)
@@ -3,27 +3,27 @@ package com.fluidbook.fwstk;
 import com.fluidbook.fwstk.layout.LayoutStripper;
 import com.fluidbook.fwstk.layout.Page;
 
-import java.io.BufferedWriter;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
 
 import org.apache.commons.text.StringEscapeUtils;
-import org.apache.pdfbox.exceptions.COSVisitorException;
+import org.apache.pdfbox.contentstream.operator.Operator;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdfparser.PDFStreamParser;
+import org.apache.pdfbox.pdfwriter.ContentStreamWriter;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDDocumentInformation;
 import org.apache.pdfbox.pdmodel.PDPage;
-import org.apache.pdfbox.pdmodel.PDPageNode;
 import org.apache.pdfbox.pdmodel.common.PDPageLabelRange;
 import org.apache.pdfbox.pdmodel.common.PDPageLabels;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
-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.PDActionRemoteGoTo;
-import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionURI;
+import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
+import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
+import org.apache.pdfbox.pdmodel.interactive.action.PDActionRemoteGoTo;
+import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
 import org.apache.pdfbox.pdmodel.interactive.annotation.*;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
@@ -35,14 +35,11 @@ import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPa
 import cube.files.FileIO;
 import cube.util.Array;
 
-import java.io.File;
-import java.util.Iterator;
-
 import org.apache.pdfbox.pdmodel.*;
 import org.apache.pdfbox.pdmodel.common.*;
 import org.apache.pdfbox.pdmodel.interactive.action.PDAnnotationAdditionalActions;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDNamedDestination;
-import org.apache.pdfbox.util.PDFImageWriter;
+
 
 public class Main {
 
@@ -53,7 +50,7 @@ public class Main {
     static Float linkOffsetX = 0.0f;
     static Float linkOffsetY = 0.0f;
 
-    public static void main(String[] args) throws IOException, COSVisitorException, ClassNotFoundException, NullPointerException, InterruptedException {
+    public static void main(String[] args) throws IOException, ClassNotFoundException, NullPointerException, InterruptedException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
 
         if (args.length < 0) {
             printUsage();
@@ -75,6 +72,7 @@ public class Main {
         boolean robust = false;
         PDDocument doc = null;
         Integer[] pages = null;
+        boolean filterTexts = false;
 
         try {
             for (int i = 0; i < args.length; i++) {
@@ -121,9 +119,6 @@ public class Main {
                 } else if (args[i].trim().compareTo("--layout") == 0) {
                     i++;
                     layoutOutput = args[i].trim();
-                } else if (args[i].trim().compareTo("--image") == 0) {
-                    i++;
-                    imageOutput = args[i].trim();
                 } else if (args[i].trim().compareTo("--ignoreSeparators") == 0) {
                     i++;
                     ignoredSeparators = args[i].trim().replace("{SPACE}", " ");
@@ -139,6 +134,8 @@ public class Main {
                 } else if (args[i].trim().compareTo("--mode") == 0) {
                     i++;
                     robust = args[i].trim().equals("robust");
+                } else if (args[i].trim().compareTo("--filterTexts") == 0) {
+                    filterTexts = true;
                 }
             }
 
@@ -149,6 +146,14 @@ public class Main {
                 pages = Array.parseRange("1-" + doc.getNumberOfPages());
             }
 
+            if (filterTexts) {
+                if (doc == null) {
+                    doc = openDocument(input);
+                }
+                filterPDFTexts(doc, output);
+                return;
+            }
+
             if (infos) {
                 if (doc == null) {
                     doc = openDocument(input);
@@ -198,13 +203,6 @@ public class Main {
                 Main m = new Main();
                 m.extractLayout(doc, layoutOutput, robust, ignoredSeparators);
             }
-            if (imageOutput.compareTo("") != 0) {
-                if (doc == null) {
-                    doc = openDocument(input);
-                }
-                Main m = new Main();
-                m.makeImages(doc, imageOutput);
-            }
 
         } finally {
             if (doc != null) {
@@ -214,36 +212,17 @@ public class Main {
 
     }
 
-    private void makeImages(PDDocument doc, String imageOutput) throws IOException {
-        PDFImageWriter writer = new PDFImageWriter();
-
-        for (int i = 0; i < doc.getNumberOfPages(); i++) {
-            PDPage p = (PDPage) doc.getDocumentCatalog().getAllPages().get(i);
-            p.setCropBox(p.findMediaBox());
-            p.setTrimBox(p.findMediaBox());
-            p.setBleedBox(p.findMediaBox());
-            p.setArtBox(p.findMediaBox());
-        }
-
-        writer.writeImage(doc, "png", "", 1, doc.getNumberOfPages(), imageOutput);
-    }
-
-    private void extractLayout(PDDocument doc, String layoutOutput, boolean robust, String ignoredSeparators) throws IOException {
+    private void extractLayout(PDDocument doc, String layoutOutput, boolean robust, String ignoredSeparators) throws IOException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
         LayoutStripper stripper = null;
 
-        List pages = doc.getDocumentCatalog().getAllPages();
-        Iterator<COSObjectable> pagesIter = pages.listIterator();
-
-        int i = 0;
-
-        while (pagesIter.hasNext()) {
+        int n = doc.getNumberOfPages();
+        for (int i = 0; i < n; i++) {
+            PDPage page = doc.getPage(i);
             stripper = new LayoutStripper();
             stripper.setSplitAllChars(robust);
             stripper.setIgnoredSeparators(ignoredSeparators);
-            PDPage nextPage = (PDPage) pagesIter.next();
-            i++;
             // For each page, one stripper, otherwise, there is bug with chars widths
-            stripper.process(nextPage, i);
+            stripper.process(page, i);
             Page layout = stripper.getLayout();
             BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(layoutOutput.replace("%d", "" + i)), "UTF-8"));
             out.write(layout.asJSON());
@@ -251,7 +230,7 @@ public class Main {
         }
     }
 
-    private static Boolean getInfos(PDDocument doc) throws IOException, COSVisitorException {
+    private static Boolean getInfos(PDDocument doc) throws IOException {
         ArrayList<String> res = new ArrayList<>();
         // General informations
         String[] fields = {"Author", "Title", "CreationDate", "Creator", "Keywords", "ModificationDate", "Producer", "Subject", "Trapped", "Version"};
@@ -263,18 +242,17 @@ public class Main {
         }
 
         // Number of pages
-        List<PDPage> list = doc.getDocumentCatalog().getAllPages();
-        int pages = list.size();
+
+        int pages = doc.getNumberOfPages();
 
         res.add("Pages:\t\t\t" + pages);
         Boolean changes = false;
-        for (int i = 0; i < pages; i++) {
-            PDPage page = list.get(i);
-            int numero = i + 1;
+        for (int numero = 1; numero <= pages; numero++) {
+            PDPage page = doc.getPage(numero);
 
             // Get boxes
-            PDRectangle mediaBox = page.findMediaBox();
-            PDRectangle cropBox = page.findCropBox();
+            PDRectangle mediaBox = page.getMediaBox();
+            PDRectangle cropBox = page.getCropBox();
 
             if (cropBox == null) {
                 cropBox = mediaBox;
@@ -296,7 +274,7 @@ public class Main {
             }
 
             // Size
-            if (page.getRotation() != null && (page.getRotation() == 90 || page.getRotation() == 270)) {
+            if ((page.getRotation() == 90 || page.getRotation() == 270)) {
                 res.add("Page " + numero + " size:\t\t" + Math.abs(cropBox.getHeight()) + " pts x " + Math.abs(cropBox.getWidth()) + " pts");
                 // Boxes
                 res.add("Page " + numero + " CropBox:\t" + cropBox.getLowerLeftY() + "\t" + cropBox.getUpperRightX() + "\t" + cropBox.getUpperRightY() + "\t" + cropBox.getLowerLeftX() + "\t");
@@ -331,6 +309,83 @@ public class Main {
         return changes;
     }
 
+    private static void filterPDFTexts(PDDocument doc, String output) throws IOException {
+        int n = doc.getNumberOfPages();
+        for (int i = 0; i < n; i++) {
+            PDPage page = doc.getPage(i);
+            filterPDFTextsPage(doc, page);
+        }
+        doc.save(output);
+    }
+
+    private static void filterPDFTextsPage(PDDocument doc, PDPage page) throws IOException {
+        COSDictionary newDictionary = new COSDictionary(page.getCOSObject());
+
+        PDFStreamParser parser = new PDFStreamParser(page);
+        parser.parse();
+        List<Object> tokens = parser.getTokens();
+        parser.close();
+        ArrayList<Object> newTokens = new ArrayList<Object>();
+
+        String[] filteredOperators = {"Do", "BI", "EI", "ID"};
+        String[] ignoredOperators = {"b", "B", "b*", "B*", "c", "cm", "d", "f", "F", "f*", "G", "g", "h", "i", "j", "J", "K", "l", "m", "M", "n", "re", "RG", "s", "S", "v", "w", "W", "W*", "y"};
+
+        for (Object token : tokens) {
+            if (token instanceof Operator) {
+                Operator op = (Operator) token;
+                System.out.println(op.getName());
+                if (Arrays.asList(ignoredOperators).contains(op.getName())) {
+                    continue;
+                }
+
+                if (Arrays.asList(filteredOperators).contains(op.getName())) {
+                    System.out.println(op);
+                    //remove the one argument to this operator
+                    // added
+                    COSName name = (COSName) newTokens.remove(newTokens.size() - 1);
+                    System.out.println(name);
+                    // added
+                    deleteObject(newDictionary, name);
+                    continue;
+                }
+            }
+            newTokens.add(token);
+        }
+        PDStream newContents = new PDStream(doc);
+        ContentStreamWriter writer = new ContentStreamWriter(newContents.createOutputStream());
+        writer.writeTokens(newTokens);
+
+        page.setContents(newContents);
+
+
+        // added
+        PDResources newResources = new PDResources(newDictionary);
+        page.setResources(newResources);
+    }
+
+    private static void moveRectangle(PDRectangle re, float x, float y) {
+        re.setLowerLeftX(re.getLowerLeftX() + x);
+        re.setLowerLeftY(re.getLowerLeftY() + y);
+        re.setUpperRightX(re.getUpperRightX() + x);
+        re.setUpperRightY(re.getUpperRightY() + y);
+    }
+
+    private static boolean deleteObject(COSDictionary d, COSName name) {
+        for (COSName key : d.keySet()) {
+            if (name.equals(key)) {
+                d.removeItem(key);
+                return true;
+            }
+            COSBase object = d.getDictionaryObject(key);
+            if (object instanceof COSDictionary) {
+                if (deleteObject((COSDictionary) object, name)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private static void addLabels(ArrayList<String> res, PDPageLabels labels, int pages) {
 
         // Get the raw list
@@ -378,14 +433,15 @@ public class Main {
         }
     }
 
-    private static void cutDocument(PDDocument doc, String input, String output, String cutmode) throws COSVisitorException, IOException {
+    private static void cutDocument(PDDocument doc, String input, String output, String cutmode) throws IOException {
 
         System.out.println("Cut document of " + doc.getNumberOfPages() + " with mode " + cutmode);
 
-        ArrayList<PDDocument> copies = duplicatePages(doc, input, cutmode);
+        PDDocument finalDoc = new PDDocument();
+        ArrayList<PDDocument> copies = duplicatePages(doc, input, cutmode, finalDoc);
         cutPages(doc, cutmode);
 
-        doc.save(output);
+        finalDoc.save(output);
 
         for (PDDocument d : copies) {
             d.close();
@@ -406,17 +462,15 @@ public class Main {
         if (cutmode.startsWith("L")) {
             cutBy = Integer.parseInt(cutmode.substring(1));
         }
-        List<PDPage> pageList = doc.getDocumentCatalog().getAllPages();
-        int page;
-        for (int i = 0; i < pageList.size(); i++) {
-            PDPage pdfPage = pageList.get(i);
-            page = i + 1;
+        int n = doc.getNumberOfPages();
+        for (int page = 1; page <= n; page++) {
+            PDPage pdfPage = doc.getPage(page);
 
             if (page == 1 && !cutFirst) {
                 System.out.println("Skip page " + page);
                 continue;
             }
-            if (page == pageList.size() && !cutLast) {
+            if (page == n && !cutLast) {
                 System.out.println("Skip page " + page);
                 continue;
             }
@@ -428,7 +482,7 @@ public class Main {
 
             int decalageCrans = page % cutBy;
             float decalage = ((float) decalageCrans) * w;
-            newbox.move(decalage, 0f);
+            moveRectangle(newbox, decalage, 0f);
 
             System.out.println("Set cropbox of page " + page + " from " + pdfPage.getCropBox() + " to " + newbox + " (offset : " + decalage + ")");
 
@@ -437,10 +491,9 @@ public class Main {
         }
     }
 
-    private static ArrayList<PDDocument> duplicatePages(PDDocument doc, String input, String cutmode) throws IOException {
+    private static ArrayList<PDDocument> duplicatePages(PDDocument doc, String input, String cutmode, PDDocument finalDoc) throws IOException {
 
-        List<PDPage> pageList = doc.getDocumentCatalog().getAllPages();
-        int originalSize = pageList.size();
+        int originalSize = doc.getNumberOfPages();
 
         Boolean duplicateFirst = true;
         Boolean duplicateLast = true;
@@ -458,39 +511,26 @@ public class Main {
         }
 
         ArrayList<PDDocument> copies = new ArrayList<>();
-        for (int i = 0; i < duplicateTime; i++) {
-            copies.add(i, PDDocument.load(input));
+        for (int i = 0; i <= duplicateTime; i++) {
+            copies.add(i, openDocument(input));
         }
 
-        int page;
         int cursor = 0;
-        PDPageNode rootPages;
         PDPage currentPage;
-        for (int i = 0; i < originalSize; i++) {
-            page = i + 1;
-
-            currentPage = pageList.get(i);
-            rootPages = currentPage.getParent();
-            cursor = rootPages.getKids().indexOf(currentPage) + 1;
+        for (int page = 1; page <= originalSize; page++) {
+            currentPage = doc.getPage(page);
 
             // Skip some pages
-            if (page == 1 && !duplicateFirst) {
+            if ((page == 1 && !duplicateFirst) || (page == originalSize && !duplicateLast)) {
                 System.out.println("Skip page " + page);
-                continue;
-            }
-            if (page == pageList.size() && !duplicateLast) {
-                System.out.println("Skip page " + page);
-                continue;
+                duplicateTime = 0;
             }
+
             System.out.println("Duplicate page " + page + " :: cursor is at " + cursor);
             // Duplicate page
-            for (int j = 0; j < duplicateTime; j++) {
-                List<PDPage> l = copies.get(j).getDocumentCatalog().getAllPages();
-                PDPage newpage = l.get(i);
-                rootPages.getKids().add(cursor, newpage);
-                newpage.setParent(rootPages);
-                rootPages.updateCount();
-                cursor++;
+            for (int j = 0; j <= duplicateTime; j++) {
+                PDPage newpage = copies.get(j).getPage(page);
+                finalDoc.addPage(newpage);
             }
         }
 
@@ -498,7 +538,7 @@ public class Main {
     }
 
     public static PDDocument openDocument(String input) throws IOException {
-        return PDDocument.load(input, true);
+        return PDDocument.load(new File(input));
 
     }
 
@@ -539,7 +579,7 @@ public class Main {
         System.out.println("Extraction des textes with " + method + " : " + ((Calendar.getInstance().getTimeInMillis() - s) / 1000) + "s");
     }
 
-    public static void updateCropBox(PDDocument doc, String output, String refbox, Integer[] pages, String defined) throws IOException, COSVisitorException {
+    public static void updateCropBox(PDDocument doc, String output, String refbox, Integer[] pages, String defined) throws IOException {
         System.out.println("updateCropBox");
         if (!"".equals(defined)) {
             updateCropBoxDefined(doc, defined);
@@ -551,8 +591,8 @@ public class Main {
         return;
     }
 
-    private static void updateCropBoxDefined(PDDocument doc, String defined) throws IOException, COSVisitorException {
-        String[] e = defined.split("*");
+    private static void updateCropBoxDefined(PDDocument doc, String defined) throws IOException {
+        String[] e = defined.split("\\*");
         for (int i = 0; i < e.length; i++) {
             String[] e1 = e[i].split(",");
             Integer[] pages = new Integer[1];
@@ -561,15 +601,13 @@ public class Main {
         }
     }
 
-    private static void updateCropBoxRange(PDDocument doc, Integer[] pages, String refbox) throws IOException, COSVisitorException {
+    private static void updateCropBoxRange(PDDocument doc, Integer[] pages, String refbox) throws IOException {
         System.out.println("updateCropBoxRange " + refbox);
 
         refbox = refbox.trim();
 
-        List<PDPage> pageList = doc.getDocumentCatalog().getAllPages();
-
         for (Integer page : pages) {
-            PDPage p = pageList.get(page - 1);
+            PDPage p = doc.getPage(page);
             if (refbox.compareTo("TrimBox") == 0) {
                 p.setCropBox(p.getTrimBox());
             } else if (refbox.compareTo("MediaBox") == 0) {
@@ -594,20 +632,18 @@ public class Main {
         float h = mediaBox.getHeight() - left - right;
 
         PDRectangle box = new PDRectangle(w, h);
-        box.move(left, top);
+        moveRectangle(box, left, top);
         return box;
     }
 
     public static void extractLinks(PDDocument doc, String linksOutput, Integer[] pages) throws IOException {
-
-        List<PDPage> pageList = doc.getDocumentCatalog().getAllPages();
-
         Boolean separate = linksOutput.contains("%d");
 
         ArrayList<Link> listLinks = new ArrayList<>();
 
-        for (Integer page : pages) {
-            PDPage p = pageList.get(page - 1);
+        int n = doc.getNumberOfPages();
+        for (int page = 0; page < n; page++) {
+            PDPage p = doc.getPage(page);
             if (separate) {
                 extractLinksOfPage(doc, page, p, linksOutput);
             } else {
@@ -705,8 +741,8 @@ public class Main {
         Link myLink;
         List<PDAnnotation> links = p.getAnnotations();
 
-        PDRectangle cropbox = p.findCropBox();
-        PDRectangle mediabox = p.findMediaBox();
+        PDRectangle cropbox = p.getCropBox();
+        PDRectangle mediabox = p.getMediaBox();
 
         System.out.println("Found " + links.size() + " annotations");
         for (PDAnnotation link : links) {
@@ -829,6 +865,7 @@ public class Main {
         System.out.println("--extractLinks file\t:\tExtract links to file");
         System.out.println("--extractTexts file\t:\tExtract texts to file");
         System.out.println("--infos\t:\tget infos and return them to standard output");
+        System.out.println("--infos\t:\tgenerate a pdf file that contains only the texts of input");
 
     }
 
index a5014a793289874976a82ee641114b2edc91dbf4..bb12a48ac96918c4f787479e06a656e97748367e 100644 (file)
@@ -189,7 +189,7 @@ public class TextsThread extends Thread {
                     LayoutStripper layoutStripper;
                     layoutStripper = new LayoutStripper();
                     layoutStripper.setIgnoredSeparators(ignoredSeparators);
-                    layoutStripper.process((PDPage) doc.getDocumentCatalog().getAllPages().get(i - 1), i);
+                    layoutStripper.process(doc.getPage(i), i);
 
                     String fbhtml = layoutStripper.getLayout().asHTML();
                     String fbtext = layoutStripper.getLayout().asText();
index 5374acec2d834db9c9740f292dd3812404d1cfe8..929b539f7d27f442d6ad8d05ca1e17bb77c98ebf 100644 (file)
@@ -1,18 +1,18 @@
 package com.fluidbook.fwstk.layout;
 
 import java.io.IOException;
-import java.util.List;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Properties;
 
+import cube.util.ResourceLoader;
 import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.common.PDStream;
-import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState;
-import org.apache.pdfbox.util.PDFStreamEngine;
-import org.apache.pdfbox.util.ResourceLoader;
-import org.apache.pdfbox.util.TextPosition;
+import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
+import org.apache.pdfbox.contentstream.PDFStreamEngine;
+import org.apache.pdfbox.text.TextPosition;
 
 public class LayoutStripper extends PDFStreamEngine {
 
@@ -21,39 +21,22 @@ public class LayoutStripper extends PDFStreamEngine {
     protected boolean splitAllChars = false;
     public Page layout;
 
-    public LayoutStripper() throws IOException {
-        super(ResourceLoader.loadProperties(
-                "org/apache/pdfbox/resources/LayoutStripper.properties", true));
-    }
-
-    public LayoutStripper(Properties props) throws IOException {
-        super(props);
-        // TODO Auto-generated constructor stub
-    }
 
     public void setIgnoredSeparators(String ignoredSeparators) {
         this.ignoredSeparators = ignoredSeparators;
     }
 
-    public void process(PDPage page, int i) throws IOException {
-        this.resetEngine();
-
+    public void process(PDPage page, int i) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         this.currentPage = page;
         layout = new Page(currentPage, i, this.splitAllChars, this.ignoredSeparators);
 
-        PDResources resources = currentPage.findResources();
-        PDStream contents = null;
-        contents = currentPage.getContents();
-        if (null == contents) {
-            return;
-        }
-        COSStream stream = contents.getStream();
-
-        processStream(currentPage, resources, stream);
+        Method method = this.getClass().getDeclaredMethod("processStream");
+        method.setAccessible(true);
+        method.invoke(this, currentPage, currentPage.getResources(), currentPage.getContents());
     }
 
     protected void processTextPosition(TextPosition text) {
-        String c = text.getCharacter();
+        String c = text.getUnicode();
 
         PDGraphicsState gs = getGraphicsState();
 
index 556939efd47f6ed8fe26cfaa1afbc041e049e7e0..6d6689cedefbff2ebdffa44031e5e792fd378cf3 100644 (file)
@@ -14,19 +14,16 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.regex.Pattern;
 
 import org.apache.pdfbox.pdmodel.PDPage;
 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.graphics.PDGraphicsState;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
-import org.apache.pdfbox.pdmodel.graphics.color.PDColorState;
-import org.apache.pdfbox.pdmodel.text.PDTextState;
+import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
+import org.apache.pdfbox.pdmodel.graphics.state.PDTextState;
+import org.apache.pdfbox.pdmodel.graphics.state.RenderingMode;
 import org.apache.pdfbox.util.Matrix;
-import org.apache.pdfbox.util.ResourceLoader;
-import org.apache.pdfbox.util.TextPosition;
+import org.apache.pdfbox.text.TextPosition;
 
 /**
  * @author Cube
@@ -43,7 +40,7 @@ public class Page extends LayoutElement {
 
     public Page(PDPage page, int pageNumber, boolean splitAllChars, String ignoredSeparators) {
         this.page = page;
-        this.cropbox = page.findCropBox();
+        this.cropbox = page.getCropBox();
         this.ignoredSeparators = ignoredSeparators;
         this.splitAllChars = splitAllChars;
 
@@ -55,9 +52,9 @@ public class Page extends LayoutElement {
     public void addText(PDGraphicsState gs, Matrix textLineMatrix, Matrix textMatrix, TextPosition textPosition, String text, boolean splitLigatures) throws IOException {
         PDTextState ts = gs.getTextState();
         float rotation = new CubeMatrix(textLineMatrix).getRotation();
-        float size = textPosition.getFontSize() * textMatrix.getXScale();
-        float y = round(cropbox.getUpperRightY() - textPosition.getTextPos().getYPosition() - cropbox.getLowerLeftY());
-        float x = textPosition.getTextPos().getXPosition();
+        float size = textPosition.getFontSize() * textMatrix.getScaleX();
+        float y = round(cropbox.getUpperRightY() - textPosition.getY() - cropbox.getLowerLeftY());
+        float x = textPosition.getX();
         float width = textPosition.getWidth();
         float height = textPosition.getHeight();
         if (width == 0.0f) {
@@ -71,8 +68,8 @@ public class Page extends LayoutElement {
         // Determine l'espace normal dans cette font
         float spaceWidth = textPosition.getWidthOfSpace();
 
-        float lineScaleX = textLineMatrix.getXScale();
-        float lineScaleY = textLineMatrix.getYScale();
+        float lineScaleX = textLineMatrix.getScaleX();
+        float lineScaleY = textLineMatrix.getScaleY();
 
         // On normalise les échelles
         float minScale = Math.abs(lineScaleX);
@@ -80,10 +77,10 @@ public class Page extends LayoutElement {
         lineScaleY /= minScale;
 
         Line line = getLine(y, rotation, lineScaleX, lineScaleY);
-        if ( splitLigatures && text.length() > 1) {
+        if (splitLigatures && text.length() > 1) {
             if (isRtl(text)) {
                 for (int i = 0; i < text.length(); i++) {
-                    line.addText(size, x, y, width, height, text.substring(i, i+1), spaceWidth);
+                    line.addText(size, x, y, width, height, text.substring(i, i + 1), spaceWidth);
                 }
             } else {
                 for (int i = 0; i < text.length(); i++) {
@@ -171,21 +168,21 @@ public class Page extends LayoutElement {
 
     protected String parseColor(PDTextState ts, PDGraphicsState gs)
             throws IOException {
-        PDColorState pcs;
+        PDColor pcs;
 
-        if (ts.getRenderingMode() == PDTextState.RENDERING_MODE_FILL_TEXT) {
+        if (ts.getRenderingMode() == RenderingMode.FILL) {
             pcs = gs.getNonStrokingColor();
-        } else if (ts.getRenderingMode() == PDTextState.RENDERING_MODE_STROKE_TEXT) {
+        } else if (ts.getRenderingMode() == RenderingMode.STROKE) {
             pcs = gs.getStrokingColor();
-        } else if (ts.getRenderingMode() == PDTextState.RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT) {
+        } else if (ts.getRenderingMode() == RenderingMode.NEITHER) {
             pcs = gs.getStrokingColor();
         } else {
             pcs = gs.getStrokingColor();
         }
 
-        ColorSpace cs = getColorSpace(pcs.getColorSpace());
+        PDColorSpace cs = pcs.getColorSpace();
 
-        float[] components = pcs.getJavaColor().getColorComponents(null);
+        float[] components = pcs.getComponents();
         float[] componentsRGB = cs.toRGB(components);
 
         Color c = new Color(0, 0, 0);
@@ -201,23 +198,4 @@ public class Page extends LayoutElement {
         return color;
     }
 
-    protected ColorSpace _loadColorSpace(String path) throws IOException {
-        if (!_cs.containsKey(path)) {
-            _cs.put(path,
-                    new ICC_ColorSpace(ICC_Profile.getInstance(ResourceLoader.loadResource(path))));
-        }
-
-        return _cs.get(path);
-
-    }
-
-    protected ColorSpace getColorSpace(PDColorSpace pdfCS) throws IOException {
-        ColorSpace cs = pdfCS.getJavaColorSpace();
-        if (pdfCS.getName().equals("DeviceCMYK")) {
-            cs = _loadColorSpace("com/adobe/icc/cmyk/USWebCoatedSWOP.icc");
-        }
-
-        return cs;
-
-    }
 }
diff --git a/resources/tools/fwstk/src/cube/util/ResourceLoader.java b/resources/tools/fwstk/src/cube/util/ResourceLoader.java
new file mode 100644 (file)
index 0000000..2cbce3d
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cube.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).  This was originally
+ * written for PDFBox but FontBox uses it as well.  For now each project will
+ * have their own version.
+ *
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @version $Revision: 1.1 $
+ */
+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 = ResourceLoader.class.getClassLoader();
+
+        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
+        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 );
+            }
+        }
+
+        return is;
+    }
+
+    /**
+     * 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 loading the properties.
+     */
+    public static Properties loadProperties( String resourceName ) throws IOException
+    {
+        Properties properties = null;
+        InputStream is = null;
+        try
+        {
+            is = loadResource( resourceName );
+            if( is != null )
+            {
+                properties = new Properties();
+                properties.load( is );
+            }
+        }
+        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;
+    }
+}
\ No newline at end of file