org.apache.pdfbox.pdmodel.PDResources Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdfbox Show documentation
Show all versions of pdfbox Show documentation
The Apache PDFBox library is an open source Java tool for working with PDF documents.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.pdmodel;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.common.COSDictionaryMap;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDFontFactory;
import org.apache.pdfbox.pdmodel.graphics.PDExtendedGraphicsState;
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory;
import org.apache.pdfbox.pdmodel.graphics.pattern.PDPatternResources;
import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingResources;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
import org.apache.pdfbox.pdmodel.markedcontent.PDPropertyList;
import org.apache.pdfbox.util.MapUtil;
/**
* This represents a set of resources available at the page/pages/stream level.
*
* @author Ben Litchfield
* @author BM
*
*/
public class PDResources implements COSObjectable
{
private COSDictionary resources;
private Map fonts = null;
private Map fontMappings = new HashMap();
private Map colorspaces = null;
private Map xobjects = null;
private Map xobjectMappings = null;
private HashMap images = null;
private Map graphicsStates = null;
private Map patterns = null;
private Map shadings = null;
/**
* Log instance.
*/
private static final Log LOG = LogFactory.getLog(PDResources.class);
/**
* Default constructor.
*/
public PDResources()
{
resources = new COSDictionary();
}
/**
* Prepopulated resources.
*
* @param resourceDictionary The cos dictionary for this resource.
*/
public PDResources(COSDictionary resourceDictionary)
{
resources = resourceDictionary;
}
/**
* This will get the underlying dictionary.
*
* @return The dictionary for these resources.
*/
public COSDictionary getCOSDictionary()
{
return resources;
}
/**
* Convert this standard java object to a COS object.
*
* @return The cos object that matches this Java object.
*/
public COSBase getCOSObject()
{
return resources;
}
/**
* Calling this will release all cached information.
*
*/
public void clear()
{
if (fonts != null)
{
for(PDFont font : fonts.values())
{
font.clear();
}
fonts.clear();
fonts = null;
}
if (fontMappings != null)
{
fontMappings.clear();
fontMappings = null;
}
if (colorspaces != null)
{
colorspaces.clear();
colorspaces = null;
}
if (xobjects != null)
{
for(PDXObject xobject : xobjects.values())
{
xobject.clear();
}
xobjects.clear();
xobjects = null;
}
if (xobjectMappings != null)
{
xobjectMappings.clear();
xobjectMappings = null;
}
if (images != null)
{
images.clear();
images = null;
}
if (graphicsStates != null)
{
graphicsStates.clear();
graphicsStates = null;
}
if (patterns != null)
{
patterns.clear();
patterns = null;
}
if (shadings != null)
{
shadings.clear();
shadings = null;
}
}
/**
* This will get the map of fonts. This will never return null. The keys are string and the values are PDFont
* objects.
*
* @param fontCache A map of existing PDFont objects to reuse.
* @return The map of fonts.
*
* @throws IOException If there is an error getting the fonts.
*
* @deprecated due to some side effects font caching is no longer supported, use {@link #getFonts()} instead
*/
public Map getFonts(Map fontCache) throws IOException
{
return getFonts();
}
/**
* This will get the map of fonts. This will never return null.
*
* @return The map of fonts.
*/
public Map getFonts()
{
if (fonts == null)
{
// at least an empty map will be returned
// TODO we should return null instead of an empty map
fonts = new HashMap();
COSDictionary fontsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.FONT);
if (fontsDictionary == null)
{
fontsDictionary = new COSDictionary();
resources.setItem(COSName.FONT, fontsDictionary);
}
else
{
for (COSName fontName : fontsDictionary.keySet())
{
COSBase font = fontsDictionary.getDictionaryObject(fontName);
// data-000174.pdf contains a font that is a COSArray, looks to be an error in the
// PDF, we will just ignore entries that are not dictionaries.
if (font instanceof COSDictionary)
{
PDFont newFont = null;
try
{
newFont = PDFontFactory.createFont((COSDictionary) font);
}
catch (IOException exception)
{
LOG.error("error while creating a font", exception);
}
if (newFont != null)
{
fonts.put(fontName.getName(), newFont);
}
}
}
}
setFonts(fonts);
}
return fonts;
}
/**
* This will get the map of PDXObjects that are in the resource dictionary. This will never return null.
*
* @return The map of xobjects.
*/
public Map getXObjects()
{
if (xobjects == null)
{
// at least an empty map will be returned
// TODO we should return null instead of an empty map
xobjects = new HashMap();
COSDictionary xobjectsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.XOBJECT);
if (xobjectsDictionary == null)
{
xobjectsDictionary = new COSDictionary();
resources.setItem(COSName.XOBJECT, xobjectsDictionary);
}
else
{
xobjects = new HashMap();
for (COSName objName : xobjectsDictionary.keySet())
{
PDXObject xobject = null;
try
{
xobject = PDXObject.createXObject(xobjectsDictionary.getDictionaryObject(objName));
}
catch (IOException exception)
{
LOG.error("error while creating a xobject", exception);
}
if (xobject != null)
{
xobjects.put(objName.getName(), xobject);
}
}
}
setXObjects(xobjects);
}
return xobjects;
}
/**
* This will get the map of images. An empty map will be returned if there are no underlying images. So far the keys
* are COSName of the image and the value is the corresponding PDXObjectImage.
*
* @return The map of images.
* @throws IOException If there is an error writing the picture.
*
* @deprecated use {@link #getXObjects()} instead, as the images map isn't synchronized with the XObjects map.
*/
public Map getImages() throws IOException
{
if (images == null)
{
Map allXObjects = getXObjects();
images = new HashMap();
for (Map.Entry entry : allXObjects.entrySet())
{
PDXObject xobject = entry.getValue();
if (xobject instanceof PDXObjectImage)
{
images.put(entry.getKey(), (PDXObjectImage) xobject);
}
}
}
return images;
}
/**
* This will set the map of fonts.
*
* @param fontsValue The new map of fonts.
*/
public void setFonts(Map fontsValue)
{
fonts = fontsValue;
if (fontsValue != null)
{
resources.setItem(COSName.FONT, COSDictionaryMap.convert(fontsValue));
fontMappings = reverseMap(fontsValue, PDFont.class);
}
else
{
resources.removeItem(COSName.FONT);
fontMappings = null;
}
}
/**
* This will set the map of xobjects.
*
* @param xobjectsValue The new map of xobjects.
*/
public void setXObjects(Map xobjectsValue)
{
xobjects = xobjectsValue;
if (xobjectsValue != null)
{
resources.setItem(COSName.XOBJECT, COSDictionaryMap.convert(xobjectsValue));
xobjectMappings = reverseMap(xobjects, PDXObject.class);
}
else
{
resources.removeItem(COSName.XOBJECT);
xobjectMappings = null;
}
}
/**
* This will get the map of colorspaces. This will return null if the underlying resources dictionary does not have
* a colorspace dictionary. The keys are string and the values are PDColorSpace objects.
*
* @return The map of colorspaces.
*/
public Map getColorSpaces()
{
if (colorspaces == null)
{
COSDictionary csDictionary = (COSDictionary) resources.getDictionaryObject(COSName.COLORSPACE);
if (csDictionary != null)
{
colorspaces = new HashMap();
for (COSName csName : csDictionary.keySet())
{
COSBase cs = csDictionary.getDictionaryObject(csName);
PDColorSpace colorspace = null;
try
{
colorspace = PDColorSpaceFactory.createColorSpace(cs);
}
catch (IOException exception)
{
LOG.error("error while creating a colorspace", exception);
}
if (colorspace != null)
{
colorspaces.put(csName.getName(), colorspace);
}
}
}
}
return colorspaces;
}
/**
* This will set the map of colorspaces.
*
* @param csValue The new map of colorspaces.
*/
public void setColorSpaces(Map csValue)
{
colorspaces = csValue;
if (csValue != null)
{
resources.setItem(COSName.COLORSPACE, COSDictionaryMap.convert(csValue));
}
else
{
resources.removeItem(COSName.COLORSPACE);
}
}
/**
* This will get the map of graphic states. This will return null if the underlying resources dictionary does not
* have a graphics dictionary. The keys are the graphic state name as a String and the values are
* PDExtendedGraphicsState objects.
*
* @return The map of extended graphic state objects.
*/
public Map getGraphicsStates()
{
if (graphicsStates == null)
{
COSDictionary states = (COSDictionary) resources.getDictionaryObject(COSName.EXT_G_STATE);
if (states != null)
{
graphicsStates = new HashMap();
for (COSName name : states.keySet())
{
COSDictionary dictionary = (COSDictionary) states.getDictionaryObject(name);
graphicsStates.put(name.getName(), new PDExtendedGraphicsState(dictionary));
}
}
}
return graphicsStates;
}
/**
* This will set the map of graphics states.
*
* @param states The new map of states.
*/
public void setGraphicsStates(Map states)
{
graphicsStates = states;
if (states != null)
{
Iterator iter = states.keySet().iterator();
COSDictionary dic = new COSDictionary();
while (iter.hasNext())
{
String name = (String) iter.next();
PDExtendedGraphicsState state = states.get(name);
dic.setItem(COSName.getPDFName(name), state.getCOSObject());
}
resources.setItem(COSName.EXT_G_STATE, dic);
}
else
{
resources.removeItem(COSName.EXT_G_STATE);
}
}
/**
* Returns the dictionary mapping resource names to property list dictionaries for marked content.
*
* @return the property list
*/
public PDPropertyList getProperties()
{
PDPropertyList retval = null;
COSDictionary props = (COSDictionary) resources.getDictionaryObject(COSName.PROPERTIES);
if (props != null)
{
retval = new PDPropertyList(props);
}
return retval;
}
/**
* Sets the dictionary mapping resource names to property list dictionaries for marked content.
*
* @param props the property list
*/
public void setProperties(PDPropertyList props)
{
resources.setItem(COSName.PROPERTIES, props.getCOSObject());
}
/**
* This will get the map of patterns. This will return null if the underlying resources dictionary does not have a
* patterns dictionary. The keys are the pattern name as a String and the values are PDPatternResources objects.
*
* @return The map of pattern resources objects.
*
* @throws IOException If there is an error getting the pattern resources.
*/
public Map getPatterns() throws IOException
{
if (patterns == null)
{
COSDictionary patternsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.PATTERN);
if (patternsDictionary != null)
{
patterns = new HashMap();
for (COSName name : patternsDictionary.keySet())
{
COSDictionary dictionary = (COSDictionary) patternsDictionary.getDictionaryObject(name);
patterns.put(name.getName(), PDPatternResources.create(dictionary));
}
}
}
return patterns;
}
/**
* This will set the map of patterns.
*
* @param patternsValue The new map of patterns.
*/
public void setPatterns(Map patternsValue)
{
patterns = patternsValue;
if (patternsValue != null)
{
Iterator iter = patternsValue.keySet().iterator();
COSDictionary dic = new COSDictionary();
while (iter.hasNext())
{
String name = iter.next();
PDPatternResources pattern = patternsValue.get(name);
dic.setItem(COSName.getPDFName(name), pattern.getCOSObject());
}
resources.setItem(COSName.PATTERN, dic);
}
else
{
resources.removeItem(COSName.PATTERN);
}
}
/**
* This will get the map of shadings. This will return null if the underlying resources dictionary does not have a
* shading dictionary. The keys are the shading name as a String and the values are PDShadingResources objects.
*
* @return The map of shading resources objects.
*
* @throws IOException If there is an error getting the shading resources.
*/
public Map getShadings() throws IOException
{
if (shadings == null)
{
COSDictionary shadingsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.SHADING);
if (shadingsDictionary != null)
{
shadings = new HashMap();
for (COSName name : shadingsDictionary.keySet())
{
COSDictionary dictionary = (COSDictionary) shadingsDictionary.getDictionaryObject(name);
shadings.put(name.getName(), PDShadingResources.create(dictionary));
}
}
}
return shadings;
}
/**
* This will set the map of shadings.
*
* @param shadingsValue The new map of shadings.
*/
public void setShadings(Map shadingsValue)
{
shadings = shadingsValue;
if (shadingsValue != null)
{
Iterator iter = shadingsValue.keySet().iterator();
COSDictionary dic = new COSDictionary();
while (iter.hasNext())
{
String name = iter.next();
PDShadingResources shading = shadingsValue.get(name);
dic.setItem(COSName.getPDFName(name), shading.getCOSObject());
}
resources.setItem(COSName.SHADING, dic);
}
else
{
resources.removeItem(COSName.SHADING);
}
}
/**
* Adds the given font to the resources of the current page.
*
* @param font the font to be added
* @return the font name to be used within the content stream.
*/
public String addFont(PDFont font)
{
// use the getter to initialize a possible empty fonts map
return addFont(font, MapUtil.getNextUniqueKey(getFonts(), "F"));
}
/**
* Adds the given font to the resources of the current page using the given font key.
*
* @param font the font to be added
* @param fontKey key to used to map to the given font
* @return the font name to be used within the content stream.
*/
public String addFont(PDFont font, String fontKey)
{
if (fonts == null)
{
// initialize fonts map
getFonts();
}
String fontMapping = fontMappings.get(font);
if (fontMapping == null)
{
fontMapping = fontKey;
fontMappings.put(font, fontMapping);
fonts.put(fontMapping, font);
addFontToDictionary(font, fontMapping);
}
return fontMapping;
}
private void addFontToDictionary(PDFont font, String fontName)
{
COSDictionary fontsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.FONT);
fontsDictionary.setItem(fontName, font);
}
/**
* Adds the given XObject to the resources of the current the page.
*
* @param xobject the XObject to be added
* @param prefix the prefix to be used for the name
*
* @return the XObject name to be used within the content stream.
*/
public String addXObject(PDXObject xobject, String prefix)
{
if (xobjects == null)
{
// initialize XObject map
getXObjects();
}
String objMapping = xobjectMappings.get(xobject);
if (objMapping == null)
{
objMapping = MapUtil.getNextUniqueKey(xobjects, prefix);
xobjectMappings.put(xobject, objMapping);
xobjects.put(objMapping, xobject);
addXObjectToDictionary(xobject, objMapping);
}
return objMapping;
}
private void addXObjectToDictionary(PDXObject xobject, String xobjectName)
{
COSDictionary xobjectsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.XOBJECT);
xobjectsDictionary.setItem(xobjectName, xobject);
}
private Map reverseMap(Map map, Class keyClass)
{
Map reversed = new java.util.HashMap();
for (Map.Entry entry : map.entrySet())
{
reversed.put(keyClass.cast(entry.getValue()), (String) entry.getKey());
}
return reversed;
}
}