You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by Mike Whittemore <mi...@gmail.com> on 2005/11/06 04:48:12 UTC

Roundtrip Java2D Shape -> SVG File -> Java2D Shape

I've spent countless hours trying to get this to work. I simply want to be able
to save some Java2D shapes to an SVG file, and then later read the file back in
and reconstitute my Java2D shapes. I know my code for reading SVG files into
Jaava2D shapes works, as I've used an external program to generate SVG files and
my code successfully reads them in. I know my code for writing shapes to SVG
files works, as I've examined the generated files with an SVG viewer and can see
they are correct. The problem is that when I save to SVG with Batik, and then
try to read the file back in with Batik, I get an endless loop. I do not get
this with files generated by other SVG programs.

I would appreciate guidance on how to get this roundtripping to work. Thanks in
advance. -Mike

Some ugly test code to illustrate what I'm doing in my application:

//////////////////////////////////////
// The Test                         //
//////////////////////////////////////
import org.apache.batik.dom.*;
import org.apache.batik.svggen.*;
import org.w3c.dom.*;

import java.awt.*;
import java.awt.geom.*;
import java.io.*;

public class BatikRoundtripTest {

    public void execute() throws Exception {

        //
        // Write Java2D Shape to SVG File
        //

        DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();

        Document document = domImpl.createDocument(null, "svg", null);
        SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
        svgGenerator.setSVGCanvasSize(new Dimension(200, 200));

        paint(svgGenerator);

        boolean useCSS = true;
        Writer out = new FileWriter(new File("C:\\rectangle.svg"));
        svgGenerator.stream(out, useCSS);
        out.close();

        //
        // Read same SVG File into Java2D Shape (endless loop when reading
        // files generated by Batik)
        //

        ShapeLoader shapeloader = new ShapeLoader("C:\\rectangle.svg", 0);
        shapeloader.run();
        Shape s = shapeloader.getShape();
        System.out.println("True or false, the shape null? " + (s == null));
     }

    public void paint(Graphics2D g2d) {
        Rectangle2D r = new Rectangle2D.Double(0.0, 0.0, 100.0, 100.0);
        g2d.fill(r);
    }

    public static void main(String[] args) throws Exception {
        new BatikRoundtripTest().execute();
    }

}

/////////////////////////////////////////////////////////////
// A helper file for loading SVG files into JAVA 2D shapes //
/////////////////////////////////////////////////////////////

import org.apache.batik.gvt.*;
import org.apache.batik.swing.svg.*;

import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.List;

public class ShapeLoader extends Thread {

    private JSVGComponent component = new JSVGComponent();
    private List<Shape> shapes = new LinkedList<Shape>();
    private String shapeFile;
    private int shapeIndex;
    private boolean shapesLoaded = false;
    private Shape shape;

    public ShapeLoader(final String shapeFile, final int shapeIndex) {

        this.shapeFile = shapeFile;
        this.shapeIndex = shapeIndex;

        component.addGVTTreeBuilderListener(

            new GVTTreeBuilderAdapter() {

                public void gvtBuildCompleted(GVTTreeBuilderEvent event) {

                    super.gvtBuildCompleted(event);

                    GVTTreeWalker treeWalker = new
GVTTreeWalker(event.getGVTRoot());

                    GraphicsNode graphicsNode = null;

                    while((graphicsNode = treeWalker.nextGraphicsNode()) != null) {
                        shapes.add(graphicsNode.getOutline());
                    }

                    shapesLoaded = true;
                }
            }
        );
    }

    public void run() {
        loadShape();
    }

    public Shape getShape() {
        return shape;
    }

    public synchronized void loadShape() {

       try {
            String urlString = new
File(shapeFile).getAbsoluteFile().toURL().toString();
            System.out.println(urlString + " loading...");

            component.loadSVGDocument(urlString);

            while(shapesLoaded != true) {

                // TODO: need timeout - file not found is endless loop

                try {
                    wait(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();  // TODO: better error handling
                }
            }

           System.out.println(urlString + " loaded.");
        }
        catch (MalformedURLException e) {
            e.printStackTrace();        // TODO: better error handling
        }

        shape = shapes.get(shapeIndex);
        shapes.clear();
    }
}



---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Roundtrip Java2D Shape -> SVG File -> Java2D Shape

Posted by Mike Whittemore <mi...@gmail.com>.
>From picking through other people's posts I've found a better way to load the
generated SVG file (new, yet still ugly code pasted below). When I used it on my
Batik generated svg file, it did not endlessly wait for the document to load,
but instead gave me an error describing that my svg file's encoding was not
supported. After some playing around, I changed the way I was saving my SVG file
to this:

    boolean useCSS = true;
    FileOutputStream fileOutputStream = new FileOutputStream("C:\\rectangle.svg");
    OutputStreamWriter outputStreamWriter = new
OutputStreamWriter(fileOutputStream, "UTF-8");
    svgGenerator.stream(outputStreamWriter, useCSS);

The trick was to manually set the character encoding. No one reponded to my post
directly, but thank you all for posting your code snippets that allowed me to
move along on my issue.

The improved (but still very ugly) mechanism for loading the SCG file:

public static void main(String[] args) {

    UserAgent      userAgent;
    DocumentLoader loader;
    BridgeContext  ctx;
    GVTBuilder     builder;
    Document doc = null;

    try {
        String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
        String uri = "file:\\c:\\rectangle.svg";
        doc = f.createDocument(uri);
    } catch (IOException ex) {
         ex.printStackTrace();
    }


    userAgent = new UserAgentAdapter();
    loader    = new DocumentLoader(userAgent);
    ctx       = new BridgeContext(userAgent, loader);
    ctx.setDynamicState(BridgeContext.DYNAMIC);
    builder   = new GVTBuilder();
    GraphicsNode graphicsNode =  builder.build(ctx, doc);

    GVTTreeWalker treeWalker = new GVTTreeWalker(graphicsNode);

    Set<Shape> shapes = new HashSet<Shape>();

    while((graphicsNode = treeWalker.nextGraphicsNode()) != null) {
        shapes.add(graphicsNode.getOutline());
    }

    System.out.println("TOTAL SHAPES LOADED: " + shapes.size());
}



---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Roundtrip Java2D Shape -> SVG File -> Java2D Shape

Posted by th...@kodak.com.
Hi Mike,

        The 'endless loop' in your example code is just the Swing Event 
loop.
Since you are creating a Java Component (the JSVGCanvas) the swing
event loop starts and it keeps the application from exiting when main 
finishes.

        The "solution" in this case is just to call System.exit(0) at the 
end of
your main function.

        Another possible solution would be to avoid using the JSVGCanvas
to create the GVT tree and instead build it yourself:

        http://wiki.apache.org/xmlgraphics-batik/BootSvgAndCssDom

        Also you might want to look at some of the thread methods like
'notify' or  Thread.join, they are much better for thread synchronization 
than
busy waiting.  Also be aware that accessing a variable across threads is
not guaranteed to work unless you cross a 'memory barrier' (like a 
synchronize block).

news <ne...@sea.gmane.org> wrote on 11/05/2005 10:48:12 PM:

> I've spent countless hours trying to get this to work. I simply want to 
be able
> to save some Java2D shapes to an SVG file, and then later read the file 
back in
> and reconstitute my Java2D shapes. I know my code for reading SVG files 
into
> Jaava2D shapes works, as I've used an external program to generate SVG 
files and
> my code successfully reads them in. I know my code for writing shapes to 
SVG
> files works, as I've examined the generated files with an SVG viewer and 
can see
> they are correct. The problem is that when I save to SVG with Batik, and 
then
> try to read the file back in with Batik, I get an endless loop. I do not 
get
> this with files generated by other SVG programs.



> 
> I would appreciate guidance on how to get this roundtripping to work. 
Thanks in
> advance. -Mike
> 
> Some ugly test code to illustrate what I'm doing in my application:
> 
> //////////////////////////////////////
> // The Test                         //
> //////////////////////////////////////
> import org.apache.batik.dom.*;
> import org.apache.batik.svggen.*;
> import org.w3c.dom.*;
> 
> import java.awt.*;
> import java.awt.geom.*;
> import java.io.*;
> 
> public class BatikRoundtripTest {
> 
>     public void execute() throws Exception {
> 
>         //
>         // Write Java2D Shape to SVG File
>         //
> 
>         DOMImplementation domImpl = 
GenericDOMImplementation.getDOMImplementation();
> 
>         Document document = domImpl.createDocument(null, "svg", null);
>         SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
>         svgGenerator.setSVGCanvasSize(new Dimension(200, 200));
> 
>         paint(svgGenerator);
> 
>         boolean useCSS = true;
>         Writer out = new FileWriter(new File("C:\\rectangle.svg"));
>         svgGenerator.stream(out, useCSS);
>         out.close();
> 
>         //
>         // Read same SVG File into Java2D Shape (endless loop when 
reading
>         // files generated by Batik)
>         //
> 
>         ShapeLoader shapeloader = new ShapeLoader("C:\\rectangle.svg", 
0);
>         shapeloader.run();
>         Shape s = shapeloader.getShape();
>         System.out.println("True or false, the shape null? " + (s == 
null));
>      }
> 
>     public void paint(Graphics2D g2d) {
>         Rectangle2D r = new Rectangle2D.Double(0.0, 0.0, 100.0, 100.0);
>         g2d.fill(r);
>     }
> 
>     public static void main(String[] args) throws Exception {
>         new BatikRoundtripTest().execute();
>     }
> 
> }
> 
> /////////////////////////////////////////////////////////////
> // A helper file for loading SVG files into JAVA 2D shapes //
> /////////////////////////////////////////////////////////////
> 
> import org.apache.batik.gvt.*;
> import org.apache.batik.swing.svg.*;
> 
> import java.awt.*;
> import java.io.*;
> import java.net.*;
> import java.util.*;
> import java.util.List;
> 
> public class ShapeLoader extends Thread {
> 
>     private JSVGComponent component = new JSVGComponent();
>     private List<Shape> shapes = new LinkedList<Shape>();
>     private String shapeFile;
>     private int shapeIndex;
>     private boolean shapesLoaded = false;
>     private Shape shape;
> 
>     public ShapeLoader(final String shapeFile, final int shapeIndex) {
> 
>         this.shapeFile = shapeFile;
>         this.shapeIndex = shapeIndex;
> 
>         component.addGVTTreeBuilderListener(
> 
>             new GVTTreeBuilderAdapter() {
> 
>                 public void gvtBuildCompleted(GVTTreeBuilderEvent event) 
{
> 
>                     super.gvtBuildCompleted(event);
> 
>                     GVTTreeWalker treeWalker = new
> GVTTreeWalker(event.getGVTRoot());
> 
>                     GraphicsNode graphicsNode = null;
> 
>                     while((graphicsNode = treeWalker.nextGraphicsNode()) 
!= null) {
>                         shapes.add(graphicsNode.getOutline());
>                     }
> 
>                     shapesLoaded = true;
>                 }
>             }
>         );
>     }
> 
>     public void run() {
>         loadShape();
>     }
> 
>     public Shape getShape() {
>         return shape;
>     }
> 
>     public synchronized void loadShape() {
> 
>        try {
>             String urlString = new
> File(shapeFile).getAbsoluteFile().toURL().toString();
>             System.out.println(urlString + " loading...");
> 
>             component.loadSVGDocument(urlString);
> 
>             while(shapesLoaded != true) {
> 
>                 // TODO: need timeout - file not found is endless loop
> 
>                 try {
>                     wait(100);
>                 } catch (InterruptedException e) {
>                     e.printStackTrace();  // TODO: better error handling
>                 }
>             }
> 
>            System.out.println(urlString + " loaded.");
>         }
>         catch (MalformedURLException e) {
>             e.printStackTrace();        // TODO: better error handling
>         }
> 
>         shape = shapes.get(shapeIndex);
>         shapes.clear();
>     }
> }
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org