You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2015/07/09 10:22:49 UTC

svn commit: r1690015 - in /pdfbox/trunk: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/ pdfbox/src/main/java/...

Author: jahewson
Date: Thu Jul  9 08:22:48 2015
New Revision: 1690015

URL: http://svn.apache.org/r1690015
Log:
PDFBOX-2370: Implement pluggable document-wide resource caching

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java   (with props)
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageTree.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDXObject.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceCharacteristicsDictionary.java
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/reflect/ResourcesValidationProcess.java

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java?rev=1690015&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java Thu Jul  9 08:22:48 2015
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.graphics.PDXObject;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
+import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
+import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
+
+/**
+ * A resource cached based on SoftReference, retains resources until memory pressure causes them
+ * to be garbage collected.
+ *
+ * @author John Hewson
+ */
+public class DefaultResourceCache implements ResourceCache
+{
+    private final Map<COSObject, SoftReference<PDFont>> fonts =
+            new HashMap<COSObject, SoftReference<PDFont>>();
+    
+    private final Map<COSObject, SoftReference<PDColorSpace>> colorSpaces =
+            new HashMap<COSObject, SoftReference<PDColorSpace>>();
+
+    private final Map<COSObject, SoftReference<PDXObject>> xobjects =
+            new HashMap<COSObject, SoftReference<PDXObject>>();
+
+    private final Map<COSObject, SoftReference<PDExtendedGraphicsState>> extGStates =
+            new HashMap<COSObject, SoftReference<PDExtendedGraphicsState>>();
+
+    private final Map<COSObject, SoftReference<PDShading>> shadings =
+            new HashMap<COSObject, SoftReference<PDShading>>();
+
+    private final Map<COSObject, SoftReference<PDAbstractPattern>> patterns =
+            new HashMap<COSObject, SoftReference<PDAbstractPattern>>();
+
+    private final Map<COSObject, SoftReference<PDPropertyList>> properties =
+            new HashMap<COSObject, SoftReference<PDPropertyList>>();
+
+    @Override
+    public PDFont getFont(COSObject indirect) throws IOException
+    {
+        SoftReference<PDFont> font = fonts.get(indirect);
+        if (font != null)
+        {
+            return font.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDFont font) throws IOException
+    {
+        fonts.put(indirect, new SoftReference<PDFont>(font));
+    }
+
+    @Override
+    public PDColorSpace getColorSpace(COSObject indirect) throws IOException
+    {
+        SoftReference<PDColorSpace> colorSpace = colorSpaces.get(indirect);
+        if (colorSpace != null)
+        {
+            return colorSpace.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDColorSpace colorSpace) throws IOException
+    {
+        colorSpaces.put(indirect, new SoftReference<PDColorSpace>(colorSpace));
+    }
+
+    @Override
+    public PDExtendedGraphicsState getExtGState(COSObject indirect)
+    {
+        SoftReference<PDExtendedGraphicsState> extGState = extGStates.get(indirect);
+        if (extGState != null)
+        {
+            return extGState.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDExtendedGraphicsState extGState)
+    {
+        extGStates.put(indirect, new SoftReference<PDExtendedGraphicsState>(extGState));
+    }
+
+    @Override
+    public PDShading getShading(COSObject indirect) throws IOException
+    {
+        SoftReference<PDShading> shading = shadings.get(indirect);
+        if (shading != null)
+        {
+            return shading.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDShading shading) throws IOException
+    {
+        shadings.put(indirect, new SoftReference<PDShading>(shading));
+    }
+
+    @Override
+    public PDAbstractPattern getPattern(COSObject indirect) throws IOException
+    {
+        SoftReference<PDAbstractPattern> pattern = patterns.get(indirect);
+        if (pattern != null)
+        {
+            return pattern.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDAbstractPattern pattern) throws IOException
+    {
+        patterns.put(indirect, new SoftReference<PDAbstractPattern>(pattern));
+    }
+    
+    @Override
+    public PDPropertyList getProperties(COSObject indirect)
+    {
+        SoftReference<PDPropertyList> propertyList = properties.get(indirect);
+        if (propertyList != null)
+        {
+            return propertyList.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDPropertyList propertyList)
+    {
+        properties.put(indirect, new SoftReference<PDPropertyList>(propertyList));
+    }
+
+    @Override
+    public PDXObject getXObject(COSObject indirect) throws IOException
+    {
+        SoftReference<PDXObject> xobject = xobjects.get(indirect);
+        if (xobject != null)
+        {
+            return xobject.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void put(COSObject indirect, PDXObject xobject) throws IOException
+    {
+        xobjects.put(indirect, new SoftReference<PDXObject>(xobject));
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java Thu Jul  9 08:22:48 2015
@@ -104,6 +104,9 @@ public class PDDocument implements Close
     // Signature interface
     private SignatureInterface signInterface;
     
+    // document-wide cached resources
+    private ResourceCache resourceCache = new DefaultResourceCache();
+    
     /**
      * Creates an empty PDF document.
      * You need to add at least one page for the document to be valid.
@@ -508,7 +511,7 @@ public class PDDocument implements Close
      */
     public PDPage importPage(PDPage page) throws IOException
     {
-        PDPage importedPage = new PDPage(new COSDictionary(page.getCOSObject()));
+        PDPage importedPage = new PDPage(new COSDictionary(page.getCOSObject()), resourceCache);
         InputStream is = null;
         OutputStream os = null;
         try
@@ -1305,4 +1308,22 @@ public class PDDocument implements Close
             getDocument().setVersion(newVersion);
         }
     }
+
+    /**
+     * Returns the resource cache associated with this document, or null if there is none.
+     */
+    public ResourceCache getResourceCache()
+    {
+        return resourceCache;
+    }
+
+    /**
+     * Sets the resource cache associated with this document.
+     * 
+     * @param resourceCache A resource cache, or null.
+     */
+    public void setResourceCache(ResourceCache resourceCache)
+    {
+        this.resourceCache = resourceCache;
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java Thu Jul  9 08:22:48 2015
@@ -123,7 +123,7 @@ public class PDDocumentCatalog implement
     public PDPageTree getPages()
     {
         // todo: cache me?
-        return new PDPageTree((COSDictionary)root.getDictionaryObject(COSName.PAGES));
+        return new PDPageTree((COSDictionary)root.getDictionaryObject(COSName.PAGES), document);
     }
 
     /**

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java Thu Jul  9 08:22:48 2015
@@ -56,6 +56,7 @@ public class PDPage implements COSObject
     
     private final COSDictionary page;
     private PDResources pageResources;
+    private ResourceCache resourceCache;
     private PDRectangle mediaBox;
 
     /**
@@ -89,6 +90,17 @@ public class PDPage implements COSObject
     }
 
     /**
+     * Creates a new instance of PDPage for reading.
+     *
+     * @param pageDictionary A page dictionary in a PDF document.
+     */
+    PDPage(COSDictionary pageDictionary, ResourceCache resourceCache)
+    {
+        page = pageDictionary;
+        this.resourceCache = resourceCache;
+    }
+
+    /**
      * Convert this standard java object to a COS object.
      * 
      * @return The cos object that matches this Java object.
@@ -128,7 +140,7 @@ public class PDPage implements COSObject
             // note: it's an error for resources to not be present
             if (resources != null)
             {
-                pageResources = new PDResources(resources);
+                pageResources = new PDResources(resources, resourceCache);
             }
         }
         return pageResources;
@@ -620,4 +632,12 @@ public class PDPage implements COSObject
     {
         return page.hashCode();
     }
+
+    /**
+     * Returns the resource cache associated with this page, or null if there is none.
+     */
+    public ResourceCache getResourceCache()
+    {
+        return resourceCache;
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageTree.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageTree.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageTree.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageTree.java Thu Jul  9 08:22:48 2015
@@ -38,6 +38,7 @@ import java.util.List;
 public class PDPageTree implements COSObjectable, Iterable<PDPage>
 {
     private final COSDictionary root;
+    private final PDDocument document; // optional
 
     /**
      * Constructor for embedding.
@@ -48,6 +49,7 @@ public class PDPageTree implements COSOb
         root.setItem(COSName.TYPE, COSName.PAGES);
         root.setItem(COSName.KIDS, new COSArray());
         root.setItem(COSName.COUNT, COSInteger.ZERO);
+        document = null;
     }
 
     /**
@@ -62,6 +64,23 @@ public class PDPageTree implements COSOb
             throw new IllegalArgumentException("root cannot be null");
         }
         this.root = root;
+        document = null;
+    }
+    
+    /**
+     * Constructor for reading.
+     *
+     * @param root A page tree root.
+     * @param document The document which contains "root".
+     */
+    PDPageTree(COSDictionary root, PDDocument document)
+    {
+        if (root == null)
+        {
+            throw new IllegalArgumentException("root cannot be null");
+        }
+        this.root = root;
+        this.document = document;
     }
 
     /**
@@ -166,7 +185,8 @@ public class PDPageTree implements COSOb
                 throw new IllegalStateException("Expected Page but got " + next);
             }
 
-            return new PDPage(next);
+            ResourceCache resourceCache = document != null ? document.getResourceCache() : null;
+            return new PDPage(next, resourceCache);
         }
 
         @Override
@@ -191,7 +211,8 @@ public class PDPageTree implements COSOb
             throw new IllegalStateException("Expected Page but got " + dict);
         }
 
-        return new PDPage(dict);
+        ResourceCache resourceCache = document != null ? document.getResourceCache() : null;
+        return new PDPage(dict, resourceCache);
     }
 
     /**

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java Thu Jul  9 08:22:48 2015
@@ -45,6 +45,7 @@ import org.apache.pdfbox.pdmodel.graphic
 public final class PDResources implements COSObjectable
 {
     private final COSDictionary resources;
+    private final ResourceCache cache;
 
     /**
      * Constructor for embedding.
@@ -52,16 +53,14 @@ public final class PDResources implement
     public PDResources()
     {
         resources = new COSDictionary();
+        cache = null;
     }
 
     /**
      * Constructor for reading.
-     * 
+     *
      * @param resourceDictionary The cos dictionary for this resource.
      */
-    // todo: replace this constructor with a static factory which can cache PDResources at will
-    //       also it should probably take a COSBase so that it is indirect-object aware.
-    //       It might also want to have some context, e.g. knowing what the parent of the resources is?
     public PDResources(COSDictionary resourceDictionary)
     {
         if (resourceDictionary == null)
@@ -69,6 +68,23 @@ public final class PDResources implement
             throw new IllegalArgumentException("resourceDictionary is null");
         }
         resources = resourceDictionary;
+        cache = null;
+    }
+    
+    /**
+     * Constructor for reading.
+     *
+     * @param resourceDictionary The cos dictionary for this resource.
+     * @param resourceCache The document's resource cache, may be null.
+     */
+    public PDResources(COSDictionary resourceDictionary, ResourceCache resourceCache)
+    {
+        if (resourceDictionary == null)
+        {
+            throw new IllegalArgumentException("resourceDictionary is null");
+        }
+        resources = resourceDictionary;
+        cache = resourceCache;
     }
 
     /**
@@ -82,18 +98,34 @@ public final class PDResources implement
 
     /**
      * Returns the font resource with the given name, or null if none exists.
-     * 
+     *
      * @param name Name of the font resource.
      * @throws java.io.IOException if something went wrong.
      */
     public PDFont getFont(COSName name) throws IOException
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDFont cached = cache.getFont(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
+        PDFont font = null;
         COSDictionary dict = (COSDictionary)get(COSName.FONT, name);
-        if (dict == null)
+        if (dict != null)
         {
-            return null;
+            font = PDFontFactory.createFont(dict);
+        }
+        
+        if (cache != null)
+        {
+            cache.put(indirect, font);
         }
-        return PDFontFactory.createFont(dict);
+        return font;
     }
 
     /**
@@ -104,18 +136,35 @@ public final class PDResources implement
      */
     public PDColorSpace getColorSpace(COSName name) throws IOException
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDColorSpace cached = cache.getColorSpace(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
         // get the instance
+        PDColorSpace colorSpace;
         COSBase object = get(COSName.COLORSPACE, name);
         if (object != null)
         {
-            return PDColorSpace.create(object, this);
+            colorSpace = PDColorSpace.create(object, this);
         }
         else
         {
-            return PDColorSpace.create(name, this);
+            colorSpace = PDColorSpace.create(name, this);
         }
-    }
 
+        if (cache != null)
+        {
+            cache.put(indirect, colorSpace);
+        }
+        return colorSpace;
+    }
+    
     /**
      * Returns true if the given color space name exists in these resources.
      *
@@ -134,12 +183,29 @@ public final class PDResources implement
      */
     public PDExtendedGraphicsState getExtGState(COSName name)
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDExtendedGraphicsState cached = cache.getExtGState(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
+        // get the instance
+        PDExtendedGraphicsState extGState = null;
         COSDictionary dict = (COSDictionary)get(COSName.EXT_G_STATE, name);
-        if (dict == null)
+        if (dict != null)
         {
-            return null;
+            extGState = new PDExtendedGraphicsState(dict);
+        }
+
+        if (cache != null)
+        {
+            cache.put(indirect, extGState);
         }
-        return new PDExtendedGraphicsState(dict);
+        return extGState;
     }
 
     /**
@@ -150,12 +216,29 @@ public final class PDResources implement
      */
     public PDShading getShading(COSName name) throws IOException
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDShading cached = cache.getShading(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
+        // get the instance
+        PDShading shading = null;
         COSDictionary dict = (COSDictionary)get(COSName.SHADING, name);
-        if (dict == null)
+        if (dict != null)
         {
-            return null;
+            shading = PDShading.create(dict);
+        }
+        
+        if (cache != null)
+        {
+            cache.put(indirect, shading);
         }
-        return PDShading.create(dict);
+        return shading;
     }
 
     /**
@@ -166,12 +249,29 @@ public final class PDResources implement
      */
     public PDAbstractPattern getPattern(COSName name) throws IOException
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDAbstractPattern cached = cache.getPattern(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
+        // get the instance
+        PDAbstractPattern pattern = null;
         COSDictionary dict = (COSDictionary)get(COSName.PATTERN, name);
-        if (dict == null)
+        if (dict != null)
         {
-            return null;
+            pattern = PDAbstractPattern.create(dict);
+        }
+
+        if (cache != null)
+        {
+            cache.put(indirect, pattern);
         }
-        return PDAbstractPattern.create(dict);
+        return pattern;
     }
 
     /**
@@ -181,12 +281,29 @@ public final class PDResources implement
      */
     public PDPropertyList getProperties(COSName name)
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDPropertyList cached = cache.getProperties(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
+        // get the instance
+        PDPropertyList propertyList = null;
         COSDictionary dict = (COSDictionary)get(COSName.PROPERTIES, name);
-        if (dict == null)
+        if (dict != null)
         {
-            return null;
+            propertyList = PDPropertyList.create(dict);
         }
-        return PDPropertyList.create(dict);
+
+        if (cache != null)
+        {
+            cache.put(indirect, propertyList);
+        }
+        return propertyList;
     }
 
     /**
@@ -197,26 +314,53 @@ public final class PDResources implement
      */
     public PDXObject getXObject(COSName name) throws IOException
     {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null)
+        {
+            PDXObject cached = cache.getXObject(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+
+        // get the instance
+        PDXObject xobject;
         COSBase value = get(COSName.XOBJECT, name);
         if (value == null)
         {
-            return null;
+            xobject = null;
         }
         else if (value instanceof COSObject)
         {
-            COSObject object = (COSObject)value;
-            // add the object number to create an unique identifier
-            String id = name.getName();
-            id += "#" + object.getObjectNumber();
-            return PDXObject.createXObject(object.getObject(), id, this);
+            xobject = PDXObject.createXObject(((COSObject) value).getObject(), this);
         }
         else
         {
-            return PDXObject.createXObject(value, name.getName(), this);
+            xobject = PDXObject.createXObject(value, this);
         }
+
+        if (cache != null)
+        {
+            cache.put(indirect, xobject);
+        }
+        return xobject;
     }
 
     /**
+     * Returns the resource with the given name and kind as an indirect object, or null.
+     */
+    private COSObject getIndirect(COSName kind, COSName name)
+    {
+        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
+        if (dict == null)
+        {
+            return null;
+        }
+        return (COSObject)dict.getItem(name);
+    }
+    
+    /**
      * Returns the resource with the given name and kind, or null.
      */
     private COSBase get(COSName kind, COSName name)
@@ -545,4 +689,12 @@ public final class PDResources implement
     {
         put(COSName.XOBJECT, name, xobject);
     }
+
+    /**
+     * Returns the resource cache associated with the Resources, or null if there is none.
+     */
+    public ResourceCache getResourceCache()
+    {
+        return cache;
+    }
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java?rev=1690015&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java Thu Jul  9 08:22:48 2015
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.COSObject;
+import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.graphics.PDXObject;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
+import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
+import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
+
+/**
+ * A document-wide cache for page resources.
+ *
+ * @author John Hewson
+ */
+public interface ResourceCache
+{
+    /**
+     * Returns the font resource for the given indirect object, if it is in the cache.
+     */
+    PDFont getFont(COSObject indirect) throws IOException;
+
+    /**
+     * Returns the color space resource for the given indirect object, if it is in the cache.
+     */
+    PDColorSpace getColorSpace(COSObject indirect) throws IOException;
+
+    /**
+     * Returns the external graphics state resource for the given indirect object, if it is in the
+     * cache.
+     */
+    PDExtendedGraphicsState getExtGState(COSObject indirect);
+        
+    /**
+     * Returns the shading resource for the given indirect object, if it is in the cache.
+     */
+    PDShading getShading(COSObject indirect) throws IOException;
+    
+    /**
+     *Returns the pattern resource for the given indirect object, if it is in the cache.
+     */
+    PDAbstractPattern getPattern(COSObject indirect) throws IOException;
+        
+    /**
+     * Returns the property list resource for the given indirect object, if it is in the cache.
+     */
+    PDPropertyList getProperties(COSObject indirect);
+        
+    /**
+     * Returns the XObject resource for the given indirect object, if it is in the cache.
+     */
+    PDXObject getXObject(COSObject indirect) throws IOException;
+
+    /**
+     * Puts the given indirect font resource in the cache.
+     */
+    void put(COSObject indirect, PDFont font) throws IOException;
+
+    /**
+     * Puts the given indirect color space resource in the cache.
+     */
+    void put(COSObject indirect, PDColorSpace colorSpace) throws IOException;
+
+    /**
+     * Puts the given indirect extended graphics state resource in the cache.
+     */
+    void put(COSObject indirect, PDExtendedGraphicsState extGState);
+
+    /**
+     * Puts the given indirect shading resource in the cache.
+     */
+    void put(COSObject indirect, PDShading shading) throws IOException;
+
+    /**
+     * Puts the given indirect pattern resource in the cache.
+     */
+    void put(COSObject indirect, PDAbstractPattern pattern) throws IOException;
+
+    /**
+     * Puts the given indirect property list resource in the cache.
+     */
+    void put(COSObject indirect, PDPropertyList propertyList);
+    
+    /**
+     * Puts the given indirect XObject resource in the cache.
+     */
+    void put(COSObject indirect, PDXObject xobject) throws IOException;
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java Thu Jul  9 08:22:48 2015
@@ -88,7 +88,7 @@ public class PDObjectReference implement
         }
         try
         {
-            PDXObject xobject = PDXObject.createXObject(obj, null, null); // <-- TODO: valid?
+            PDXObject xobject = PDXObject.createXObject(obj, null); // <-- TODO: valid?
             if (xobject != null)
             {
                 return xobject;

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDXObject.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDXObject.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDXObject.java Thu Jul  9 08:22:48 2015
@@ -45,8 +45,7 @@ public class PDXObject implements COSObj
      * @return A new XObject instance.
      * @throws java.io.IOException if there is an error creating the XObject.
      */
-    public static PDXObject createXObject(COSBase base, String name, PDResources resources)
-            throws IOException
+    public static PDXObject createXObject(COSBase base, PDResources resources) throws IOException
     {
         if (base == null)
         {
@@ -68,7 +67,7 @@ public class PDXObject implements COSObj
         }
         else if (COSName.FORM.getName().equals(subtype))
         {
-            return new PDFormXObject(new PDStream(stream), name);
+            return new PDFormXObject(new PDStream(stream), resources.getResourceCache());
         }
         else if (COSName.PS.getName().equals(subtype))
         {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java Thu Jul  9 08:22:48 2015
@@ -26,6 +26,7 @@ import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.ResourceCache;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 import org.apache.pdfbox.pdmodel.graphics.PDXObject;
@@ -52,10 +53,8 @@ final and all fields private.
  */
 public class PDFormXObject extends PDXObject implements PDContentStream
 {
-    // name of XObject in resources, to prevent recursion
-    private String name;
-
     private PDGroup group;
+    private final ResourceCache cache;
 
     /**
      * Creates a Form XObject for reading.
@@ -64,19 +63,19 @@ public class PDFormXObject extends PDXOb
     public PDFormXObject(PDStream stream)
     {
         super(stream, COSName.FORM);
+        cache = null;
     }
 
     /**
      * Creates a Form XObject for reading.
      * @param stream The XObject stream
-     * @param name The name of the form XObject, to prevent recursion.
      */
-    public PDFormXObject(PDStream stream, String name)
+    public PDFormXObject(PDStream stream, ResourceCache cache)
     {
         super(stream, COSName.FORM);
-        this.name = name;
+        this.cache = cache;
     }
-
+    
     /**
      * Creates a Form Image XObject for writing, in the given document.
      * @param document The current document
@@ -84,6 +83,7 @@ public class PDFormXObject extends PDXOb
     public PDFormXObject(PDDocument document)
     {
         super(document, COSName.FORM);
+        cache = null;
     }
 
     /**
@@ -140,7 +140,7 @@ public class PDFormXObject extends PDXOb
         COSDictionary resources = (COSDictionary) getCOSStream().getDictionaryObject(COSName.RESOURCES);
         if (resources != null)
         {
-            return new PDResources(resources);
+            return new PDResources(resources, cache);
         }
         return null;
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java Thu Jul  9 08:22:48 2015
@@ -59,7 +59,7 @@ public final class PDImageXObject extend
 
     private SoftReference<BufferedImage> cachedImage;
     private PDColorSpace colorSpace;
-    private PDResources resources; // current resource dictionary (has color spaces)
+    private final PDResources resources; // current resource dictionary (has color spaces)
 
     /**
      * Creates a thumbnail Image XObject from the given COSBase and name.

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java Thu Jul  9 08:22:48 2015
@@ -115,7 +115,7 @@ public final class PDSoftMask implements
             if (cosGroup != null)
             {
                 group = (PDFormXObject) PDXObject
-                        .createXObject(cosGroup, COSName.G.getName(), null);
+                        .createXObject(cosGroup, null);
             }
         }
         return group;

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceCharacteristicsDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceCharacteristicsDictionary.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceCharacteristicsDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAppearanceCharacteristicsDictionary.java Thu Jul  9 08:22:48 2015
@@ -190,7 +190,7 @@ public class PDAppearanceCharacteristics
         COSBase i = this.getCOSObject().getDictionaryObject("I");
         if (i instanceof COSStream)
         {
-            return new PDFormXObject(new PDStream((COSStream) i), "I");
+            return new PDFormXObject(new PDStream((COSStream) i));
         }
         return null;
     }
@@ -205,7 +205,7 @@ public class PDAppearanceCharacteristics
         COSBase i = this.getCOSObject().getDictionaryObject("RI");
         if (i instanceof COSStream)
         {
-            return new PDFormXObject(new PDStream((COSStream) i), "RI");
+            return new PDFormXObject(new PDStream((COSStream) i));
         }
         return null;
     }
@@ -220,7 +220,7 @@ public class PDAppearanceCharacteristics
         COSBase i = this.getCOSObject().getDictionaryObject("IX");
         if (i instanceof COSStream)
         {
-            return new PDFormXObject(new PDStream((COSStream) i), "IX");
+            return new PDFormXObject(new PDStream((COSStream) i));
         }
         return null;
     }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java Thu Jul  9 08:22:48 2015
@@ -197,7 +197,7 @@ public abstract class AnnotationValidato
 
                 // Appearance stream is a XObjectForm, check it.
                 ContextHelper.validateElement(ctx, new PDFormXObject(
-                        new PDStream(COSUtils.getAsStream(apn, cosDocument)), "N"),
+                        new PDStream(COSUtils.getAsStream(apn, cosDocument))),
                         GRAPHIC_PROCESS);
             }
         } // else ok, nothing to check,this field is optional

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/reflect/ResourcesValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/reflect/ResourcesValidationProcess.java?rev=1690015&r1=1690014&r2=1690015&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/reflect/ResourcesValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/reflect/ResourcesValidationProcess.java Thu Jul  9 08:22:48 2015
@@ -21,17 +21,10 @@
 
 package org.apache.pdfbox.preflight.process.reflect;
 
-import static org.apache.pdfbox.preflight.PreflightConfiguration.EXTGSTATE_PROCESS;
-import static org.apache.pdfbox.preflight.PreflightConfiguration.FONT_PROCESS;
-import static org.apache.pdfbox.preflight.PreflightConfiguration.GRAPHIC_PROCESS;
-import static org.apache.pdfbox.preflight.PreflightConfiguration.SHADING_PATTERN_PROCESS;
-import static org.apache.pdfbox.preflight.PreflightConfiguration.TILING_PATTERN_PROCESS;
-
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
-
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSDocument;
@@ -40,14 +33,11 @@ import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.font.PDFont;
 import org.apache.pdfbox.pdmodel.font.PDFontFactory;
+import org.apache.pdfbox.pdmodel.graphics.PDXObject;
 import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
 import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
 import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
-import org.apache.pdfbox.pdmodel.graphics.PDXObject;
 import org.apache.pdfbox.preflight.PreflightConstants;
-import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_INVALID_PATTERN_DEFINITION;
-import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_MAIN;
-import static org.apache.pdfbox.preflight.PreflightConstants.TRANPARENCY_DICTIONARY_KEY_EXTGSTATE;
 import org.apache.pdfbox.preflight.PreflightContext;
 import org.apache.pdfbox.preflight.PreflightPath;
 import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
@@ -56,6 +46,16 @@ import org.apache.pdfbox.preflight.proce
 import org.apache.pdfbox.preflight.utils.COSUtils;
 import org.apache.pdfbox.preflight.utils.ContextHelper;
 
+
+import static org.apache.pdfbox.preflight.PreflightConfiguration.EXTGSTATE_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConfiguration.FONT_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConfiguration.GRAPHIC_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConfiguration.SHADING_PATTERN_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConfiguration.TILING_PATTERN_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_INVALID_PATTERN_DEFINITION;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_GRAPHIC_MAIN;
+import static org.apache.pdfbox.preflight.PreflightConstants.TRANPARENCY_DICTIONARY_KEY_EXTGSTATE;
+
 public class ResourcesValidationProcess extends AbstractProcess
 {
 
@@ -283,7 +283,7 @@ public class ResourcesValidationProcess
                     try
                     {
                         COSStream stream = COSUtils.getAsStream(xobj, cosDocument);
-                        PDXObject pdXObject = PDXObject.createXObject(stream, entry.getKey().getName(), resources);
+                        PDXObject pdXObject = PDXObject.createXObject(stream, resources);
                         if (pdXObject != null)
                         {
                             ContextHelper.validateElement(context, pdXObject, GRAPHIC_PROCESS);