Re: rendering directly to java.awt.Graphics2D

Mike Jarmy <[email protected]>
Newsgroups gmane.text.xml.batik.user
Message-ID <CADjkO6g3qnTRc2uU=vPDzTXPaiMqhuOgKZN8wG6ge8+vxq6S6Q@mail.gmail.com>
On Sun, Aug 7, 2011 at 6:43 PM, jonathan wood
<[email protected]> wrote:
> Hi Mike,
>   I've seen variations of this type thing before...  in my case a top level
> svg that contains an <image> who's xlink:href references another document
> (svg in my case).  The referenced svg document had an id'd gradient that was
> in the <defs>...when the gradient was referenced by a shape's fill, the
> transcode would fail. Seems once the DOM (GVT) is booted the calls out to
> the xlnk:href are resolved. The uri for the embedded document seemed to be
> null (null#id on reference)You can try to setDocumentURI("something") on the
> parent...I think I tried that with no success, but needed to work-around
> (base64 data uri worked fine) and move on. I can probably reproduce this
> behavior in a test case if you think it will help resolve your issue.  I
> have not had time to debug it further, but it is on the (long) list.
> On Thu, Aug 4, 2011 at 4:36 PM, Mike Jarmy <[email protected]> wrote:
>>
>> On Wed, Aug 3, 2011 at 3:39 PM, Mike Jarmy <[email protected]> wrote:
>> > On Wed, Aug 3, 2011 at 1:03 PM, Mike Jarmy <[email protected]> wrote:
>> >> I'm working with a custom widget toolkit that is built directly on top
>> >> of java.awt -- in other words I'm not using Swing, or SWT, or anything
>> >> other than a framework built on plain old AWT.
>> >>
>> >> I'd like to be able to render (and animate) SVG drawings directly onto
>> >> a java.awt.Graphics2D instance.  However, I'm having a bit of trouble
>> >> figuring out how exactly to do that with batik.  I *think* that I need
>> >> to decode my SVG drawing into a GVT tree, and then render the tree.
>> >> However I can't figure out which part of batik I need in order to do
>> >> the rendering.  Transcoder and SVGGraphics2D do not seem to be quite
>> >> what I want. Actually, I haven't yet figured out the
>> >> decoding-to-GVT-step either, but I'm assuming that's pretty
>> >> straightforward.
>> >>
>> >> So can anyone give me a pointer on how to do this?  Perhaps just point
>> >> me to an existing example?  My first goal is to just get static images
>> >> rendering.
>> >>
>> >> After that, I'll need to get animation working.  I'm assuming that
>> >> supporting animation will entail updating the drawing's current time
>> >> every so oftern on a separate thread, via the AnimationEngine, and
>> >> then re-rendering the updated GVT?
>> >>
>> >> I *could* do all this by rendering into a static java.awt.Image, and
>> >> then bliting the Image (i.e. roll my own double-buffering), but I'd
>> >> prefer to figure out how to just draw directly onto a Graphics2D
>> >> instance first.  That's because the framework I'm using already has
>> >> some double-buffering, so I most likely wont need to do that with the
>> >> SVG rendering.
>> >>
>> >> Thanks,
>> >> Mike Jarmy
>> >>
>> >> P.S. FYI, I'll probably never need to support handling interactive user
>> >> input.
>> >>
>> >
>> > OK, I have discovered the GraphicsNode.paint(Graphics2D g2d)  method,
>> > which may be all I need to call once I actually get a valid GVT build.
>> >  However, I'm having trouble building a GVT from a
>> > java.io.InputStream.  Here is the code I'm using:
>> >
>> >            String parser =
>> > XMLResourceDescriptor.getXMLParserClassName();
>> >            SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
>> > //            String uri = "http://www.example.org/document.svg";
>> >            Document document = f.createDocument(null, inputStream);
>> >
>> >            UserAgent userAgent = new UserAgentAdapter();
>> >            DocumentLoader loader = new DocumentLoader(userAgent);
>> >            BridgeContext bctx = new BridgeContext(userAgent, loader);
>> >            bctx.setDynamicState( BridgeContext.DYNAMIC );
>> >            GVTBuilder builder = new GVTBuilder();
>> >            this.gvtRoot = builder.build(bctx, document);
>> >
>> > This code fails at the call to GVTBuilder.build(), with the following
>> > error:
>> >
>> > Invalid CSS document.
>> > Unable to make sense of URL for connection
>> >        at
>> > org.apache.batik.css.engine.CSSEngine.parseStyleSheet(CSSEngine.java:1149)
>> >        at
>> > org.apache.batik.dom.svg.SVGDOMImplementation.createCSSEngine(SVGDOMImplementation.java:117)
>> >        at
>> > org.apache.batik.dom.ExtensibleDOMImplementation.createCSSEngine(ExtensibleDOMImplementation.java:212)
>> >        at
>> > org.apache.batik.bridge.BridgeContext.initializeDocument(BridgeContext.java:378)
>> >        at org.apache.batik.bridge.GVTBuilder.build(GVTBuilder.java:55)
>> >        at
>> > com.tridium.svg.ui.BSvgDrawing.loadDrawing(BSvgDrawing.java:305)
>> >
>> > Could that be because I'm passing a null value in for the URI when I
>> > create the document from the InputStream?  I have noticed that I get
>> > the same error no matter what I pass in for the URI.  Is there perhaps
>> > a better way to construct a Document from an InputStream?
>> >
>> > Thanks,
>> > Mike Jarmy
>> >
>>
>> I have this working now in a simple "hello, world" style, java app,
>> using the following approach:
>>
>>    public static void main(String[] args) throws Exception
>>    {
>>        // make the file, along with its input stream and URI
>>        File file = new File("D:\\aaa\\svg\\samples\\batik70.svg");
>>        FileInputStream inputStream = new FileInputStream(file);
>>        String uri = file.toURL().toString();
>>
>> System.out.println("File " + file.getAbsolutePath() + " exists: " +
>> file.exists());
>>
>>        // create the document
>>        String parser = XMLResourceDescriptor.getXMLParserClassName();
>>        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
>>        Document document = f.createDocument(uri, inputStream);
>>
>>        // create the GVT
>>        UserAgent userAgent = new UserAgentAdapter();
>>        DocumentLoader loader = new DocumentLoader(userAgent);
>>        BridgeContext bctx = new BridgeContext(userAgent, loader);
>>        bctx.setDynamicState( BridgeContext.DYNAMIC );
>>        GVTBuilder builder = new GVTBuilder();
>>        GraphicsNode gvtRoot = builder.build(bctx, document);
>>
>>        AwtApp app = new AwtApp(gvtRoot);
>>        app.setVisible(true);
>>    }
>>
>> AwtApp just calls gvtRoot.paint(Graphics2D) from within a custom
>> java.awt.Canvas.  This works perfectly.
>>
>> However, when I run the same code within my company's software
>> framework, I'm still getting this:
>>
>> Invalid CSS document.
>> Unable to make sense of URL for connection
>>   at
>> org.apache.batik.css.engine.CSSEngine.parseStyleSheet(CSSEngine.java:1149)
>>   at
>> org.apache.batik.dom.svg.SVGDOMImplementation.createCSSEngine(SVGDOMImplementation.java:117)
>>   at
>> org.apache.batik.dom.ExtensibleDOMImplementation.createCSSEngine(ExtensibleDOMImplementation.java:212)
>>   at
>> org.apache.batik.bridge.BridgeContext.initializeDocument(BridgeContext.java:378)
>>   at org.apache.batik.bridge.GVTBuilder.build(GVTBuilder.java:55)
>>   at com.tridium.svg.ui.BSvgDrawing.main(BSvgDrawing.java:535)
>>   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>   at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>>   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
>>   at java.lang.reflect.Method.invoke(Unknown Source)
>>   at com.tridium.sys.Nre.runClass(Nre.java:209)
>>   at com.tridium.sys.Nre.main(Nre.java:152)
>>
>> Obviously this isn't batik's fault, since my test app works just fine
>> in a 'normal' vanilla environment.
>>
>> Clearly the framework is doing something different, but I'm somewhat
>> at a loss to say what it could be.  One possibility is that the
>> problem could be caused by classloading.  Our framework using custom
>> ClassLoaders, one per jar file.  I have all of the batik jar files
>> actually stuffed into one big jar file, as per our general approach.
>> Could that have something to do with this problem?
>>
>> Any other ideas?  If not then I'm on my own, since I have batik doing
>> what I want it to do in a simple app.
>>
>> Thanks,
>> Mike Jarmy
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [email protected]
>> For additional commands, e-mail: [email protected]
>>

I was actually able to get this working.  It was only happening for
certain files, and I do believe that it had something to do with URIs
embedded in the svg file.  By always setting the URI to an absolute
path I was able to resolve the problem.

This problem may however come back to bite me again.  I have not yet
experimented with reading SVG files from a jar file, as I will
inevitably need to do.  In that case I may have to disallow having SVG
files refer to each other, since its likely there is no real way to
specify a URI to another file inside a jar file.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.