Author: lehmi Date: Sat Oct 26 09:37:52 2013 New Revision: 1535956 URL: http://svn.apache.org/r1535956 Log: PDFBOX-1753: intialize the internal font/xobject map when adding a font/xobject
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=1535956&r1=1535955&r2=1535956&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 Oct 26 09:37:52 2013 @@ -42,22 +42,22 @@ import org.apache.pdfbox.util.MapUtil; /** * This represents a set of resources available at the page/pages/stream level. - * + * * @author <a href="mailto:b...@benlitchfield.com">Ben Litchfield</a> - * @version $Revision: 1.16 $ + * */ public class PDResources implements COSObjectable { private COSDictionary resources; - private Map<String,PDFont> fonts = null; + private Map<String, PDFont> fonts = null; private Map<PDFont, String> fontMappings = new HashMap<PDFont, String>(); - private Map<String,PDColorSpace> colorspaces = null; - private Map<String,PDXObject> xobjects = null; - private Map<PDXObject,String> xobjectMappings = null; - private HashMap<String,PDXObjectImage> images = null; - private Map<String,PDExtendedGraphicsState> graphicsStates = null; - private Map<String,PDPatternResources> patterns = null; - private Map<String,PDShadingResources> shadings = null; + private Map<String, PDColorSpace> colorspaces = null; + private Map<String, PDXObject> xobjects = null; + private Map<PDXObject, String> xobjectMappings = null; + private HashMap<String, PDXObjectImage> images = null; + private Map<String, PDExtendedGraphicsState> graphicsStates = null; + private Map<String, PDPatternResources> patterns = null; + private Map<String, PDShadingResources> shadings = null; /** * Log instance. @@ -74,17 +74,17 @@ public class PDResources implements COSO /** * Prepopulated resources. - * + * * @param resourceDictionary The cos dictionary for this resource. */ - public PDResources( COSDictionary resourceDictionary ) + public PDResources(COSDictionary resourceDictionary) { resources = resourceDictionary; } /** * This will get the underlying dictionary. - * + * * @return The dictionary for these resources. */ public COSDictionary getCOSDictionary() @@ -94,7 +94,7 @@ public class PDResources implements COSO /** * Convert this standard java object to a COS object. - * + * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() @@ -106,7 +106,7 @@ public class PDResources implements COSO * Calling this will release all cached information. * */ - public void clear() + public void clear() { if (fonts != null) { @@ -154,53 +154,54 @@ public class PDResources implements COSO shadings = null; } } + /** - * This will get the map of fonts. This will never return null. The keys are string - * and the values are PDFont objects. - * + * 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<String,PDFont> getFonts( Map<String,PDFont> fontCache ) throws IOException + public Map<String, PDFont> getFonts(Map<String, PDFont> fontCache) throws IOException { return getFonts(); } /** * This will get the map of fonts. This will never return null. - * + * * @return The map of fonts. */ - public Map<String,PDFont> getFonts() + public Map<String, PDFont> 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<String,PDFont>(); - COSDictionary fontsDictionary = (COSDictionary)resources.getDictionaryObject( COSName.FONT ); - if( fontsDictionary == null ) + fonts = new HashMap<String, PDFont>(); + COSDictionary fontsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.FONT); + if (fontsDictionary == null) { fontsDictionary = new COSDictionary(); - resources.setItem( COSName.FONT, fontsDictionary ); + resources.setItem(COSName.FONT, fontsDictionary); } else { - for( COSName fontName : fontsDictionary.keySet() ) + 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 ) + 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 ); + newFont = PDFontFactory.createFont((COSDictionary) font); } catch (IOException exception) { @@ -208,80 +209,81 @@ public class PDResources implements COSO } if (newFont != null) { - fonts.put( fontName.getName(), newFont); + 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. - * + * 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<String,PDXObject> getXObjects() + public Map<String, PDXObject> 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<String,PDXObject>(); - COSDictionary xobjectsDictionary = (COSDictionary)resources.getDictionaryObject( COSName.XOBJECT ); - if( xobjectsDictionary == null ) + xobjects = new HashMap<String, PDXObject>(); + COSDictionary xobjectsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.XOBJECT); + if (xobjectsDictionary == null) { xobjectsDictionary = new COSDictionary(); - resources.setItem( COSName.XOBJECT, xobjectsDictionary ); + resources.setItem(COSName.XOBJECT, xobjectsDictionary); } else { - xobjects = new HashMap<String,PDXObject>(); - for( COSName objName : xobjectsDictionary.keySet() ) + xobjects = new HashMap<String, PDXObject>(); + for (COSName objName : xobjectsDictionary.keySet()) { PDXObject xobject = null; try { - xobject = PDXObject.createXObject( xobjectsDictionary.getDictionaryObject(objName) ); + xobject = PDXObject.createXObject(xobjectsDictionary.getDictionaryObject(objName)); } catch (IOException exception) { LOG.error("error while creating a xobject", exception); } - if( xobject != null ) + if (xobject != null) { - xobjects.put( objName.getName(), xobject); + 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. - * + * 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. + * * @author By BM * @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<String,PDXObjectImage> getImages() throws IOException + public Map<String, PDXObjectImage> getImages() throws IOException { - if (images == null) + if (images == null) { - Map<String,PDXObject> allXObjects = getXObjects(); - images = new HashMap<String,PDXObjectImage>(); - for( Map.Entry<String,PDXObject> entry: allXObjects.entrySet() ) + Map<String, PDXObject> allXObjects = getXObjects(); + images = new HashMap<String, PDXObjectImage>(); + for (Map.Entry<String, PDXObject> entry : allXObjects.entrySet()) { PDXObject xobject = entry.getValue(); - if( xobject instanceof PDXObjectImage ) + if (xobject instanceof PDXObjectImage) { - images.put( entry.getKey(), (PDXObjectImage)xobject); + images.put(entry.getKey(), (PDXObjectImage) xobject); } } } @@ -290,62 +292,65 @@ public class PDResources implements COSO /** * This will set the map of fonts. - * + * * @param fontsValue The new map of fonts. */ - public void setFonts( Map<String,PDFont> fontsValue ) + public void setFonts(Map<String, PDFont> fontsValue) { fonts = fontsValue; if (fontsValue != null) { - resources.setItem( COSName.FONT, COSDictionaryMap.convert( fontsValue ) ); + 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<String,PDXObject> xobjectsValue ) + public void setXObjects(Map<String, PDXObject> xobjectsValue) { xobjects = xobjectsValue; if (xobjectsValue != null) { - resources.setItem( COSName.XOBJECT, COSDictionaryMap.convert( xobjectsValue ) ); + 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. - * + * 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<String,PDColorSpace> getColorSpaces() + public Map<String, PDColorSpace> getColorSpaces() { - if (colorspaces == null) + if (colorspaces == null) { - COSDictionary csDictionary = (COSDictionary)resources.getDictionaryObject( COSName.COLORSPACE ); - if( csDictionary != null ) + COSDictionary csDictionary = (COSDictionary) resources.getDictionaryObject(COSName.COLORSPACE); + if (csDictionary != null) { - colorspaces = new HashMap<String,PDColorSpace>(); - for( COSName csName : csDictionary.keySet() ) + colorspaces = new HashMap<String, PDColorSpace>(); + for (COSName csName : csDictionary.keySet()) { - COSBase cs = csDictionary.getDictionaryObject( csName ); + COSBase cs = csDictionary.getDictionaryObject(csName); PDColorSpace colorspace = null; - try + try { - colorspace = PDColorSpaceFactory.createColorSpace( cs ); + colorspace = PDColorSpaceFactory.createColorSpace(cs); } catch (IOException exception) { @@ -353,7 +358,7 @@ public class PDResources implements COSO } if (colorspace != null) { - colorspaces.put( csName.getName(), colorspace ); + colorspaces.put(csName.getName(), colorspace); } } } @@ -363,15 +368,15 @@ public class PDResources implements COSO /** * This will set the map of colorspaces. - * + * * @param csValue The new map of colorspaces. */ - public void setColorSpaces( Map<String,PDColorSpace> csValue ) + public void setColorSpaces(Map<String, PDColorSpace> csValue) { colorspaces = csValue; if (csValue != null) { - resources.setItem( COSName.COLORSPACE, COSDictionaryMap.convert( csValue ) ); + resources.setItem(COSName.COLORSPACE, COSDictionaryMap.convert(csValue)); } else { @@ -380,24 +385,24 @@ public class PDResources implements COSO } /** - * 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. - * + * 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<String,PDExtendedGraphicsState> getGraphicsStates() + public Map<String, PDExtendedGraphicsState> getGraphicsStates() { if (graphicsStates == null) { - COSDictionary states = (COSDictionary)resources.getDictionaryObject( COSName.EXT_G_STATE ); - if( states != null ) + COSDictionary states = (COSDictionary) resources.getDictionaryObject(COSName.EXT_G_STATE); + if (states != null) { - graphicsStates = new HashMap<String,PDExtendedGraphicsState>(); - for( COSName name : states.keySet() ) + graphicsStates = new HashMap<String, PDExtendedGraphicsState>(); + for (COSName name : states.keySet()) { - COSDictionary dictionary = (COSDictionary)states.getDictionaryObject( name ); - graphicsStates.put( name.getName(), new PDExtendedGraphicsState( dictionary ) ); + COSDictionary dictionary = (COSDictionary) states.getDictionaryObject(name); + graphicsStates.put(name.getName(), new PDExtendedGraphicsState(dictionary)); } } } @@ -406,23 +411,23 @@ public class PDResources implements COSO /** * This will set the map of graphics states. - * + * * @param states The new map of states. */ - public void setGraphicsStates( Map<String,PDExtendedGraphicsState> states ) + public void setGraphicsStates(Map<String, PDExtendedGraphicsState> states) { graphicsStates = states; if (states != null) { Iterator<String> iter = states.keySet().iterator(); COSDictionary dic = new COSDictionary(); - while( iter.hasNext() ) + while (iter.hasNext()) { - String name = (String)iter.next(); - PDExtendedGraphicsState state = states.get( name ); - dic.setItem( COSName.getPDFName( name ), state.getCOSObject() ); + String name = (String) iter.next(); + PDExtendedGraphicsState state = states.get(name); + dic.setItem(COSName.getPDFName(name), state.getCOSObject()); } - resources.setItem( COSName.EXT_G_STATE, dic ); + resources.setItem(COSName.EXT_G_STATE, dic); } else { @@ -431,14 +436,14 @@ public class PDResources implements COSO } /** - * Returns the dictionary mapping resource names to property list dictionaries for marked - * content. + * 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); + COSDictionary props = (COSDictionary) resources.getDictionaryObject(COSName.PROPERTIES); if (props != null) { @@ -448,8 +453,8 @@ public class PDResources implements COSO } /** - * Sets the dictionary mapping resource names to property list dictionaries for marked - * content. + * Sets the dictionary mapping resource names to property list dictionaries for marked content. + * * @param props the property list */ public void setProperties(PDPropertyList props) @@ -458,26 +463,25 @@ public class PDResources implements COSO } /** - * 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. - * + * 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<String,PDPatternResources> getPatterns() throws IOException + public Map<String, PDPatternResources> getPatterns() throws IOException { if (patterns == null) { - COSDictionary patternsDictionary = (COSDictionary)resources.getDictionaryObject( COSName.PATTERN ); - if( patternsDictionary != null ) + COSDictionary patternsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.PATTERN); + if (patternsDictionary != null) { - patterns = new HashMap<String,PDPatternResources>(); - for( COSName name : patternsDictionary.keySet() ) + patterns = new HashMap<String, PDPatternResources>(); + for (COSName name : patternsDictionary.keySet()) { - COSDictionary dictionary = (COSDictionary)patternsDictionary.getDictionaryObject( name ); - patterns.put( name.getName(), PDPatternResources.create( dictionary ) ); + COSDictionary dictionary = (COSDictionary) patternsDictionary.getDictionaryObject(name); + patterns.put(name.getName(), PDPatternResources.create(dictionary)); } } } @@ -486,23 +490,23 @@ public class PDResources implements COSO /** * This will set the map of patterns. - * + * * @param patternsValue The new map of patterns. */ - public void setPatterns( Map<String,PDPatternResources> patternsValue ) + public void setPatterns(Map<String, PDPatternResources> patternsValue) { patterns = patternsValue; if (patternsValue != null) { Iterator<String> iter = patternsValue.keySet().iterator(); COSDictionary dic = new COSDictionary(); - while( iter.hasNext() ) + while (iter.hasNext()) { String name = iter.next(); - PDPatternResources pattern = patternsValue.get( name ); - dic.setItem( COSName.getPDFName( name ), pattern.getCOSObject() ); + PDPatternResources pattern = patternsValue.get(name); + dic.setItem(COSName.getPDFName(name), pattern.getCOSObject()); } - resources.setItem( COSName.PATTERN, dic ); + resources.setItem(COSName.PATTERN, dic); } else { @@ -511,26 +515,25 @@ public class PDResources implements COSO } /** - * 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. - * + * 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<String,PDShadingResources> getShadings() throws IOException + public Map<String, PDShadingResources> getShadings() throws IOException { if (shadings == null) { - COSDictionary shadingsDictionary = (COSDictionary)resources.getDictionaryObject( COSName.SHADING ); - if( shadingsDictionary != null ) + COSDictionary shadingsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.SHADING); + if (shadingsDictionary != null) { - shadings = new HashMap<String,PDShadingResources>(); - for( COSName name : shadingsDictionary.keySet() ) + shadings = new HashMap<String, PDShadingResources>(); + for (COSName name : shadingsDictionary.keySet()) { - COSDictionary dictionary = (COSDictionary)shadingsDictionary.getDictionaryObject( name ); - shadings.put( name.getName(), PDShadingResources.create( dictionary ) ); + COSDictionary dictionary = (COSDictionary) shadingsDictionary.getDictionaryObject(name); + shadings.put(name.getName(), PDShadingResources.create(dictionary)); } } } @@ -539,23 +542,23 @@ public class PDResources implements COSO /** * This will set the map of shadings. - * + * * @param shadingsValue The new map of shadings. */ - public void setShadings( Map<String,PDShadingResources> shadingsValue ) + public void setShadings(Map<String, PDShadingResources> shadingsValue) { shadings = shadingsValue; if (shadingsValue != null) { Iterator<String> iter = shadingsValue.keySet().iterator(); COSDictionary dic = new COSDictionary(); - while( iter.hasNext() ) + while (iter.hasNext()) { String name = iter.next(); - PDShadingResources shading = shadingsValue.get( name ); - dic.setItem( COSName.getPDFName( name ), shading.getCOSObject() ); + PDShadingResources shading = shadingsValue.get(name); + dic.setItem(COSName.getPDFName(name), shading.getCOSObject()); } - resources.setItem( COSName.SHADING, dic ); + resources.setItem(COSName.SHADING, dic); } else { @@ -569,9 +572,10 @@ public class PDResources implements COSO * @param font the font to be added * @return the font name to be used within the content stream. */ - public String addFont(PDFont font) + public String addFont(PDFont font) { - return addFont(font, MapUtil.getNextUniqueKey( fonts, "F" )); + // use the getter to initialize a possible empty fonts map + return addFont(font, MapUtil.getNextUniqueKey(getFonts(), "F")); } /** @@ -581,31 +585,31 @@ public class PDResources implements COSO * @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) + public String addFont(PDFont font, String fontKey) { - if (fonts == null) + if (fonts == null) { - fonts = getFonts(); - fontMappings = reverseMap(fonts, PDFont.class); - setFonts(fonts); + // initialize fonts map + getFonts(); } - - String fontMapping = fontMappings.get( font ); - if( fontMapping == null ) + + String fontMapping = fontMappings.get(font); + if (fontMapping == null) { fontMapping = fontKey; - fontMappings.put( font, fontMapping ); - fonts.put( fontMapping, font ); + 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); + COSDictionary fontsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.FONT); fontsDictionary.setItem(fontName, font); } + /** * Adds the given XObject to the resources of the current the page. * @@ -614,20 +618,19 @@ public class PDResources implements COSO * * @return the XObject name to be used within the content stream. */ - public String addXObject(PDXObject xobject, String prefix) + public String addXObject(PDXObject xobject, String prefix) { - if (xobjects == null) + if (xobjects == null) { - xobjects = getXObjects(); - xobjectMappings = reverseMap(xobjects, PDXObject.class); - setXObjects(xobjects); + // initialize XObject map + getXObjects(); } - String objMapping = xobjectMappings.get( xobject ); - if( objMapping == null ) + String objMapping = xobjectMappings.get(xobject); + if (objMapping == null) { - objMapping = MapUtil.getNextUniqueKey( xobjects, prefix ); - xobjectMappings.put( xobject, objMapping ); - xobjects.put( objMapping, xobject ); + objMapping = MapUtil.getNextUniqueKey(xobjects, prefix); + xobjectMappings.put(xobject, objMapping); + xobjects.put(objMapping, xobject); addXObjectToDictionary(xobject, objMapping); } return objMapping; @@ -635,7 +638,7 @@ public class PDResources implements COSO private void addXObjectToDictionary(PDXObject xobject, String xobjectName) { - COSDictionary xobjectsDictionary = (COSDictionary)resources.getDictionaryObject(COSName.XOBJECT); + COSDictionary xobjectsDictionary = (COSDictionary) resources.getDictionaryObject(COSName.XOBJECT); xobjectsDictionary.setItem(xobjectName, xobject); } @@ -644,10 +647,9 @@ public class PDResources implements COSO Map<T, String> reversed = new java.util.HashMap<T, String>(); for (Map.Entry<String, T> entry : map.entrySet()) { - reversed.put(keyClass.cast(entry.getValue()), (String)entry.getKey()); + reversed.put(keyClass.cast(entry.getValue()), (String) entry.getKey()); } return reversed; } - }