From d9382798459f9f07eaefa86591afcf7038d73a3d Mon Sep 17 00:00:00 2001 From: torakiki Date: Wed, 3 Mar 2021 14:40:19 +0100 Subject: [PATCH] SetGraphicState operator to just ignore non existing values (same as PDFBox one) instead of throwing an exception. Update the context in case of a valid ExtGState (same as PDFBox but without caching) --- .../optimization/ResourcesHitter.java | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/optimization/ResourcesHitter.java b/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/optimization/ResourcesHitter.java index d8350391c..bc23723e9 100644 --- a/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/optimization/ResourcesHitter.java +++ b/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/optimization/ResourcesHitter.java @@ -18,6 +18,7 @@ */ package org.sejda.impl.sambox.component.optimization; +import static java.util.Objects.nonNull; import static java.util.Optional.ofNullable; import static org.sejda.commons.util.RequireUtils.require; import static org.sejda.sambox.contentstream.operator.OperatorName.DRAW_OBJECT; @@ -49,6 +50,7 @@ import org.sejda.sambox.pdmodel.graphics.PDXObject; import org.sejda.sambox.pdmodel.graphics.form.PDFormXObject; import org.sejda.sambox.pdmodel.graphics.form.PDTransparencyGroup; +import org.sejda.sambox.pdmodel.graphics.state.PDExtendedGraphicsState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -202,37 +204,43 @@ public void process(Operator operator, List operands) throws IOExceptio .map(r -> r.getCOSObject().getDictionaryObject(COSName.EXT_G_STATE, COSDictionary.class)); COSDictionary gsDictionary = states.map(d -> d.getDictionaryObject(gsName, COSDictionary.class)) - .orElseThrow(() -> new MissingResourceException( - "Graphic state resource '" + gsName.getName() + "' missing or unexpected type")); + .orElseGet(() -> { + LOG.warn("Graphic state resource '{}' missing or unexpected type", gsName.getName()); + return null; + }); - if (!(gsDictionary instanceof InUseDictionary)) { - // we wrap the existing so we can identify it later as "in use" and already processed - if (gsDictionary.hasId()) { - LOG.trace("Hit ExtGState with name {} id {}", gsName.getName(), gsDictionary.id()); - // we wrap reuse the InUseFont if we hit it before - states.get().setItem(gsName, ofNullable(hitGSById.get(gsDictionary.id())).orElseGet(() -> { - InUseDictionary gs = new InUseDictionary(gsDictionary); - hitGSById.put(gsDictionary.id(), gs); - return gs; - })); - } else { - // not an indirect ref (so without id) - LOG.trace("Hit ExtGState with name {}", gsName.getName()); - states.get().setItem(gsName, new InUseDictionary(gsDictionary)); - } + if (nonNull(gsDictionary)) { + + new PDExtendedGraphicsState(gsDictionary).copyIntoGraphicsState(getContext().getGraphicsState()); + if (!(gsDictionary instanceof InUseDictionary)) { + // we wrap the existing so we can identify it later as "in use" and already processed + if (gsDictionary.hasId()) { + LOG.trace("Hit ExtGState with name {} id {}", gsName.getName(), gsDictionary.id()); + // we wrap reuse the InUseFont if we hit it before + states.get().setItem(gsName, ofNullable(hitGSById.get(gsDictionary.id())).orElseGet(() -> { + InUseDictionary gs = new InUseDictionary(gsDictionary); + hitGSById.put(gsDictionary.id(), gs); + return gs; + })); + } else { + // not an indirect ref (so without id) + LOG.trace("Hit ExtGState with name {}", gsName.getName()); + states.get().setItem(gsName, new InUseDictionary(gsDictionary)); + } - // ExtGState can contain a softmask dictionary in the form of a transparency group XObject. If present we process its stream to hit used resources - Optional softMask = ofNullable( - gsDictionary.getDictionaryObject(COSName.SMASK, COSDictionary.class)) - .map(d -> d.getDictionaryObject(COSName.G, COSStream.class)) - .filter(s -> COSName.FORM.getName().equals(s.getNameAsString(COSName.SUBTYPE))); - if (softMask.isPresent()) { - PDXObject xobject = PDXObject.createXObject(softMask.get(), getContext().getResources()); - // should always be transparency - if (xobject instanceof PDTransparencyGroup) { - getContext().showTransparencyGroup((PDTransparencyGroup) xobject); - } else if (xobject instanceof PDFormXObject) { - getContext().showForm((PDFormXObject) xobject); + // ExtGState can contain a softmask dictionary in the form of a transparency group XObject. If present we process its stream to hit used resources + Optional softMask = ofNullable( + gsDictionary.getDictionaryObject(COSName.SMASK, COSDictionary.class)) + .map(d -> d.getDictionaryObject(COSName.G, COSStream.class)) + .filter(s -> COSName.FORM.getName().equals(s.getNameAsString(COSName.SUBTYPE))); + if (softMask.isPresent()) { + PDXObject xobject = PDXObject.createXObject(softMask.get(), getContext().getResources()); + // should always be transparency + if (xobject instanceof PDTransparencyGroup) { + getContext().showTransparencyGroup((PDTransparencyGroup) xobject); + } else if (xobject instanceof PDFormXObject) { + getContext().showForm((PDFormXObject) xobject); + } } } }