Hi Thomas!
Your added suggestions did the trick. Also, I agree with your
conclusion that the approach suggested in the tread (>
http://mail-archives.apache.org/mod_mbox/xmlgraphics-batik-users/200112.
) is inefficient compared to the code in this thread.
I have taken all of the suggestions of this thread and what we have
learned an applied it to a small, immutable class. For the benefit of
others here is a way to efficiently load a SVG from a URL or document
and retrieve it as a java.awt.Image.
Hopefully some form of this code can be integrated into Batik.
- Jonathan
Usages: java.awt.Image image = new SvgImage(url).getImage(50, 50);
java.awt.Image image = new SvgImage(doc).getImage(50, 50);
Code:
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.bridge.ViewBox;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
/**
* Immutable class to get the Image representation of a svg resource.
*/
public final class SvgImage
{
/** Root node of svg document */
private final GraphicsNode rootSvgNode;
/** Loaded SVG document */
private final SVGDocument svgDocument;
/**
* Load the svg resource from a URL into a document.
* @param url location of svg resource.
* @throws java.io.IOException when svg resource cannot be read.
*/
public SvgImage(URL url)
throws IOException
{
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new
SAXSVGDocumentFactory(parser);
svgDocument =
(SVGDocument)factory.createDocument(url.toString());
rootSvgNode = getRootNode(svgDocument);
}
/**
* Load the svg from a document.
*
* @param document svg resource
*/
public SvgImage(SVGDocument document)
{
svgDocument = document;
rootSvgNode = getRootNode(svgDocument);
}
/**
* Get svg root from the given document.
*
* @param document svg resource
*/
private static GraphicsNode getRootNode(SVGDocument document)
{
// Build the tree and get the document dimensions
UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
BridgeContext bridgeContext = new
BridgeContext(userAgentAdapter);
GVTBuilder builder = new GVTBuilder();
return builder.build(bridgeContext, document);
}
/**
* Get the svg root node of the document.
*
* @return svg root node.
*/
public GraphicsNode getRootSvgNode()
{
return rootSvgNode;
}
/**
* Get the svg document.
* @return the svg document.
*/
public SVGDocument getSvgDocument()
{
return svgDocument;
}
/**
* Renders and returns the svg based image.
*
* @param width desired width
* @param height desired height
* @return image of the rendered svg.
*/
public Image getImage(int width, int height)
{
// Paint svg into image buffer
BufferedImage bufferedImage = new BufferedImage(width,
height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
// For a smooth graphic with no jagged edges or rastorized look.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// Scale image to desired size
Element elt = svgDocument.getRootElement();
AffineTransform usr2dev = ViewBox.getViewTransform(null, elt,
width, height);
g2d.transform(usr2dev);
rootSvgNode.paint(g2d);
// Cleanup and return image
g2d.dispose();
return bufferedImage;
}
}
-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
Sent: Saturday, January 21, 2006 7:13 AM
To: [email protected]
Subject: RE: How to load an SVG resource into a java.awt.Image?
Hi Jonathan,
"Johnson, Jonathan" <[EMAIL PROTECTED]> wrote on 01/20/2006 04:54:13 PM:
> I still have two problems. The svg image does not scale itself into
the
> dimension I specified and the image rasterizes with jagged edges.
What
> controls the scaling of the image to the image size and the edge
> smoothness?
An affine transform controls the scaling:
import java.awt.geom.AffineTransform;
import org.apache.batik.bridge.ViewBox;
Element elt = ((SVGDocument)svgDoc).getRootElement();
AffineTransform usr2dev = ViewBox.getViewTransform
(null, elt, dimension.width, dimension.height));
g2d.transform(usr2dev);
Rendering Hints control how a document is rendered 'by default':
import java.awt.RenderingHints;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
> For a smoother out-of-the-box experience for new batik users this
> would be a nice, basic utility method (with perhaps complementary
> methods to accept a File, SVGDocument or a GraphicsNode instead of a
URL).
This is a nice start, thanks for posting it. I suspect it will help
others.
> /**
> * Loads a svg resource from a URL, renders and returns the image.
> * @param url location of svg resource.
> * @param dimension desired size
> * @return image of the rendered svg
> * @throws IOException when svg resource cannot be read.
> */
> public static Image getImageFromSvg(URL url, Dimension dimension)
> throws IOException
> {
> // Load SVG resource into a document
> String parser = XMLResourceDescriptor.getXMLParserClassName();
> SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
> SVGDocument document = (SVGDocument)
> f.createDocument(url.toString());
>
> // Build the tree and get the document dimensions
> UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
> BridgeContext bridgeContext = new
> BridgeContext(userAgentAdapter);
> GVTBuilder builder = new GVTBuilder();
> GraphicsNode graphicsNode = builder.build(bridgeContext,
> document);
>
> // Paint svg into image buffer
> BufferedImage bufferedImage = new
BufferedImage(dimension.width,
> dimension.height, BufferedImage.TYPE_INT_ARGB);
> Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
> graphicsNode.paint(g2d);
>
> // Cleanup and return image
> g2d.dispose();
> return bufferedImage;
> }
>
> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Friday, January 20, 2006 6:03 AM
> To: [email protected]
> Cc: [email protected]
> Subject: Re: How to load an SVG resource into a java.awt.Image?
>
> Hi Johnson,
>
> "Johnson, Jonathan" <[EMAIL PROTECTED]> wrote on 01/18/2006 04:55:48
PM:
>
> > Swing has a simple utility method to load a gif, jpeg or png file
> >
> > Image Toolkit.getDefaultToolkit().getImage(url)
> >
> > and place it in a java.awt.Image object. At this point you can
create
> a
> swing
> > JButton and hand it the Image.
> >
> > Using Batik I'm looking for a way to load a svg into a
java.awt.Image,
>
> Icon,
> > BufferedImage or into some object that I can convert to an
> java.awt.Image.
> > While preserving the transparent background as well.
>
> > Using a JSVGComponent is not the right solution since a JButton
> accepts
> an
> > Icon and not a component for attaching a common button image. I
also
> want to
> > avoid transcoding the svg to a png file.
>
> BTW there isn't much difference between this route and using a PNG
> (for mid/high resolution the SVG will be smaller and in many
> cases more flexible).
>
> > Is there a Batik API call to achieve this?
>
> If you mean a single 'high level' java call to do this, No.
> The code you have below is roughly the simplest version of
> the code.
>
> > All I could find is this relatively complex solution...
>
> So I've often considered adding such a call but given
> than at least on the surface 90% of users of the transcoders
> API's want to tweak this or that parameter of the transcoding
> processes (at least width/height, often what part of canvas,
> contents of document, run onload handlers etc). It's always
> seemed like many users would end up needing something more.
> Even below you seem to have some form of scale you are
> manipulating (scaleX/Y), so such a simple call would not
> have helped you much...
>
> SVG is not like a PNG, there is no real inherent pixel size.
>
> BTW if you want to keep the transparent background then
> I would suggest using TYPE_INT_ARGB instead of just RGB.
>
> > String parser = XMLResourceDescriptor.getXMLParserClassName();
> > SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
> >
> > File file = new
File(MyClass.class.getResource("test.svg").getFile());
> > document = (SVGDocument) f.createDocument(file.toURL().toString());
> >
> > // Build the tree and get the document dimensions
> > UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
> > BridgeContext bridgeContext = new BridgeContext(userAgentAdapter);
> > GVTBuilder builder = new GVTBuilder();
> > GraphicsNode graphicsNode = builder.build(bridgeContext, document);
> >
> > BufferedImage bufferedImage = new BufferedImage
> > ((int)(bounds.getWidth() * scaleX),
> > (int)(bounds.getHeight() * scaleY),
> > BufferedImage.TYPE_INT_RGB);
> > Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
> > graphicsNode.paint(g2d);
> > g2d.dispose();
> >
> > return bufferedImage;
> >
> > LEGAL NOTICE:
> > Unless expressly stated otherwise, this message is confidential and
> may
> be
> > privileged. It is intended for the addressee(s) only. Access to this
> e-mail by
> > anyone else is unauthorized. If you are not an addressee, any
> disclosure
> or
> > copying of the contents or any action taken (or not taken) in
reliance
>
> on it
> > is unauthorized and may be unlawful. If you are not an addressee,
> please
>
> > inform the sender immediately.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail:
[EMAIL PROTECTED]
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]