Skip to content

Commit b071589

Browse files
committed
PDFBOX-6175: extend ResourceCache so that PDCIDFont and PDFontDescriptor instances can be shared if those are referenced multiple times
git-svn-id: https://svn.apache.org/repos/asf/pdfbox/trunk@1932381 13f79535-47bb-0310-9956-ffa450edef68
1 parent 5b097b0 commit b071589

12 files changed

Lines changed: 215 additions & 31 deletions

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/DefaultResourceCache.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525

2626
import org.apache.pdfbox.cos.COSObject;
2727
import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
28+
import org.apache.pdfbox.pdmodel.font.PDCIDFont;
2829
import org.apache.pdfbox.pdmodel.font.PDFont;
30+
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
2931
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
3032
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
3133
import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
@@ -54,7 +56,11 @@ public class DefaultResourceCache implements ResourceCache
5456
new HashMap<>();
5557
private final Map<Long, Integer> removedFonts = new HashMap<>();
5658
private final Set<Long> stableFonts = new HashSet<>();
57-
59+
60+
private final Map<COSObject, SoftReference<PDCIDFont>> cidFonts = new HashMap<>();
61+
62+
private final Map<COSObject, SoftReference<PDFontDescriptor>> fontDescriptors = new HashMap<>();
63+
5864
private final Map<COSObject, SoftReference<PDColorSpace>> colorSpaces =
5965
new HashMap<>();
6066
private final Map<Long, Integer> removedColorSpaces = new HashMap<>();
@@ -144,6 +150,58 @@ public PDFont removeFont(COSObject indirect)
144150
return font != null ? font.get() : null;
145151
}
146152

153+
@Override
154+
public PDCIDFont getCIDFont(COSObject indirect)
155+
{
156+
SoftReference<PDCIDFont> font = cidFonts.get(indirect);
157+
return font != null ? font.get() : null;
158+
}
159+
160+
@Override
161+
public void put(COSObject indirect, PDCIDFont font)
162+
{
163+
cidFonts.put(indirect, new SoftReference<>(font));
164+
}
165+
166+
@Override
167+
public PDCIDFont removeCIDFont(COSObject indirect)
168+
{
169+
if (cidFonts.isEmpty())
170+
{
171+
return null;
172+
}
173+
SoftReference<PDCIDFont> font = cidFonts.remove(indirect);
174+
return font != null ? font.get() : null;
175+
}
176+
177+
@Override
178+
public PDFontDescriptor getFontDescriptor(COSObject indirect)
179+
{
180+
if (fontDescriptors.isEmpty())
181+
{
182+
return null;
183+
}
184+
SoftReference<PDFontDescriptor> fontDescriptor = fontDescriptors.get(indirect);
185+
return fontDescriptor != null ? fontDescriptor.get() : null;
186+
}
187+
188+
@Override
189+
public void put(COSObject indirect, PDFontDescriptor fontDescriptor)
190+
{
191+
fontDescriptors.put(indirect, new SoftReference<>(fontDescriptor));
192+
}
193+
194+
@Override
195+
public PDFontDescriptor removeFontDescriptor(COSObject indirect)
196+
{
197+
if (fontDescriptors.isEmpty())
198+
{
199+
return null;
200+
}
201+
SoftReference<PDFontDescriptor> font = fontDescriptors.remove(indirect);
202+
return font != null ? font.get() : null;
203+
}
204+
147205
@Override
148206
public PDColorSpace getColorSpace(COSObject indirect)
149207
{

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import org.apache.pdfbox.pdmodel.common.PDMetadata;
4848
import org.apache.pdfbox.pdmodel.common.PDRectangle;
4949
import org.apache.pdfbox.pdmodel.common.PDStream;
50+
import org.apache.pdfbox.pdmodel.font.PDFont;
51+
import org.apache.pdfbox.pdmodel.font.PDType0Font;
5052
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
5153
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
5254
import org.apache.pdfbox.pdmodel.interactive.action.PDPageAdditionalActions;
@@ -141,14 +143,40 @@ private void removeResources(COSDictionary resources)
141143
.forEach(resourceCache::removeColorSpace);
142144
getIndirectResourceObjects(resources, COSName.EXT_G_STATE)
143145
.forEach(resourceCache::removeExtState);
144-
getIndirectResourceObjects(resources, COSName.FONT)
145-
.forEach(resourceCache::removeFont);
146146
getIndirectResourceObjects(resources, COSName.PATTERN)
147147
.forEach(resourceCache::removePattern);
148148
getIndirectResourceObjects(resources, COSName.PROPERTIES)
149149
.forEach(resourceCache::removeProperties);
150150
getIndirectResourceObjects(resources, COSName.SHADING)
151151
.forEach(resourceCache::removeShading);
152+
for (COSObject cosObject : getIndirectResourceObjects(resources, COSName.FONT))
153+
{
154+
PDFont removedFont = resourceCache.removeFont(cosObject);
155+
if (removedFont == null)
156+
{
157+
continue;
158+
}
159+
COSDictionary fontDict = removedFont.getCOSObject();
160+
if (removedFont instanceof PDType0Font)
161+
{
162+
// remove PDCIDFont from cache
163+
COSArray descendantFonts = fontDict.getCOSArray(COSName.DESCENDANT_FONTS);
164+
if (descendantFonts != null)
165+
{
166+
COSBase descendantFontBaseObject = descendantFonts.get(0);
167+
if (descendantFontBaseObject instanceof COSObject)
168+
{
169+
resourceCache.removeCIDFont((COSObject) descendantFontBaseObject);
170+
}
171+
}
172+
}
173+
COSObject fdIndirectObject = fontDict.getCOSObject(COSName.FONT_DESC);
174+
// remove PDFontDescriptor from cache
175+
if (fdIndirectObject != null)
176+
{
177+
resourceCache.removeFontDescriptor(fdIndirectObject);
178+
}
179+
}
152180
for (COSObject cosObject : getIndirectResourceObjects(resources, COSName.XOBJECT))
153181
{
154182
PDXObject removedXObject = resourceCache.removeXObject(cosObject);

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ResourceCache.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
import org.apache.pdfbox.cos.COSObject;
2121
import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
22+
import org.apache.pdfbox.pdmodel.font.PDCIDFont;
2223
import org.apache.pdfbox.pdmodel.font.PDFont;
24+
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
2325
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
2426
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
2527
import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
@@ -41,6 +43,22 @@ public interface ResourceCache
4143
*/
4244
PDFont getFont(COSObject indirect);
4345

46+
/**
47+
* Returns the PDCIDFont instance for the given indirect object, if it is in the cache.
48+
*
49+
* @param indirect the indirect reference of the PDCIDFont instance to be returned
50+
* @return the cached instance of the PDCIDFont, if available
51+
*/
52+
PDCIDFont getCIDFont(COSObject indirect);
53+
54+
/**
55+
* Returns the PDFontDescriptor instance for the given indirect object, if it is in the cache.
56+
*
57+
* @param indirect the indirect reference of the PDFontDescriptor instance to be returned
58+
* @return the cached instance of the PDFontDescriptor, if available
59+
*/
60+
PDFontDescriptor getFontDescriptor(COSObject indirect);
61+
4462
/**
4563
* Returns the color space resource for the given indirect object, if it is in the cache.
4664
*
@@ -97,6 +115,22 @@ public interface ResourceCache
97115
*/
98116
void put(COSObject indirect, PDFont font);
99117

118+
/**
119+
* Puts the PDCIDFont instance of the given indirect object in the cache.
120+
*
121+
* @param indirect the indirect reference of the PDCIDFont to be cached
122+
* @param font the font to be cached
123+
*/
124+
void put(COSObject indirect, PDCIDFont cidFont);
125+
126+
/**
127+
* Puts the PDFontDescriptor instance of the given indirect object in the cache.
128+
*
129+
* @param indirect the indirect reference of the PDFontDescriptor to be cached
130+
* @param font the font to be cached
131+
*/
132+
void put(COSObject indirect, PDFontDescriptor fontDescriptor);
133+
100134
/**
101135
* Puts the given indirect color space resource in the cache.
102136
*
@@ -172,6 +206,24 @@ public interface ResourceCache
172206
*/
173207
PDFont removeFont(COSObject indirect);
174208

209+
/**
210+
* Removes the PDCIDFont instance for the given indirect object from the cache.
211+
*
212+
* @param indirect the indirect reference of the PDCIDFont to be removed
213+
*
214+
* @return the removed PDCIDFont if present
215+
*/
216+
PDCIDFont removeCIDFont(COSObject indirect);
217+
218+
/**
219+
* Removes the PDFontDescriptor instance for the given indirect object from the cache.
220+
*
221+
* @param indirect the indirect reference of the PDFontDescriptor to be removed
222+
*
223+
* @return the removed PDFontDescriptor if present
224+
*/
225+
PDFontDescriptor removeFontDescriptor(COSObject indirect);
226+
175227
/**
176228
* Removes the given indirect shading resource from the cache.
177229
*

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
import org.apache.pdfbox.cos.COSDictionary;
3535
import org.apache.pdfbox.cos.COSName;
3636
import org.apache.pdfbox.cos.COSNumber;
37+
import org.apache.pdfbox.cos.COSObject;
3738
import org.apache.pdfbox.cos.COSStream;
3839
import org.apache.pdfbox.io.RandomAccessRead;
40+
import org.apache.pdfbox.pdmodel.ResourceCache;
3941
import org.apache.pdfbox.pdmodel.common.COSObjectable;
4042
import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName;
4143
import org.apache.pdfbox.pdmodel.font.encoding.GlyphList;
@@ -101,34 +103,46 @@ public abstract class PDFont implements COSObjectable, PDFontLike
101103
* Constructor.
102104
*
103105
* @param fontDictionary Font dictionary.
106+
* @param resourceCache ResourceCache, can be null.
104107
*/
105-
protected PDFont(COSDictionary fontDictionary)
108+
protected PDFont(COSDictionary fontDictionary, ResourceCache resourceCache)
106109
{
107110
dict = fontDictionary;
108111
codeToWidthMap = new HashMap<>();
109112

110113
// standard 14 fonts use an AFM
111114
afmStandard14 = Standard14Fonts.getAFM(getName()); // may be null (it usually is)
112-
fontDescriptor = loadFontDescriptor();
115+
fontDescriptor = loadFontDescriptor(resourceCache);
113116
toUnicodeCMap = loadUnicodeCmap();
114117
}
115118

116-
private PDFontDescriptor loadFontDescriptor()
119+
private PDFontDescriptor loadFontDescriptor(ResourceCache resourceCache)
117120
{
121+
COSObject fdIndirectObject = dict.getCOSObject(COSName.FONT_DESC);
122+
if (fdIndirectObject != null && resourceCache != null)
123+
{
124+
PDFontDescriptor pdFontdescriptor = resourceCache.getFontDescriptor(fdIndirectObject);
125+
if (pdFontdescriptor != null)
126+
{
127+
return pdFontdescriptor;
128+
}
129+
}
118130
COSDictionary fd = dict.getCOSDictionary(COSName.FONT_DESC);
119131
if (fd != null)
120132
{
121-
return new PDFontDescriptor(fd);
133+
PDFontDescriptor pdFontdescriptor = new PDFontDescriptor(fd);
134+
if (resourceCache != null && fdIndirectObject != null)
135+
{
136+
resourceCache.put(fdIndirectObject, pdFontdescriptor);
137+
}
138+
return pdFontdescriptor;
122139
}
123140
else if (afmStandard14 != null)
124141
{
125142
// build font descriptor from the AFM
126143
return PDType1FontEmbedder.buildFontDescriptor(afmStandard14);
127144
}
128-
else
129-
{
130-
return null;
131-
}
145+
return null;
132146
}
133147

134148
private CMap loadUnicodeCmap()

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,22 +135,22 @@ public static PDFont createFont(COSDictionary dictionary, ResourceCache resource
135135
COSDictionary fd = dictionary.getCOSDictionary(COSName.FONT_DESC);
136136
if (fd != null && fd.containsKey(COSName.FONT_FILE3))
137137
{
138-
return new PDType1CFont(dictionary);
138+
return new PDType1CFont(dictionary, resourceCache);
139139
}
140-
return new PDType1Font(dictionary);
140+
return new PDType1Font(dictionary, resourceCache);
141141
}
142142
else if (COSName.MM_TYPE1.equals(subType))
143143
{
144144
COSDictionary fd = dictionary.getCOSDictionary(COSName.FONT_DESC);
145145
if (fd != null && fd.containsKey(COSName.FONT_FILE3))
146146
{
147-
return new PDType1CFont(dictionary);
147+
return new PDType1CFont(dictionary, resourceCache);
148148
}
149149
return new PDMMType1Font(dictionary);
150150
}
151151
else if (COSName.TRUE_TYPE.equals(subType))
152152
{
153-
return new PDTrueTypeFont(dictionary);
153+
return new PDTrueTypeFont(dictionary, resourceCache);
154154
}
155155
else if (COSName.TYPE3.equals(subType))
156156
{
@@ -170,7 +170,7 @@ else if (COSName.TYPE0.equals(subType))
170170
fixType0Subtype(descendantFont, fontDescriptor, fontTypeFromFont.getSubtype());
171171
}
172172
}
173-
return new PDType0Font(dictionary);
173+
return new PDType0Font(dictionary, resourceCache);
174174
}
175175
else if (COSName.CID_FONT_TYPE0.equals(subType))
176176
{
@@ -185,7 +185,7 @@ else if (COSName.CID_FONT_TYPE2.equals(subType))
185185
// assuming Type 1 font (see PDFBOX-1988) because it seems that Adobe Reader does this
186186
// however, we may need more sophisticated logic perhaps looking at the FontFile
187187
LOG.warn("Invalid font subtype '{}'", subType);
188-
return new PDType1Font(dictionary);
188+
return new PDType1Font(dictionary, resourceCache);
189189
}
190190
}
191191

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ public class PDMMType1Font extends PDType1Font
3636
*/
3737
public PDMMType1Font(COSDictionary fontDictionary) throws IOException
3838
{
39-
super(fontDictionary);
39+
super(fontDictionary, null);
4040
}
4141
}

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.pdfbox.cos.COSBase;
2828
import org.apache.pdfbox.cos.COSDictionary;
2929
import org.apache.pdfbox.cos.COSName;
30+
import org.apache.pdfbox.pdmodel.ResourceCache;
3031
import org.apache.pdfbox.pdmodel.common.PDRectangle;
3132
import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName;
3233
import org.apache.pdfbox.pdmodel.font.encoding.DictionaryEncoding;
@@ -71,10 +72,11 @@ public abstract class PDSimpleFont extends PDFont
7172
* Constructor.
7273
*
7374
* @param fontDictionary Font dictionary.
75+
* @param resourceCache ResourceCache, can be null.
7476
*/
75-
PDSimpleFont(COSDictionary fontDictionary)
77+
PDSimpleFont(COSDictionary fontDictionary, ResourceCache resourceCache)
7678
{
77-
super(fontDictionary);
79+
super(fontDictionary, resourceCache);
7880
}
7981

8082
/**

pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.apache.pdfbox.io.RandomAccessReadBuffer;
4747
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
4848
import org.apache.pdfbox.pdmodel.PDDocument;
49+
import org.apache.pdfbox.pdmodel.ResourceCache;
4950
import org.apache.pdfbox.pdmodel.common.PDRectangle;
5051
import org.apache.pdfbox.pdmodel.common.PDStream;
5152
import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName;
@@ -97,12 +98,14 @@ public class PDTrueTypeFont extends PDSimpleFont implements PDVectorFont
9798
* Creates a new TrueType font from a Font dictionary.
9899
*
99100
* @param fontDictionary The font dictionary according to the PDF specification.
101+
* @param resourceCache ResourceCache, can be null.
100102
*
101103
* @throws IOException if the font could not be created
102104
*/
103-
public PDTrueTypeFont(COSDictionary fontDictionary) throws IOException
105+
public PDTrueTypeFont(COSDictionary fontDictionary, ResourceCache resourceCache)
106+
throws IOException
104107
{
105-
super(fontDictionary);
108+
super(fontDictionary, resourceCache);
106109

107110
TrueTypeFont ttfFont = null;
108111
boolean fontIsDamaged = false;

0 commit comments

Comments
 (0)