You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by Apache Wiki <wi...@apache.org> on 2006/03/05 15:44:23 UTC

[Xmlgraphics-batik Wiki] Update of "DynamicSvgOffscreen" by ThomasDeWeese

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Xmlgraphics-batik Wiki" for change notification.

The following page has been changed by ThomasDeWeese:
http://wiki.apache.org/xmlgraphics-batik/DynamicSvgOffscreen

New page:
##language:en
== Rendering a dynamic SVG document to an offscreen buffer ==

It can be helpful in some circumstance to render a Dynamic SVG document
not to the screen but to an offscreen buffer.  This is most useful when
you have a large SVG Document that you want to output as JPEG or PNG
with a few minor variations from rendering to rendering.

By treating the "template" document as a dynamic document where you
just modify small pieces you can avoid the overhead of rereading and
parsing the SVG, as well as the building of the Rendering tree from
that SVG document (which involves parsing many attributes, performing
CSS cascade etc.

The following example takes the filename on the command line of a 'base' 
document to read, it then creates a 'dynamic' rect on top of the document
and renders the document with the rect moving across the top of the
document.  It renders the images to a BufferedImage which it then writes
to a sequence of PNG files. 

=== Example ===
{{{
package org.example;

import java.awt.geom.AffineTransform;
import java.awt.Rectangle;
import java.io.File;
import java.io.OutputStream;
import java.io.IOException;
import java.io.FileOutputStream;
import java.net.MalformedURLException;
import java.util.List;

import org.apache.batik.ext.awt.image.codec.PNGEncodeParam;
import org.apache.batik.ext.awt.image.codec.PNGImageEncoder;

import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.BridgeException;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UpdateManager;
import org.apache.batik.bridge.UpdateManagerAdapter;
import org.apache.batik.bridge.UpdateManagerEvent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.util.RunnableQueue;
import org.apache.batik.util.XMLResourceDescriptor;
import org.apache.batik.gvt.CanvasGraphicsNode;
import org.apache.batik.gvt.CompositeGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory;
import org.apache.batik.gvt.renderer.ImageRenderer;
import org.apache.batik.gvt.renderer.ImageRendererFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;


public class TestOffScreenRender {
    static final String SVGNS = "http://www.w3.org/2000/svg";

    Document document;
    UserAgentAdapter userAgent;
    GVTBuilder builder;
    BridgeContext ctx;
    ImageRenderer renderer;
    AffineTransform curTxf;
    UpdateManager manager;
    GraphicsNode gvtRoot;
    int DISPLAY_WIDTH = 1280;
    int DISPLAY_HEIGHT = 1024;


    public TestOffScreenRender (Document doc) {
        userAgent = new UserAgentAdapter();
        ctx       = new BridgeContext(userAgent);
        builder   = new GVTBuilder();
        document  = doc;
    }

    public void init() {
        GraphicsNode gvtRoot = null ;

        try {
            ctx.setDynamicState(BridgeContext.DYNAMIC);
            gvtRoot = builder.build(ctx, document);
        }
        catch (BridgeException e) { 
            e.printStackTrace(); 
            System.exit(1);
        }

        ImageRendererFactory rendererFactory;
        rendererFactory = new ConcreteImageRendererFactory();
        renderer        = rendererFactory.createDynamicImageRenderer();
        renderer.setDoubleBuffered(true);

        float docWidth  = (float) ctx.getDocumentSize().getWidth();
        float docHeight = (float) ctx.getDocumentSize().getHeight();

        float xscale = DISPLAY_WIDTH/docWidth;
        float yscale = DISPLAY_HEIGHT/docHeight;
        float scale = Math.min(xscale, yscale);

        AffineTransform px  = AffineTransform.getScaleInstance(scale, scale);

        double tx = -0 + (DISPLAY_WIDTH/scale - docWidth)/2;
        double ty = -0 + (DISPLAY_WIDTH/scale - docHeight)/2;
        px.translate(tx, ty);
        CanvasGraphicsNode cgn = getGraphicsNode(gvtRoot);
        if (cgn != null) {
            cgn.setViewingTransform(px);
            curTxf = new AffineTransform();
        } else {
            curTxf = px;
        }
        manager = new UpdateManager(ctx, gvtRoot, document);
        manager.setMinRepaintTime(-1);

        renderer.updateOffScreen(DISPLAY_WIDTH, DISPLAY_HEIGHT);
        renderer.setTree(gvtRoot);
        renderer.setTransform(curTxf);
        renderer.clearOffScreen();
        renderer.repaint(new Rectangle(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
        manager.addUpdateManagerListener(new UpdateManagerAdapter() {
                public void updateCompleted(UpdateManagerEvent e) {
                    render(e.getImage());
                }

                public void managerSuspended(UpdateManagerEvent e) {
                    // Make sure pending updates are completed.
                    System.exit(0);
                }
            });
        manager.manageUpdates(renderer);
        this.gvtRoot = gvtRoot;
    }

    private CanvasGraphicsNode getGraphicsNode(GraphicsNode gn) {
        if (!(gn instanceof CompositeGraphicsNode))
            return null;
        CompositeGraphicsNode cgn = (CompositeGraphicsNode) gn;
        List children = cgn.getChildren();
        if(children.size() == 0)
            return null;
        gn = (GraphicsNode) children.get(0);
        if (!(gn instanceof CanvasGraphicsNode))
            return null;
        return (CanvasGraphicsNode) gn;

    }

    int imgCount = 1;
    public void render(java.awt.image.BufferedImage img) {
        // paint the image or stream the image to the client display
        try {
            String file = "frame."+(imgCount++)+".png";
            System.err.println("Output: " + file);
            OutputStream os = new FileOutputStream(file);
            
            PNGEncodeParam params = PNGEncodeParam.getDefaultEncodeParam(img);
            PNGImageEncoder pngEncoder = new PNGImageEncoder(os, params);
            pngEncoder.encode(img);
            os.flush();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        String docStr = args[0];
        
        String xmlParser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory df;
        df = new SAXSVGDocumentFactory(xmlParser);
        Document doc = null;
        TestOffScreenRender render = null;
        Element r=null;
        try {
            File f = new File(docStr);
            doc = df.createSVGDocument(f.toURL().toString());
            r = doc.createElementNS(SVGNS, "rect");
            r.setAttributeNS(null, "x", "100");
            r.setAttributeNS(null, "y", "200");
            r.setAttributeNS(null, "width", "200");
            r.setAttributeNS(null, "height", "150");
            r.setAttributeNS(null, "fill", "crimson");
            r.setAttributeNS(null, "stroke", "gold");
            r.setAttributeNS(null, "stroke-width", "3");
            doc.getDocumentElement().appendChild(r);
            render = new TestOffScreenRender(doc);
            render.init();
        } catch (IOException ioe) {
            ioe.printStackTrace();
            System.exit(0);
        }

        final Element rect = r;

        RunnableQueue rq = render.manager.getUpdateRunnableQueue();
        for (int i=1; i<10; i++) {
            final int x = 100+ (i*10);
            try {
                rq.invokeAndWait(new Runnable() {
                        public void run() {
                            rect.setAttributeNS(null, "x", ""+x);
                        }
                    });
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
        render.manager.suspend();
    }
}

}}}