/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: AFPSVGHandler.java 1664570 2015-03-06 09:41:07Z lbernardo $ */

package org.apache.fop.render.afp;

// FOP
import java.awt.Dimension;
import java.awt.geom.AffineTransform;
import java.io.IOException;

import org.w3c.dom.Document;

import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DefaultFontFamilyResolver;
import org.apache.batik.gvt.GraphicsNode;

import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.xmlgraphics.util.MimeConstants;

import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.afp.AFPGraphicsObjectInfo;
import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.AFPUnitConverter;
import org.apache.fop.afp.svg.AFPBridgeContext;
import org.apache.fop.afp.svg.AFPFontFamilyResolver;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.image.loader.batik.BatikUtil;
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl;
import org.apache.fop.render.AbstractGenericSVGHandler;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RendererContext.RendererContextWrapper;
import org.apache.fop.svg.SVGEventProducer;
import org.apache.fop.svg.SVGUserAgent;
import org.apache.fop.svg.font.AggregatingFontFamilyResolver;

AFP XML handler for SVG. Uses Apache Batik for SVG processing. This handler handles XML for foreign objects and delegates to AFPGraphics2DAdapter.
See Also:
  • AFPGraphics2DAdapter
/** * AFP XML handler for SVG. Uses Apache Batik for SVG processing. * This handler handles XML for foreign objects and delegates to AFPGraphics2DAdapter. * @see AFPGraphics2DAdapter */
public class AFPSVGHandler extends AbstractGenericSVGHandler { private boolean paintAsBitmap;
{@inheritDoc}
/** {@inheritDoc} */
public void handleXML(RendererContext context, Document doc, String ns) throws Exception { if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) { renderSVGDocument(context, doc); } }
Render the SVG document.
Params:
  • rendererContext – the renderer context
  • doc – the SVG document
Throws:
  • IOException – In case of an I/O error while painting the image
/** * Render the SVG document. * * @param rendererContext the renderer context * @param doc the SVG document * @throws IOException In case of an I/O error while painting the image */
protected void renderSVGDocument(final RendererContext rendererContext, final Document doc) throws IOException { AFPRendererContext afpRendererContext = (AFPRendererContext)rendererContext; AFPInfo afpInfo = afpRendererContext.getInfo(); this.paintAsBitmap = afpInfo.paintAsBitmap(); FOUserAgent userAgent = rendererContext.getUserAgent(); // fallback paint as bitmap String uri = getDocumentURI(doc); if (paintAsBitmap) { try { super.renderSVGDocument(rendererContext, doc); } catch (IOException ioe) { SVGEventProducer eventProducer = SVGEventProducer.Provider.get( userAgent.getEventBroadcaster()); eventProducer.svgRenderingError(this, ioe, uri); } return; } // Create a new AFPGraphics2D final boolean textAsShapes = afpInfo.strokeText(); AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); AFPPaintingState paintingState = g2d.getPaintingState(); paintingState.setImageUri(uri); // Create an AFPBridgeContext BridgeContext bridgeContext = createBridgeContext(userAgent, g2d); //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) //to it. Document clonedDoc = BatikUtil.cloneSVGDocument(doc); // Build the SVG DOM and provide the painter with it GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc); // Create Graphics2DImagePainter final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext(rendererContext); Dimension imageSize = getImageSize(wrappedContext); Graphics2DImagePainter painter = createGraphics2DImagePainter(bridgeContext, root, imageSize); // Create AFPObjectAreaInfo RendererContextWrapper rctx = RendererContext.wrapRendererContext(rendererContext); int x = rctx.getCurrentXPosition(); int y = rctx.getCurrentYPosition(); int width = afpInfo.getWidth(); int height = afpInfo.getHeight(); int resolution = afpInfo.getResolution(); paintingState.save(); // save AFPObjectAreaInfo objectAreaInfo = createObjectAreaInfo(paintingState, x, y, width, height, resolution); // Create AFPGraphicsObjectInfo AFPResourceInfo resourceInfo = afpInfo.getResourceInfo(); AFPGraphicsObjectInfo graphicsObjectInfo = createGraphicsObjectInfo( paintingState, painter, userAgent, resourceInfo, g2d); graphicsObjectInfo.setObjectAreaInfo(objectAreaInfo); // Create the GOCA GraphicsObject in the DataStream AFPResourceManager resourceManager = afpInfo.getResourceManager(); resourceManager.createObject(graphicsObjectInfo); paintingState.restore(); // resume } private AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, int x, int y, int width, int height, int resolution) { // set the data object parameters AffineTransform at = paintingState.getData().getTransform(); at.translate(x, y); AFPUnitConverter unitConv = paintingState.getUnitConverter(); int rotation = paintingState.getRotation(); int objX = (int) Math.round(at.getTranslateX()); int objY = (int) Math.round(at.getTranslateY()); int objWidth = Math.round(unitConv.mpt2units(width)); int objHeight = Math.round(unitConv.mpt2units(height)); AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(objX, objY, objWidth, objHeight, resolution, rotation); return objectAreaInfo; } private AFPGraphicsObjectInfo createGraphicsObjectInfo( AFPPaintingState paintingState, Graphics2DImagePainter painter, FOUserAgent userAgent, AFPResourceInfo resourceInfo, AFPGraphics2D g2d) { AFPGraphicsObjectInfo graphicsObjectInfo = new AFPGraphicsObjectInfo(); String uri = paintingState.getImageUri(); graphicsObjectInfo.setUri(uri); graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); graphicsObjectInfo.setResourceInfo(resourceInfo); graphicsObjectInfo.setPainter(painter); // Set the afp graphics 2d implementation graphicsObjectInfo.setGraphics2D(g2d); return graphicsObjectInfo; }
Params:
  • userAgent – a user agent instance
  • g2d – a graphics context
Returns:a bridge context
/** * @param userAgent a user agent instance * @param g2d a graphics context * @return a bridge context */
public static BridgeContext createBridgeContext(FOUserAgent userAgent, AFPGraphics2D g2d) { ImageManager imageManager = userAgent.getImageManager(); FontInfo fontInfo = g2d.getFontInfo(); SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new AggregatingFontFamilyResolver(new AFPFontFamilyResolver(fontInfo, userAgent.getEventBroadcaster()), DefaultFontFamilyResolver.SINGLETON), new AffineTransform()); ImageSessionContext imageSessionContext = userAgent.getImageSessionContext(); return new AFPBridgeContext(svgUserAgent, fontInfo, imageManager, imageSessionContext, new AffineTransform(), g2d, userAgent.getEventBroadcaster()); }
{@inheritDoc}
/** {@inheritDoc} */
public boolean supportsRenderer(Renderer renderer) { return false; }
{@inheritDoc}
/** {@inheritDoc} */
protected void updateRendererContext(RendererContext context) { //Work around a problem in Batik: Gradients cannot be done in ColorSpace.CS_GRAY context.setProperty(AFPRendererContextConstants.AFP_GRAYSCALE, Boolean.FALSE); } private Graphics2DImagePainter createGraphics2DImagePainter(BridgeContext ctx, GraphicsNode root, Dimension imageSize) { Graphics2DImagePainter painter = null; if (paintAsBitmap()) { // paint as IOCA Image painter = super.createGraphics2DImagePainter(root, ctx, imageSize); } else { // paint as GOCA Graphics painter = new Graphics2DImagePainterImpl(root, ctx, imageSize); } return painter; }
Returns true if the SVG is to be painted as a bitmap
Returns:true if the SVG is to be painted as a bitmap
/** * Returns true if the SVG is to be painted as a bitmap * * @return true if the SVG is to be painted as a bitmap */
private boolean paintAsBitmap() { return paintAsBitmap; } }