pdfbox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From til...@apache.org
Subject svn commit: r1755396 - /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java
Date Sat, 06 Aug 2016 13:11:38 GMT
Author: tilman
Date: Sat Aug  6 13:11:38 2016
New Revision: 1755396

URL: http://svn.apache.org/viewvc?rev=1755396&view=rev
Log:
PDFBOX-3442: cache direct fonts

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java

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=1755396&r1=1755395&r2=1755396&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 Sat Aug 
6 13:11:38 2016
@@ -1,751 +1,775 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.pdfbox.pdmodel;
-
-import java.io.IOException;
-import java.util.Collections;
-
-import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.cos.COSObject;
-import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.pdmodel.common.COSObjectable;
-import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
-import org.apache.pdfbox.pdmodel.font.PDFont;
-import org.apache.pdfbox.pdmodel.font.PDFontFactory;
-import org.apache.pdfbox.pdmodel.graphics.color.PDPattern;
-import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
-import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup;
-import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
-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.image.PDImageXObject;
-import org.apache.pdfbox.pdmodel.graphics.PDXObject;
-
-/**
- * A set of resources available at the page/pages/stream level.
- * 
- * @author Ben Litchfield
- * @author John Hewson
- */
-public final class PDResources implements COSObjectable
-{
-    private final COSDictionary resources;
-    private final ResourceCache cache;
-
-    /**
-     * Constructor for embedding.
-     */
-    public PDResources()
-    {
-        resources = new COSDictionary();
-        cache = null;
-    }
-
-    /**
-     * Constructor for reading.
-     *
-     * @param resourceDictionary The cos dictionary for this resource.
-     */
-    public PDResources(COSDictionary resourceDictionary)
-    {
-        if (resourceDictionary == null)
-        {
-            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;
-    }
-
-    /**
-     * Returns the underlying dictionary.
-     */
-    @Override
-    public COSDictionary getCOSObject()
-    {
-        return resources;
-    }
-
-    /**
-     * 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 && indirect != null)
-        {
-            PDFont cached = cache.getFont(indirect);
-            if (cached != null)
-            {
-                return cached;
-            }
-        }
-
-        PDFont font = null;
-        COSDictionary dict = (COSDictionary)get(COSName.FONT, name);
-        if (dict != null)
-        {
-            font = PDFontFactory.createFont(dict);
-        }
-        
-        if (cache != null)
-        {
-            cache.put(indirect, font);
-        }
-        return font;
-    }
-
-    /**
-     * Returns the color space resource with the given name, or null if none exists.
-     * 
-     * @param name Name of the color space resource.
-     * @return a new color space.
-     * @throws IOException if something went wrong.
-     */
-    public PDColorSpace getColorSpace(COSName name) throws IOException
-    {
-        return getColorSpace(name, false);
-    }
-    
-    /**
-     * Returns the color space resource with the given name, or null if none exists. This
method is
-     * for PDFBox internal use only, others should use {@link #getColorSpace(COSName)}.
-     *
-     * @param name Name of the color space resource.
-     * @param wasDefault if current color space was used by a default color space. This parameter
is
-     * to
-     * @return a new color space.
-     * @throws IOException if something went wrong.
-     */
-    public PDColorSpace getColorSpace(COSName name, boolean wasDefault) throws IOException
-    {
-        COSObject indirect = getIndirect(COSName.COLORSPACE, name);
-        if (cache != null && indirect != 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)
-        {
-            colorSpace = PDColorSpace.create(object, this, wasDefault);
-        }
-        else
-        {
-            colorSpace = PDColorSpace.create(name, this, wasDefault);
-        }
-
-        // we can't cache PDPattern, because it holds page resources, see PDFBOX-2370
-        if (cache != null && !(colorSpace instanceof PDPattern))
-        {
-            cache.put(indirect, colorSpace);
-        }
-        return colorSpace;
-    }
-    
-    /**
-     * Returns true if the given color space name exists in these resources.
-     *
-     * @param name Name of the color space resource.
-     */
-    public boolean hasColorSpace(COSName name)
-    {
-        return get(COSName.COLORSPACE, name) != null;
-    }
-
-    /**
-     * Returns the extended graphics state resource with the given name, or null
-     * if none exists.
-     *
-     * @param name Name of the graphics state resource.
-     */
-    public PDExtendedGraphicsState getExtGState(COSName name)
-    {
-        COSObject indirect = getIndirect(COSName.EXT_G_STATE, name);
-        if (cache != null && indirect != 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)
-        {
-            extGState = new PDExtendedGraphicsState(dict);
-        }
-
-        if (cache != null)
-        {
-            cache.put(indirect, extGState);
-        }
-        return extGState;
-    }
-
-    /**
-     * Returns the shading resource with the given name, or null if none exists.
-     *
-     * @param name Name of the shading resource.
-     * @throws java.io.IOException if something went wrong.
-     */
-    public PDShading getShading(COSName name) throws IOException
-    {
-        COSObject indirect = getIndirect(COSName.SHADING, name);
-        if (cache != null && indirect != 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)
-        {
-            shading = PDShading.create(dict);
-        }
-        
-        if (cache != null)
-        {
-            cache.put(indirect, shading);
-        }
-        return shading;
-    }
-
-    /**
-     * Returns the pattern resource with the given name, or null if none exists.
-     * 
-     * @param name Name of the pattern resource.
-     * @throws java.io.IOException if something went wrong.
-     */
-    public PDAbstractPattern getPattern(COSName name) throws IOException
-    {
-        COSObject indirect = getIndirect(COSName.PATTERN, name);
-        if (cache != null && indirect != 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)
-        {
-            pattern = PDAbstractPattern.create(dict);
-        }
-
-        if (cache != null)
-        {
-            cache.put(indirect, pattern);
-        }
-        return pattern;
-    }
-
-    /**
-     * Returns the property list resource with the given name, or null if none exists.
-     * 
-     * @param name Name of the property list resource.
-     */
-    public PDPropertyList getProperties(COSName name)
-    {
-        COSObject indirect = getIndirect(COSName.PROPERTIES, name);
-        if (cache != null && indirect != 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)
-        {
-            propertyList = PDPropertyList.create(dict);
-        }
-
-        if (cache != null)
-        {
-            cache.put(indirect, propertyList);
-        }
-        return propertyList;
-    }
-
-    /**
-     * Tells whether the XObject resource with the given name is an image.
-     *
-     * @param name Name of the XObject resource.
-     * @return true if it is an image XObject, false if not.
-     */
-    public boolean isImageXObject(COSName name)
-    {
-        // get the instance
-        COSBase value = get(COSName.XOBJECT, name);
-        if (value == null)
-        {
-            return false;
-        }
-        else if (value instanceof COSObject)
-        {
-            value = ((COSObject) value).getObject();
-        }
-        if (!(value instanceof COSStream))
-        {
-            return false;
-        }
-        COSStream stream = (COSStream) value;
-        return COSName.IMAGE.equals(stream.getCOSName(COSName.SUBTYPE));
-    }
-
-    /**
-     * Returns the XObject resource with the given name, or null if none exists.
-     * 
-     * @param name Name of the XObject resource.
-     * @throws java.io.IOException if something went wrong.
-     */
-    public PDXObject getXObject(COSName name) throws IOException
-    {
-        COSObject indirect = getIndirect(COSName.XOBJECT, name);
-        if (cache != null && indirect != 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)
-        {
-            xobject = null;
-        }
-        else if (value instanceof COSObject)
-        {
-            xobject = PDXObject.createXObject(((COSObject) value).getObject(), this);
-        }
-        else
-        {
-            xobject = PDXObject.createXObject(value, this);
-        }
-
-        // we can't cache PDImageXObject, because it holds page resources, see PDFBOX-2370
-        if (cache != null && !(xobject instanceof PDImageXObject))
-        {
-            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;
-        }
-        COSBase base = dict.getItem(name);
-        if (base instanceof COSObject)
-        {
-            return (COSObject)base;
-        }
-        return null;
-    }
-    
-    /**
-     * Returns the resource with the given name and kind, or null.
-     */
-    private COSBase get(COSName kind, COSName name)
-    {
-        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
-        if (dict == null)
-        {
-            return null;
-        }
-        return dict.getDictionaryObject(name);
-    }
-
-    /**
-     * Returns the names of the color space resources, if any.
-     */
-    public Iterable<COSName> getColorSpaceNames()
-    {
-        return getNames(COSName.COLORSPACE);
-    }
-
-    /**
-     * Returns the names of the XObject resources, if any.
-     */
-    public Iterable<COSName> getXObjectNames()
-    {
-        return getNames(COSName.XOBJECT);
-    }
-
-    /**
-     * Returns the names of the font resources, if any.
-     */
-    public Iterable<COSName> getFontNames()
-    {
-        return getNames(COSName.FONT);
-    }
-
-    /**
-     * Returns the names of the property list resources, if any.
-     */
-    public Iterable<COSName> getPropertiesNames()
-    {
-        return getNames(COSName.PROPERTIES);
-    }
-
-    /**
-     * Returns the names of the shading resources, if any.
-     */
-    public Iterable<COSName> getShadingNames()
-    {
-        return getNames(COSName.SHADING);
-    }
-
-    /**
-     * Returns the names of the pattern resources, if any.
-     */
-    public Iterable<COSName> getPatternNames()
-    {
-        return getNames(COSName.PATTERN);
-    }
-
-    /**
-     * Returns the names of the extended graphics state resources, if any.
-     */
-    public Iterable<COSName> getExtGStateNames()
-    {
-        return getNames(COSName.EXT_G_STATE);
-    }
-
-    /**
-     * Returns the resource names of the given kind.
-     */
-    private Iterable<COSName> getNames(COSName kind)
-    {
-        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
-        if (dict == null)
-        {
-            return Collections.emptySet();
-        }
-        return dict.keySet();
-    }
-
-    /**
-     * Adds the given font to the resources of the current page and returns the name for
the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param font the font to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDFont font)
-    {
-        return add(COSName.FONT, "F", font);
-    }
-
-    /**
-     * Adds the given color space to the resources of the current page and returns the name
for the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param colorSpace the color space to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDColorSpace colorSpace)
-    {
-        return add(COSName.COLORSPACE, "cs", colorSpace);
-    }
-
-    /**
-     * Adds the given extended graphics state to the resources of the current page and returns
the
-     * name for the new resources. Returns the existing resource name if the given item already
exists.
-     *
-     * @param extGState the extended graphics state to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDExtendedGraphicsState extGState)
-    {
-        return add(COSName.EXT_G_STATE, "gs", extGState);
-    }
-
-    /**
-     * Adds the given shading to the resources of the current page and returns the name for
the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param shading the shading to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDShading shading)
-    {
-        return add(COSName.SHADING, "sh", shading);
-    }
-
-    /**
-     * Adds the given pattern to the resources of the current page and returns the name for
the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param pattern the pattern to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDAbstractPattern pattern)
-    {
-        return add(COSName.PATTERN, "p", pattern);
-    }
-
-    /**
-     * Adds the given property list to the resources of the current page and returns the
name for
-     * the new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param properties the property list to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDPropertyList properties)
-    {
-        if (properties instanceof PDOptionalContentGroup)
-        {
-            return add(COSName.PROPERTIES, "oc", properties);
-        }
-        else
-        {
-            return add(COSName.PROPERTIES, "Prop", properties);
-        }
-    }
-
-    /**
-     * Adds the given image to the resources of the current page and returns the name for
the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param image the image to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDImageXObject image)
-    {
-        return add(COSName.XOBJECT, "Im", image);
-    }
-
-    /**
-     * Adds the given form to the resources of the current page and returns the name for
the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param form the form to add
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDFormXObject form)
-    {
-        return add(COSName.XOBJECT, "Form", form);
-    }
-
-    /**
-     * Adds the given XObject to the resources of the current page and returns the name for
the
-     * new resources. Returns the existing resource name if the given item already exists.
-     *
-     * @param xobject the XObject to add
-     * @param prefix the prefix to be used when creating the resource name
-     * @return the name of the resource in the resources dictionary
-     */
-    public COSName add(PDXObject xobject, String prefix)
-    {
-        return add(COSName.XOBJECT, prefix, xobject);
-    }
-
-    /**
-     * Adds the given resource if it does not already exist.
-     */
-    private COSName add(COSName kind, String prefix, COSObjectable object)
-    {
-        // return the existing key if the item exists already
-        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
-        if (dict != null && dict.containsValue(object.getCOSObject()))
-        {
-            return dict.getKeyForValue(object.getCOSObject());
-        }
-
-        // add the item with a new key
-        COSName name = createKey(kind, prefix);
-        put(kind, name, object);
-        return name;
-    }
-
-    /**
-     * Returns a unique key for a new resource.
-     */
-    private COSName createKey(COSName kind, String prefix)
-    {
-        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
-        if (dict == null)
-        {
-            return COSName.getPDFName(prefix + 1);
-        }
-
-        // find a unique key
-        String key;
-        int n = dict.keySet().size();
-        do
-        {
-            ++n;
-            key = prefix + n;
-        }
-        while (dict.containsKey(key));
-        return COSName.getPDFName(key);
-    }
-
-    /**
-     * Sets the value of a given named resource.
-     */
-    private void put(COSName kind, COSName name, COSObjectable object)
-    {
-        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
-        if (dict == null)
-        {
-            dict = new COSDictionary();
-            resources.setItem(kind, dict);
-        }
-        dict.setItem(name, object);
-    }
-
-    /**
-     * Sets the font resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param font the font to be added
-     */
-    public void put(COSName name, PDFont font)
-    {
-        put(COSName.FONT, name, font);
-    }
-
-    /**
-     * Sets the color space resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param colorSpace the color space to be added
-     */
-    public void put(COSName name, PDColorSpace colorSpace)
-    {
-        put(COSName.COLORSPACE, name, colorSpace);
-    }
-
-    /**
-     * Sets the extended graphics state resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param extGState the extended graphics state to be added
-     */
-    public void put(COSName name, PDExtendedGraphicsState extGState)
-    {
-        put(COSName.EXT_G_STATE, name, extGState);
-    }
-
-    /**
-     * Sets the shading resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param shading the shading to be added
-     */
-    public void put(COSName name, PDShading shading)
-    {
-        put(COSName.SHADING, name, shading);
-    }
-
-    /**
-     * Sets the pattern resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param pattern the pattern to be added
-     */
-    public void put(COSName name, PDAbstractPattern pattern)
-    {
-        put(COSName.PATTERN, name, pattern);
-    }
-
-    /**
-     * Sets the property list resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param properties the property list to be added
-     */
-    public void put(COSName name, PDPropertyList properties)
-    {
-        put(COSName.PROPERTIES, name, properties);
-    }
-
-    /**
-     * Sets the XObject resource with the given name.
-     *
-     * @param name the name of the resource
-     * @param xobject the XObject to be added
-     */
-    public void put(COSName name, PDXObject xobject)
-    {
-        put(COSName.XOBJECT, name, xobject);
-    }
-
-    /**
-     * Returns the resource cache associated with the Resources, or null if there is none.
-     */
-    public ResourceCache getResourceCache()
-    {
-        return cache;
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontFactory;
+import org.apache.pdfbox.pdmodel.graphics.color.PDPattern;
+import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
+import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup;
+import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
+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.image.PDImageXObject;
+import org.apache.pdfbox.pdmodel.graphics.PDXObject;
+
+/**
+ * A set of resources available at the page/pages/stream level.
+ * 
+ * @author Ben Litchfield
+ * @author John Hewson
+ */
+public final class PDResources implements COSObjectable
+{
+    private final COSDictionary resources;
+    private final ResourceCache cache;
+    
+    // PDFBOX-3442 cache fonts that are not indirect objects, as these aren't cached in ResourceCache
+    // and this would result in huge memory footprint in text extraction
+    private final Map <COSName,SoftReference<PDFont>> directFontCache = 
+            new HashMap<COSName, SoftReference<PDFont>>();
+
+    /**
+     * Constructor for embedding.
+     */
+    public PDResources()
+    {
+        resources = new COSDictionary();
+        cache = null;
+    }
+
+    /**
+     * Constructor for reading.
+     *
+     * @param resourceDictionary The cos dictionary for this resource.
+     */
+    public PDResources(COSDictionary resourceDictionary)
+    {
+        if (resourceDictionary == null)
+        {
+            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;
+    }
+
+    /**
+     * Returns the underlying dictionary.
+     */
+    @Override
+    public COSDictionary getCOSObject()
+    {
+        return resources;
+    }
+
+    /**
+     * Returns the font resource with the given name, or null if none exists.
+     *
+     * @param name Name of the font resource.
+     * @throws IOException if something went wrong.
+     */
+    public PDFont getFont(COSName name) throws IOException
+    {
+        COSObject indirect = getIndirect(COSName.FONT, name);
+        if (cache != null && indirect != null)
+        {
+            PDFont cached = cache.getFont(indirect);
+            if (cached != null)
+            {
+                return cached;
+            }
+        }
+        else if (indirect == null)
+        {
+            SoftReference<PDFont> ref = directFontCache.get(name);
+            if (ref != null)
+            {
+                PDFont cached = ref.get();
+                if (cached != null)
+                {
+                    return cached;
+                }
+            }
+        }
+
+        PDFont font = null;
+        COSDictionary dict = (COSDictionary)get(COSName.FONT, name);
+        if (dict != null)
+        {
+            font = PDFontFactory.createFont(dict);
+        }
+        
+        if (cache != null && indirect != null)
+        {
+            cache.put(indirect, font);
+        }
+        else if (indirect == null)
+        {
+            directFontCache.put(name, new SoftReference<PDFont>(font));
+        }
+        return font;
+    }
+
+    /**
+     * Returns the color space resource with the given name, or null if none exists.
+     * 
+     * @param name Name of the color space resource.
+     * @return a new color space.
+     * @throws IOException if something went wrong.
+     */
+    public PDColorSpace getColorSpace(COSName name) throws IOException
+    {
+        return getColorSpace(name, false);
+    }
+    
+    /**
+     * Returns the color space resource with the given name, or null if none exists. This
method is
+     * for PDFBox internal use only, others should use {@link #getColorSpace(COSName)}.
+     *
+     * @param name Name of the color space resource.
+     * @param wasDefault if current color space was used by a default color space. This parameter
is
+     * to
+     * @return a new color space.
+     * @throws IOException if something went wrong.
+     */
+    public PDColorSpace getColorSpace(COSName name, boolean wasDefault) throws IOException
+    {
+        COSObject indirect = getIndirect(COSName.COLORSPACE, name);
+        if (cache != null && indirect != 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)
+        {
+            colorSpace = PDColorSpace.create(object, this, wasDefault);
+        }
+        else
+        {
+            colorSpace = PDColorSpace.create(name, this, wasDefault);
+        }
+
+        // we can't cache PDPattern, because it holds page resources, see PDFBOX-2370
+        if (cache != null && !(colorSpace instanceof PDPattern))
+        {
+            cache.put(indirect, colorSpace);
+        }
+        return colorSpace;
+    }
+    
+    /**
+     * Returns true if the given color space name exists in these resources.
+     *
+     * @param name Name of the color space resource.
+     */
+    public boolean hasColorSpace(COSName name)
+    {
+        return get(COSName.COLORSPACE, name) != null;
+    }
+
+    /**
+     * Returns the extended graphics state resource with the given name, or null
+     * if none exists.
+     *
+     * @param name Name of the graphics state resource.
+     */
+    public PDExtendedGraphicsState getExtGState(COSName name)
+    {
+        COSObject indirect = getIndirect(COSName.EXT_G_STATE, name);
+        if (cache != null && indirect != 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)
+        {
+            extGState = new PDExtendedGraphicsState(dict);
+        }
+
+        if (cache != null)
+        {
+            cache.put(indirect, extGState);
+        }
+        return extGState;
+    }
+
+    /**
+     * Returns the shading resource with the given name, or null if none exists.
+     *
+     * @param name Name of the shading resource.
+     * @throws IOException if something went wrong.
+     */
+    public PDShading getShading(COSName name) throws IOException
+    {
+        COSObject indirect = getIndirect(COSName.SHADING, name);
+        if (cache != null && indirect != 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)
+        {
+            shading = PDShading.create(dict);
+        }
+        
+        if (cache != null)
+        {
+            cache.put(indirect, shading);
+        }
+        return shading;
+    }
+
+    /**
+     * Returns the pattern resource with the given name, or null if none exists.
+     * 
+     * @param name Name of the pattern resource.
+     * @throws IOException if something went wrong.
+     */
+    public PDAbstractPattern getPattern(COSName name) throws IOException
+    {
+        COSObject indirect = getIndirect(COSName.PATTERN, name);
+        if (cache != null && indirect != 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)
+        {
+            pattern = PDAbstractPattern.create(dict);
+        }
+
+        if (cache != null)
+        {
+            cache.put(indirect, pattern);
+        }
+        return pattern;
+    }
+
+    /**
+     * Returns the property list resource with the given name, or null if none exists.
+     * 
+     * @param name Name of the property list resource.
+     */
+    public PDPropertyList getProperties(COSName name)
+    {
+        COSObject indirect = getIndirect(COSName.PROPERTIES, name);
+        if (cache != null && indirect != 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)
+        {
+            propertyList = PDPropertyList.create(dict);
+        }
+
+        if (cache != null)
+        {
+            cache.put(indirect, propertyList);
+        }
+        return propertyList;
+    }
+
+    /**
+     * Tells whether the XObject resource with the given name is an image.
+     *
+     * @param name Name of the XObject resource.
+     * @return true if it is an image XObject, false if not.
+     */
+    public boolean isImageXObject(COSName name)
+    {
+        // get the instance
+        COSBase value = get(COSName.XOBJECT, name);
+        if (value == null)
+        {
+            return false;
+        }
+        else if (value instanceof COSObject)
+        {
+            value = ((COSObject) value).getObject();
+        }
+        if (!(value instanceof COSStream))
+        {
+            return false;
+        }
+        COSStream stream = (COSStream) value;
+        return COSName.IMAGE.equals(stream.getCOSName(COSName.SUBTYPE));
+    }
+
+    /**
+     * Returns the XObject resource with the given name, or null if none exists.
+     * 
+     * @param name Name of the XObject resource.
+     * @throws IOException if something went wrong.
+     */
+    public PDXObject getXObject(COSName name) throws IOException
+    {
+        COSObject indirect = getIndirect(COSName.XOBJECT, name);
+        if (cache != null && indirect != 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)
+        {
+            xobject = null;
+        }
+        else if (value instanceof COSObject)
+        {
+            xobject = PDXObject.createXObject(((COSObject) value).getObject(), this);
+        }
+        else
+        {
+            xobject = PDXObject.createXObject(value, this);
+        }
+
+        // we can't cache PDImageXObject, because it holds page resources, see PDFBOX-2370
+        if (cache != null && !(xobject instanceof PDImageXObject))
+        {
+            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;
+        }
+        COSBase base = dict.getItem(name);
+        if (base instanceof COSObject)
+        {
+            return (COSObject)base;
+        }
+        return null;
+    }
+    
+    /**
+     * Returns the resource with the given name and kind, or null.
+     */
+    private COSBase get(COSName kind, COSName name)
+    {
+        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
+        if (dict == null)
+        {
+            return null;
+        }
+        return dict.getDictionaryObject(name);
+    }
+
+    /**
+     * Returns the names of the color space resources, if any.
+     */
+    public Iterable<COSName> getColorSpaceNames()
+    {
+        return getNames(COSName.COLORSPACE);
+    }
+
+    /**
+     * Returns the names of the XObject resources, if any.
+     */
+    public Iterable<COSName> getXObjectNames()
+    {
+        return getNames(COSName.XOBJECT);
+    }
+
+    /**
+     * Returns the names of the font resources, if any.
+     */
+    public Iterable<COSName> getFontNames()
+    {
+        return getNames(COSName.FONT);
+    }
+
+    /**
+     * Returns the names of the property list resources, if any.
+     */
+    public Iterable<COSName> getPropertiesNames()
+    {
+        return getNames(COSName.PROPERTIES);
+    }
+
+    /**
+     * Returns the names of the shading resources, if any.
+     */
+    public Iterable<COSName> getShadingNames()
+    {
+        return getNames(COSName.SHADING);
+    }
+
+    /**
+     * Returns the names of the pattern resources, if any.
+     */
+    public Iterable<COSName> getPatternNames()
+    {
+        return getNames(COSName.PATTERN);
+    }
+
+    /**
+     * Returns the names of the extended graphics state resources, if any.
+     */
+    public Iterable<COSName> getExtGStateNames()
+    {
+        return getNames(COSName.EXT_G_STATE);
+    }
+
+    /**
+     * Returns the resource names of the given kind.
+     */
+    private Iterable<COSName> getNames(COSName kind)
+    {
+        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
+        if (dict == null)
+        {
+            return Collections.emptySet();
+        }
+        return dict.keySet();
+    }
+
+    /**
+     * Adds the given font to the resources of the current page and returns the name for
the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param font the font to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDFont font)
+    {
+        return add(COSName.FONT, "F", font);
+    }
+
+    /**
+     * Adds the given color space to the resources of the current page and returns the name
for the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param colorSpace the color space to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDColorSpace colorSpace)
+    {
+        return add(COSName.COLORSPACE, "cs", colorSpace);
+    }
+
+    /**
+     * Adds the given extended graphics state to the resources of the current page and returns
the
+     * name for the new resources. Returns the existing resource name if the given item already
exists.
+     *
+     * @param extGState the extended graphics state to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDExtendedGraphicsState extGState)
+    {
+        return add(COSName.EXT_G_STATE, "gs", extGState);
+    }
+
+    /**
+     * Adds the given shading to the resources of the current page and returns the name for
the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param shading the shading to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDShading shading)
+    {
+        return add(COSName.SHADING, "sh", shading);
+    }
+
+    /**
+     * Adds the given pattern to the resources of the current page and returns the name for
the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param pattern the pattern to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDAbstractPattern pattern)
+    {
+        return add(COSName.PATTERN, "p", pattern);
+    }
+
+    /**
+     * Adds the given property list to the resources of the current page and returns the
name for
+     * the new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param properties the property list to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDPropertyList properties)
+    {
+        if (properties instanceof PDOptionalContentGroup)
+        {
+            return add(COSName.PROPERTIES, "oc", properties);
+        }
+        else
+        {
+            return add(COSName.PROPERTIES, "Prop", properties);
+        }
+    }
+
+    /**
+     * Adds the given image to the resources of the current page and returns the name for
the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param image the image to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDImageXObject image)
+    {
+        return add(COSName.XOBJECT, "Im", image);
+    }
+
+    /**
+     * Adds the given form to the resources of the current page and returns the name for
the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param form the form to add
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDFormXObject form)
+    {
+        return add(COSName.XOBJECT, "Form", form);
+    }
+
+    /**
+     * Adds the given XObject to the resources of the current page and returns the name for
the
+     * new resources. Returns the existing resource name if the given item already exists.
+     *
+     * @param xobject the XObject to add
+     * @param prefix the prefix to be used when creating the resource name
+     * @return the name of the resource in the resources dictionary
+     */
+    public COSName add(PDXObject xobject, String prefix)
+    {
+        return add(COSName.XOBJECT, prefix, xobject);
+    }
+
+    /**
+     * Adds the given resource if it does not already exist.
+     */
+    private COSName add(COSName kind, String prefix, COSObjectable object)
+    {
+        // return the existing key if the item exists already
+        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
+        if (dict != null && dict.containsValue(object.getCOSObject()))
+        {
+            return dict.getKeyForValue(object.getCOSObject());
+        }
+
+        // add the item with a new key
+        COSName name = createKey(kind, prefix);
+        put(kind, name, object);
+        return name;
+    }
+
+    /**
+     * Returns a unique key for a new resource.
+     */
+    private COSName createKey(COSName kind, String prefix)
+    {
+        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
+        if (dict == null)
+        {
+            return COSName.getPDFName(prefix + 1);
+        }
+
+        // find a unique key
+        String key;
+        int n = dict.keySet().size();
+        do
+        {
+            ++n;
+            key = prefix + n;
+        }
+        while (dict.containsKey(key));
+        return COSName.getPDFName(key);
+    }
+
+    /**
+     * Sets the value of a given named resource.
+     */
+    private void put(COSName kind, COSName name, COSObjectable object)
+    {
+        COSDictionary dict = (COSDictionary)resources.getDictionaryObject(kind);
+        if (dict == null)
+        {
+            dict = new COSDictionary();
+            resources.setItem(kind, dict);
+        }
+        dict.setItem(name, object);
+    }
+
+    /**
+     * Sets the font resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param font the font to be added
+     */
+    public void put(COSName name, PDFont font)
+    {
+        put(COSName.FONT, name, font);
+    }
+
+    /**
+     * Sets the color space resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param colorSpace the color space to be added
+     */
+    public void put(COSName name, PDColorSpace colorSpace)
+    {
+        put(COSName.COLORSPACE, name, colorSpace);
+    }
+
+    /**
+     * Sets the extended graphics state resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param extGState the extended graphics state to be added
+     */
+    public void put(COSName name, PDExtendedGraphicsState extGState)
+    {
+        put(COSName.EXT_G_STATE, name, extGState);
+    }
+
+    /**
+     * Sets the shading resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param shading the shading to be added
+     */
+    public void put(COSName name, PDShading shading)
+    {
+        put(COSName.SHADING, name, shading);
+    }
+
+    /**
+     * Sets the pattern resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param pattern the pattern to be added
+     */
+    public void put(COSName name, PDAbstractPattern pattern)
+    {
+        put(COSName.PATTERN, name, pattern);
+    }
+
+    /**
+     * Sets the property list resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param properties the property list to be added
+     */
+    public void put(COSName name, PDPropertyList properties)
+    {
+        put(COSName.PROPERTIES, name, properties);
+    }
+
+    /**
+     * Sets the XObject resource with the given name.
+     *
+     * @param name the name of the resource
+     * @param xobject the XObject to be added
+     */
+    public void put(COSName name, PDXObject xobject)
+    {
+        put(COSName.XOBJECT, name, xobject);
+    }
+
+    /**
+     * Returns the resource cache associated with the Resources, or null if there is none.
+     */
+    public ResourceCache getResourceCache()
+    {
+        return cache;
+    }
+}




Mime
View raw message