Browse Source

FOP-2357: When an SVG image has transparency and a PDF profile is used that disallows it, ignore it and issue a warning rather than throw an error


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1577477 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Vincent Hennebert 10 years ago
parent
commit
4c131bd42f

+ 18
- 5
src/java/org/apache/fop/pdf/PDFProfile.java View File

@@ -169,15 +169,28 @@ public class PDFProfile {
* @param context Context information for the user to identify the problem spot
*/
public void verifyTransparencyAllowed(String context) {
final String err = "{0} does not allow the use of transparency. ({1})";
Object profile = isTransparencyAllowed();
if (profile != null) {
throw new PDFConformanceException(profile + " does not allow the use of transparency. ("
+ profile + ")");
}
}

/**
* Returns {@code null} if transparency is allowed, otherwise returns the profile that
* prevents it.
*
* @return {@code null}, or an object whose {@code toString} method returns the name
* of the profile that disallows transparency
*/
public Object isTransparencyAllowed() {
if (pdfAMode.isPart1()) {
throw new PDFConformanceException(MessageFormat.format(err,
new Object[] {getPDFAMode(), context}));
return getPDFAMode();
}
if (isPDFXActive()) {
throw new PDFConformanceException(MessageFormat.format(err,
new Object[] {getPDFXMode(), context}));
return getPDFXMode();
}
return null;
}

/** Checks if the right PDF version is set. */

+ 1
- 1
src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java View File

@@ -86,7 +86,7 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D {
PDFGraphics2D graphics = new PDFGraphics2D(textAsShapes,
pdfContext.getFontInfo(), generator.getDocument(),
generator.getResourceContext(), pdfContext.getPage().referencePDF(),
"", 0.0f);
"", 0.0f, null);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

AffineTransform transform = new AffineTransform();

+ 26
- 1
src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java View File

@@ -41,6 +41,7 @@ import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.image.loader.batik.BatikUtil;
import org.apache.fop.render.ImageHandler;
@@ -171,7 +172,7 @@ public class PDFImageHandlerSVG implements ImageHandler {
PDFGraphics2D graphics = new PDFGraphics2D(true, pdfContext.getFontInfo(),
generator.getDocument(),
generator.getResourceContext(), pdfContext.getPage().referencePDF(),
"", 0);
"", 0, new TransparencyIgnoredEventListener(pdfContext, imageSVG));
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

if (!resolutionScaling.isIdentity()) {
@@ -222,6 +223,30 @@ public class PDFImageHandlerSVG implements ImageHandler {
}
}

private static class TransparencyIgnoredEventListener
implements PDFGraphics2D.TransparencyIgnoredEventListener {

private final RenderingContext context;

private final Image image;

public TransparencyIgnoredEventListener(RenderingContext context, Image image) {
this.context = context;
this.image = image;
}

private boolean warningIssued;

public void transparencyIgnored(Object pdfProfile) {
if (!warningIssued) {
EventBroadcaster broadcaster = context.getUserAgent().getEventBroadcaster();
SVGEventProducer producer = SVGEventProducer.Provider.get(broadcaster);
producer.transparencyIgnored(this, pdfProfile, image.getInfo().getOriginalURI());
warningIssued = true;
}
}
}

/** {@inheritDoc} */
public int getPriority() {
return 400;

+ 32
- 15
src/java/org/apache/fop/svg/PDFGraphics2D.java View File

@@ -189,6 +189,17 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
*/
protected OutputStream outputStream = null;

private TransparencyIgnoredEventListener transparencyIgnoredEventListener;

/**
* May be used to give proper feedback to the user when a particular PDF profile is
* being used that disallows transparency.
*/
public interface TransparencyIgnoredEventListener {

void transparencyIgnored(Object pdfProfile);
}

/**
* Create a new PDFGraphics2D with the given pdf document info.
* This is used to create a Graphics object for use inside an already
@@ -203,7 +214,8 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
* @param size the current font size
*/
public PDFGraphics2D(boolean textAsShapes, FontInfo fi, PDFDocument doc,
PDFResourceContext page, String pref, String font, float size) {
PDFResourceContext page, String pref, String font, float size,
TransparencyIgnoredEventListener listener) {
this(textAsShapes);
pdfDoc = doc;
this.colorHandler = new PDFColorHandler(doc.getResources());
@@ -213,6 +225,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
fontInfo = fi;
pageRef = pref;
paintingState = new PDFPaintingState();
this.transparencyIgnoredEventListener = listener;
}

/**
@@ -244,6 +257,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
this.nativeCount = g.nativeCount;
this.outputStream = g.outputStream;
this.ovFontState = g.ovFontState;
this.transparencyIgnoredEventListener = g.transparencyIgnoredEventListener;
}

/**
@@ -977,7 +991,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
PDFResourceContext context = new PDFResourceContext(res);
PDFGraphics2D pattGraphic = new PDFGraphics2D(textAsShapes, specialFontInfo,
pdfDoc, context, getPageReference(),
"", 0);
"", 0, transparencyIgnoredEventListener);
pattGraphic.setGraphicContext(new GraphicContext());
pattGraphic.gc.validateTransformStack();
pattGraphic.setRenderingHints(this.getRenderingHints());
@@ -1430,18 +1444,21 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
*/
protected void applyAlpha(int fillAlpha, int strokeAlpha) {
if (fillAlpha != OPAQUE || strokeAlpha != OPAQUE) {
checkTransparencyAllowed();
Map<String, Float> vals = new java.util.HashMap<String, Float>();
if (fillAlpha != OPAQUE) {
vals.put(PDFGState.GSTATE_ALPHA_NONSTROKE, new Float(fillAlpha / 255f));
}
if (strokeAlpha != OPAQUE) {
vals.put(PDFGState.GSTATE_ALPHA_STROKE, new Float(strokeAlpha / 255f));
Object profile = isTransparencyAllowed();
if (profile == null) {
Map<String, Float> vals = new java.util.HashMap<String, Float>();
if (fillAlpha != OPAQUE) {
vals.put(PDFGState.GSTATE_ALPHA_NONSTROKE, new Float(fillAlpha / 255f));
}
if (strokeAlpha != OPAQUE) {
vals.put(PDFGState.GSTATE_ALPHA_STROKE, new Float(strokeAlpha / 255f));
}
PDFGState gstate = pdfDoc.getFactory().makeGState(vals, paintingState.getGState());
resourceContext.addGState(gstate);
currentStream.write("/" + gstate.getName() + " gs\n");
} else if (transparencyIgnoredEventListener != null) {
transparencyIgnoredEventListener.transparencyIgnored(profile);
}
PDFGState gstate = pdfDoc.getFactory().makeGState(
vals, paintingState.getGState());
resourceContext.addGState(gstate);
currentStream.write("/" + gstate.getName() + " gs\n");
}
}

@@ -1686,8 +1703,8 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand
}

/** Checks whether the use of transparency is allowed. */
protected void checkTransparencyAllowed() {
pdfDoc.getProfile().verifyTransparencyAllowed("Java2D graphics");
protected Object isTransparencyAllowed() {
return pdfDoc.getProfile().isTransparencyAllowed();
}

/**

+ 9
- 0
src/java/org/apache/fop/svg/SVGEventProducer.java View File

@@ -89,4 +89,13 @@ public interface SVGEventProducer extends EventProducer {
*/
void svgRenderingError(Object source, Exception e, String uri);

/**
* Transparency has been ignored due to restrictions from the PDF profile being used.
* @param source the event source
* @param pdfProfile the PDF profile
* @param uri the image URI, if available
* @event.severity WARN
*/
void transparencyIgnored(Object source, Object pdfProfile, String uri);

}

+ 1
- 0
src/java/org/apache/fop/svg/SVGEventProducer.xml View File

@@ -22,4 +22,5 @@
<message key="info">SVG info: {message}</message>
<message key="svgNotBuilt">SVG graphic could not be built. Reason: {e}</message>
<message key="svgRenderingError">SVG graphic could not be rendered. Reason: {e}</message>
<message key="transparencyIgnored">Transparency in an SVG image will be ignored because {pdfProfile} does not allow it[ (see {uri})].</message>
</catalogue>

+ 4
- 4
test/java/org/apache/fop/events/EventChecker.java View File

@@ -27,7 +27,7 @@ import static org.junit.Assert.fail;
/**
* Class that checks that an expected event is produced, and only this one.
*/
class EventChecker implements EventListener {
public class EventChecker implements EventListener {

private final String expectedEventID;

@@ -35,7 +35,7 @@ class EventChecker implements EventListener {

private boolean eventReceived;

EventChecker(String expectedEventID, Map<String, Object> expectedParams) {
public EventChecker(String expectedEventID, Map<String, Object> expectedParams) {
this.expectedEventID = expectedEventID;
this.expectedParams = expectedParams;
}
@@ -51,9 +51,9 @@ class EventChecker implements EventListener {
}
}

void end() {
public void end() {
if (!eventReceived) {
fail("Did not received expected event: " + expectedEventID);
fail("Did not receive expected event: " + expectedEventID);
}
}
}

+ 18
- 0
test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java View File

@@ -21,6 +21,8 @@ package org.apache.fop.render.pdf;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.xml.sax.SAXException;
@@ -28,7 +30,10 @@ import org.xml.sax.SAXException;
import static org.junit.Assert.fail;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.EventChecker;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.svg.SVGEventProducer;

/**
* Tests PDF/A-1 functionality.
@@ -108,4 +113,17 @@ public class PDFAConformanceTestCase extends BasePDFTest {
}
}

@Test
public void svgTransparency() throws Exception {
Map<String, Object> params = new HashMap<String, Object>();
params.put("pdfProfile", PDFAMode.PDFA_1B);
EventChecker eventChecker = new EventChecker(SVGEventProducer.class.getName()
+ ".transparencyIgnored", params);
FOUserAgent ua = getUserAgent();
ua.getEventBroadcaster().addEventListener(eventChecker);
File foFile = new File(foBaseDir, "svg-transparency.fo");
convertFO(foFile, ua, dumpPDF);
eventChecker.end();
}

}

+ 1
- 1
test/java/org/apache/fop/svg/PDFTextPainterTestCase.java View File

@@ -36,7 +36,7 @@ public class PDFTextPainterTestCase extends NativeTextPainterTest {
private static class OperatorCheckingPDFGraphics2D extends PDFGraphics2D {

OperatorCheckingPDFGraphics2D(FontInfo fontInfo, final OperatorValidator validator) {
super(false, fontInfo, new PDFDocument("test"), null, null, null, 0);
super(false, fontInfo, new PDFDocument("test"), null, null, null, 0, null);
this.currentStream = new StringWriter() {

@Override

+ 24
- 0
test/xml/pdf-a/svg-transparency.fo View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Gladiator">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="420pt" page-width="620pt" margin="10pt">
<fo:region-body display-align="center"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" text-align="center">
<fo:block font-size="20pt">RGB Circles</fo:block>
<fo:block><fo:instream-foreign-object>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="286.6">
<g style="fill-opacity:0.7; stroke:black; stroke-width:3"
transform="translate(0, 286.6) scale(1, -1) translate(100, 100)">
<circle cx="50" cy="86.6" r="80" style="fill:red;"/>
<circle cx="0" cy="0" r="80" style="fill:green;"/>
<circle cx="100" cy="0" r="80" style="fill:blue;"/>
</g>
</svg>
</fo:instream-foreign-object></fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

Loading…
Cancel
Save