|
20 | 20 | import java.io.IOException; |
21 | 21 | import java.io.InputStream; |
22 | 22 | import java.util.ArrayList; |
| 23 | +import java.util.Collections; |
23 | 24 | import java.util.Iterator; |
24 | 25 | import java.util.List; |
25 | 26 | import java.util.stream.Collectors; |
|
46 | 47 | import org.apache.pdfbox.pdmodel.common.PDMetadata; |
47 | 48 | import org.apache.pdfbox.pdmodel.common.PDRectangle; |
48 | 49 | import org.apache.pdfbox.pdmodel.common.PDStream; |
| 50 | +import org.apache.pdfbox.pdmodel.graphics.PDXObject; |
| 51 | +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; |
49 | 52 | import org.apache.pdfbox.pdmodel.interactive.action.PDPageAdditionalActions; |
50 | 53 | import org.apache.pdfbox.pdmodel.interactive.annotation.AnnotationFilter; |
51 | 54 | import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; |
@@ -114,6 +117,64 @@ public PDPage(COSDictionary pageDictionary) |
114 | 117 | this.resourceCache = resourceCache; |
115 | 118 | } |
116 | 119 |
|
| 120 | + /** |
| 121 | + * Remove all page resources from the cache to avoid relying on the implementation of the Cache. Does make sense |
| 122 | + * after processing a page. |
| 123 | + */ |
| 124 | + public void removePageResourceFromCache() |
| 125 | + { |
| 126 | + if (resourceCache == null) |
| 127 | + { |
| 128 | + return; |
| 129 | + } |
| 130 | + // limit purge operation to page resources, don't remove inherited resources |
| 131 | + removeResources(page.getCOSDictionary(COSName.RESOURCES)); |
| 132 | + } |
| 133 | + |
| 134 | + private void removeResources(COSDictionary resources) |
| 135 | + { |
| 136 | + if (resources == null) |
| 137 | + { |
| 138 | + return; |
| 139 | + } |
| 140 | + getIndirectResourceObjects(resources, COSName.COLORSPACE) |
| 141 | + .forEach(resourceCache::removeColorSpace); |
| 142 | + getIndirectResourceObjects(resources, COSName.EXT_G_STATE) |
| 143 | + .forEach(resourceCache::removeExtState); |
| 144 | + getIndirectResourceObjects(resources, COSName.FONT) |
| 145 | + .forEach(resourceCache::removeFont); |
| 146 | + getIndirectResourceObjects(resources, COSName.PATTERN) |
| 147 | + .forEach(resourceCache::removePattern); |
| 148 | + getIndirectResourceObjects(resources, COSName.PROPERTIES) |
| 149 | + .forEach(resourceCache::removeProperties); |
| 150 | + getIndirectResourceObjects(resources, COSName.SHADING) |
| 151 | + .forEach(resourceCache::removeShading); |
| 152 | + for (COSObject cosObject : getIndirectResourceObjects(resources, COSName.XOBJECT)) |
| 153 | + { |
| 154 | + PDXObject removedXObject = resourceCache.removeXObject(cosObject); |
| 155 | + // clean up the resources of the XFormObject |
| 156 | + if (removedXObject instanceof PDFormXObject) |
| 157 | + { |
| 158 | + COSStream cosStream = removedXObject.getCOSObject(); |
| 159 | + removeResources(cosStream.getCOSDictionary(COSName.RESOURCES)); |
| 160 | + } |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + private List<COSObject> getIndirectResourceObjects(COSDictionary pageResources, COSName kind) |
| 165 | + { |
| 166 | + COSDictionary resourcesDictionary = pageResources.getCOSDictionary(kind); |
| 167 | + if (resourcesDictionary == null) |
| 168 | + { |
| 169 | + return Collections.emptyList(); |
| 170 | + } |
| 171 | + return resourcesDictionary.getValues().stream() // |
| 172 | + .filter(f -> f instanceof COSObject) // |
| 173 | + .map(f -> (COSObject) f) // |
| 174 | + .filter(COSObject::isDereferenced) // |
| 175 | + .collect(Collectors.toList()); |
| 176 | + } |
| 177 | + |
117 | 178 | /** |
118 | 179 | * Convert this standard java object to a COS object. |
119 | 180 | * |
|
0 commit comments