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 Bob Carpenter <bo...@engineer.com> on 2004/02/20 21:02:41 UTC

JSVGCanvas Thread Timing Problem

I've started using Batik 1.5 with Java 1.4.

I need some help getting my head around how best to convert my app to use
SVG files.

I have a Swing client that currently uses BufferedImages that are generated
from DXF files. These images are typically floor plans. There are other
bufImgs that are icons that get dropped on a floor plan. All images are
placed in a JLayeredPane - on various layers - which is then added to a
JPanel. I want to quit using DXF files and start using SVG files.

To get started down the conversion path I thought I could simply create a
JSVGCanvas of the floorplan.svg and call svgCanvas.getOffScreen() to grab
the bufImg, and place that in the layeredPane. But I'm having a thread
timing problem. The svgCanvas doesn't start rendering the bufImg until after
it has been added to the layeredPane. I've tried using a sleep thread that
wakes up to see if the tree build is done, but the svgCanvas thread doesn't
start until it's too late to grab the bufImg.

I'd appreciate any help to solve this timing problem, or a suggestion on a
better approach to do the conversion.

For those interested, I've included my SVGUtil class which is meant to
handle creation of the svgCanvas and expose the bufImg.

Thanks,

--BobC

------------------

package com.bobc.common;

import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter;
import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
import org.apache.batik.swing.svg.GVTTreeBuilderAdapter;
import org.apache.batik.swing.svg.GVTTreeBuilderEvent;
import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.log4j.Category;
import org.w3c.dom.svg.SVGDocument;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.io.IOException;

/**
 * This class provides utilities for working with Scalable Vector Graphic
files.
 *
 * User: Bob Carpenter
 * Date: Feb 17, 2004
 */
public class SVGUtils implements Runnable {
    private Category logger = Category.getInstance(this.getClass());

    private JSVGCanvas svgCanvas = null;
    private BufferedImage bufi = null;
    private Timer timer = null;
    private boolean isBuildDone = false;
    private boolean isThreadDone = false;
    private Thread bldThread = null;
    private Frame tmpFrame = new Frame();

    public SVGUtils() {
        logger.info("ctor_entry");

        svgSetup();
//
svgCanvas.setURI("file:/C:/jakarta/batik/batik-1.5/samples/3D.svg");

svgCanvas.loadSVGDocument("file:/C:/jakarta/batik/batik-1.5/samples/3D.svg")
; //demo file
        svgCanvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);

        //add to tmp frame - trying to force svg build and render to start
        tmpFrame.add(svgCanvas);
        tmpFrame.repaint();

        logger.info("ctor_exit");
    }

    public BufferedImage getBufi() {
        logger.info("getBufi_entry");

        // This is threaded so that the svg build and render takes place
before it's needed by gui
        synchronized (this) {
            try {
                bldThread = new Thread(this);
                bldThread.setPriority(Thread.MIN_PRIORITY);
                bldThread.start();
                logger.info("getBufi - thread started");

                logger.info("getBufi - thread count = "
+Thread.activeCount());

                //run for awhile - exit if time expires, thread ends or
exception
                Calendar stopTime = new GregorianCalendar();
                stopTime.add(Calendar.SECOND, 30);
                logger.info("getBufi - thread times-out at: "
+stopTime.getTime());

                Calendar elapsedTime = new GregorianCalendar();

                int iter = 0;
                while(!isThreadDone) {

                    try {
                        if(elapsedTime.after(stopTime)) {
                            isThreadDone = true;
                            logger.info("getBufi - thread timed-out");
                        }

                        //sleep for a period then see if thread timed-out
                        iter++;
                        int slpPeriod = 1000;
                        Thread.sleep(slpPeriod);
                        elapsedTime.add(Calendar.SECOND, slpPeriod/1000);
                        if((iter % slpPeriod) == 0) logger.info("getBufi -
thread heartbeat -  iter = " +iter);
                    }
                    catch(Exception ex) {
                        logger.error("getBufi - ERROR: " + ex);
                    }
                }

            }
            catch (Exception ex) {
                logger.error("getBufi - ERROR: " + ex);
            }

        };

        logger.info("getBufi_exit");
        return bufi;
    }


    public void run() {
		  logger.info("run_entry");

		  try {
			  //process replies from Inktomi
			  while(!isBuildDone) {
				  //wait until build done
                logger.info("******* SLEEP");
				  bldThread.sleep(10000L);
                logger.info("******* AWAKE");
			  }
		  }
		  catch(Exception ex) {
        logger.error("run - ERROR: " +ex);
		  }

		  isThreadDone = true;
		  logger.info("run_exit");
    }


    public void svgSetup() {
        logger.info("svgSetup_entry");

        svgCanvas = new JSVGCanvas(null, true, false);

        // Set the JSVGCanvas listeners.
        svgCanvas.addSVGDocumentLoaderListener(new
SVGDocumentLoaderAdapter() {
            public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
                logger.info("Document Loading...");
            }
            public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
                logger.info("Document Loaded.");
            }
        });

        svgCanvas.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
            public void gvtBuildStarted(GVTTreeBuilderEvent e) {
                logger.info("Build Started...");
            }
            public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
                logger.info("Build Done.");
                tmpFrame.pack();  //causes render to start
                isBuildDone = true;
            }
        });

        svgCanvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
            public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
                logger.info("Rendering Started...");
            }
            public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
                logger.info("Rendering Done");
                if(svgCanvas != null) bufi = svgCanvas.getOffScreen();
                if(bufi != null) logger.info("gvtRenderingCompleted - BUFI
NOT NULL");
                else logger.info("gvtRenderingCompleted - BUFI IS NULL");
            }
        });
        logger.info("svgSetup_exit");

    }


    public JSVGCanvas getSvgCanvas() {
        return svgCanvas;
    }
}


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


RE: JSVGCanvas Thread Timing Problem

Posted by Bob Carpenter <bo...@engineer.com>.
>  Well just a guess but do you ever add the jsvgcanvas to the
>  rendering tree?  If not it's size might be zero in which case it
>  may decide not to render.

  This is the first I've heard of the "rendering tree". Most of my Batik
knowledge
  comes from the JSVGCanvas Tutorial. I've not been able to find any User
Guide
  or other docs that explain how developers are to use Batik.

  How do I add the jsvgcanvas to the rendering tree?

> I think you would be better off using the slideshow code for now as
> that is doing essentially what you want here.  Using the canvas for
> this is really 'abusing the system'.

  I will jump into it now and see what I can learn...

Thanks,

--BobC


-----Original Message-----
From: Thomas DeWeese [mailto:Thomas.DeWeese@Kodak.com]
Sent: Friday, February 20, 2004 1:11 PM
To: Batik Users
Subject: Re: JSVGCanvas Thread Timing Problem


Bob Carpenter wrote:

>> If you just want to convert SVG to buffered images you could look
>> at the 'slideshow' application as this is what it does.
>
>
> 	I'll have a look and see if I can make some progress.
>
>
>> I'm not sure I follow you here (what you mean by 'too late'), but
>> the JSVGCanvas has events that you can listen to, in particular the
>> 'GVTTreeRenderer' events include the 'BufferedImage' in the completed
>> event.  This is how I would get the results of the rendering.
>
>
> 	Yes, I know about the events - I am using them, see my SVGUtils class.

      A quick look it seemed like you were using a 'busy wait'  but I
didn't go through the code that closely.

> 	But the creation of the svgCanvas object seems to place the Load,
> 	Build, Render processes on a low priority thread that doesn't start until
> 	after all other threads are finished. So, when I create the svgCanvas
>       object I cannot figure out how to force it to start the Load, Build,
>       Render processes

     Well just a guess but do you ever add the jsvgcanvas to the
rendering tree?  If not it's size might be zero in which case it
may decide not to render.

> 	so that I can wait until the bufImg is non-NULL and can be added to the
> layeredPane.
> 	Down stream processes expect to find a non-NULL bufImg so that they can
do
> things
> 	like pane sizing, etc.

    I think you would be better off using the slideshow code for now as
that is doing essentially what you want here.  Using the canvas for
this is really 'abusing the system'.

>> Is there a reason you can't just add the JSVGCanvas to the JLayered
>> Pane and bypass all this buffered image nonsense?
>
>
> 	Yes, right now my app is BufferedImage centric and it will take many
hours
> 	to convert it to being centered around the JSVGCanvas. A worthwhile goal,
> 	but I need to walk before I crawl.
>
> Thanks for your patience with this newbie.
>
> --BobC
>
>
> -----Original Message-----
> From: Thomas DeWeese [mailto:Thomas.DeWeese@Kodak.com]
> Sent: Friday, February 20, 2004 12:16 PM
> To: Batik Users
> Subject: Re: JSVGCanvas Thread Timing Problem
>
>
> Bob Carpenter wrote:
>
>
>>I need some help getting my head around how best to convert my app to use
>>SVG files.
>>
>>I have a Swing client that currently uses BufferedImages that are
>
> generated
>
>>from DXF files. These images are typically floor plans. There are other
>>bufImgs that are icons that get dropped on a floor plan. All images are
>>placed in a JLayeredPane - on various layers - which is then added to a
>>JPanel. I want to quit using DXF files and start using SVG files.
>>
>>To get started down the conversion path I thought I could simply create a
>>JSVGCanvas of the floorplan.svg and call svgCanvas.getOffScreen() to grab
>>the bufImg, and place that in the layeredPane.
>
>
>     If you just want to convert SVG to buffered images you could look
> at the 'slideshow' application as this is what it does.
>
>
>>But I'm having a thread
>>timing problem. The svgCanvas doesn't start rendering the bufImg until
>
> after
>
>>it has been added to the layeredPane. I've tried using a sleep thread that
>>wakes up to see if the tree build is done, but the svgCanvas thread
>
> doesn't
>
>>start until it's too late to grab the bufImg.
>
>
>     I'm not sure I follow you here (what you mean by 'too late'), but
> the JSVGCanvas has events that you can listen to, in particular the
> 'GVTTreeRenderer' events include the 'BufferedImage' in the completed
> event.  This is how I would get the results of the rendering.
>
>     Is there a reason you can't just add the JSVGCanvas to the JLayered
> Pane and bypass all this buffered image nonsense?
>
>
>>I'd appreciate any help to solve this timing problem, or a suggestion on a
>>better approach to do the conversion.
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
> For additional commands, e-mail: batik-users-help@xml.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
> For additional commands, e-mail: batik-users-help@xml.apache.org
>



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


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


Re: JSVGCanvas Thread Timing Problem

Posted by Thomas DeWeese <Th...@Kodak.com>.
Bob Carpenter wrote:

>> If you just want to convert SVG to buffered images you could look
>> at the 'slideshow' application as this is what it does.
> 
> 
> 	I'll have a look and see if I can make some progress.
> 
> 
>> I'm not sure I follow you here (what you mean by 'too late'), but
>> the JSVGCanvas has events that you can listen to, in particular the
>> 'GVTTreeRenderer' events include the 'BufferedImage' in the completed
>> event.  This is how I would get the results of the rendering.
> 
> 
> 	Yes, I know about the events - I am using them, see my SVGUtils class.

      A quick look it seemed like you were using a 'busy wait'  but I
didn't go through the code that closely.

> 	But the creation of the svgCanvas object seems to place the Load,
> 	Build, Render processes on a low priority thread that doesn't start until
> 	after all other threads are finished. So, when I create the svgCanvas
>       object I cannot figure out how to force it to start the Load, Build, 
>       Render processes

     Well just a guess but do you ever add the jsvgcanvas to the
rendering tree?  If not it's size might be zero in which case it
may decide not to render.

> 	so that I can wait until the bufImg is non-NULL and can be added to the
> layeredPane.
> 	Down stream processes expect to find a non-NULL bufImg so that they can do
> things
> 	like pane sizing, etc.

    I think you would be better off using the slideshow code for now as
that is doing essentially what you want here.  Using the canvas for
this is really 'abusing the system'.

>> Is there a reason you can't just add the JSVGCanvas to the JLayered
>> Pane and bypass all this buffered image nonsense?
> 
> 
> 	Yes, right now my app is BufferedImage centric and it will take many hours
> 	to convert it to being centered around the JSVGCanvas. A worthwhile goal,
> 	but I need to walk before I crawl.
> 
> Thanks for your patience with this newbie.
> 
> --BobC
> 
> 
> -----Original Message-----
> From: Thomas DeWeese [mailto:Thomas.DeWeese@Kodak.com]
> Sent: Friday, February 20, 2004 12:16 PM
> To: Batik Users
> Subject: Re: JSVGCanvas Thread Timing Problem
> 
> 
> Bob Carpenter wrote:
> 
> 
>>I need some help getting my head around how best to convert my app to use
>>SVG files.
>>
>>I have a Swing client that currently uses BufferedImages that are
> 
> generated
> 
>>from DXF files. These images are typically floor plans. There are other
>>bufImgs that are icons that get dropped on a floor plan. All images are
>>placed in a JLayeredPane - on various layers - which is then added to a
>>JPanel. I want to quit using DXF files and start using SVG files.
>>
>>To get started down the conversion path I thought I could simply create a
>>JSVGCanvas of the floorplan.svg and call svgCanvas.getOffScreen() to grab
>>the bufImg, and place that in the layeredPane.
> 
> 
>     If you just want to convert SVG to buffered images you could look
> at the 'slideshow' application as this is what it does.
> 
> 
>>But I'm having a thread
>>timing problem. The svgCanvas doesn't start rendering the bufImg until
> 
> after
> 
>>it has been added to the layeredPane. I've tried using a sleep thread that
>>wakes up to see if the tree build is done, but the svgCanvas thread
> 
> doesn't
> 
>>start until it's too late to grab the bufImg.
> 
> 
>     I'm not sure I follow you here (what you mean by 'too late'), but
> the JSVGCanvas has events that you can listen to, in particular the
> 'GVTTreeRenderer' events include the 'BufferedImage' in the completed
> event.  This is how I would get the results of the rendering.
> 
>     Is there a reason you can't just add the JSVGCanvas to the JLayered
> Pane and bypass all this buffered image nonsense?
> 
> 
>>I'd appreciate any help to solve this timing problem, or a suggestion on a
>>better approach to do the conversion.
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
> For additional commands, e-mail: batik-users-help@xml.apache.org
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
> For additional commands, e-mail: batik-users-help@xml.apache.org
> 



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


RE: JSVGCanvas Thread Timing Problem

Posted by Bob Carpenter <bo...@engineer.com>.
>  If you just want to convert SVG to buffered images you could look
>  at the 'slideshow' application as this is what it does.

	I'll have a look and see if I can make some progress.

>  I'm not sure I follow you here (what you mean by 'too late'), but
>  the JSVGCanvas has events that you can listen to, in particular the
>  'GVTTreeRenderer' events include the 'BufferedImage' in the completed
>  event.  This is how I would get the results of the rendering.

	Yes, I know about the events - I am using them, see my SVGUtils class.
	But the creation of the svgCanvas object seems to place the Load,
	Build, Render processes on a low priority thread that doesn't start until
	after all other threads are finished. So, when I create the svgCanvas
object
	I cannot figure out how to force it to start the Load, Build, Render
processes
	so that I can wait until the bufImg is non-NULL and can be added to the
layeredPane.
	Down stream processes expect to find a non-NULL bufImg so that they can do
things
	like pane sizing, etc.


>  Is there a reason you can't just add the JSVGCanvas to the JLayered
>  Pane and bypass all this buffered image nonsense?

	Yes, right now my app is BufferedImage centric and it will take many hours
	to convert it to being centered around the JSVGCanvas. A worthwhile goal,
	but I need to walk before I crawl.

Thanks for your patience with this newbie.

--BobC


-----Original Message-----
From: Thomas DeWeese [mailto:Thomas.DeWeese@Kodak.com]
Sent: Friday, February 20, 2004 12:16 PM
To: Batik Users
Subject: Re: JSVGCanvas Thread Timing Problem


Bob Carpenter wrote:

> I need some help getting my head around how best to convert my app to use
> SVG files.
>
> I have a Swing client that currently uses BufferedImages that are
generated
> from DXF files. These images are typically floor plans. There are other
> bufImgs that are icons that get dropped on a floor plan. All images are
> placed in a JLayeredPane - on various layers - which is then added to a
> JPanel. I want to quit using DXF files and start using SVG files.
>
> To get started down the conversion path I thought I could simply create a
> JSVGCanvas of the floorplan.svg and call svgCanvas.getOffScreen() to grab
> the bufImg, and place that in the layeredPane.

    If you just want to convert SVG to buffered images you could look
at the 'slideshow' application as this is what it does.

> But I'm having a thread
> timing problem. The svgCanvas doesn't start rendering the bufImg until
after
> it has been added to the layeredPane. I've tried using a sleep thread that
> wakes up to see if the tree build is done, but the svgCanvas thread
doesn't
> start until it's too late to grab the bufImg.

    I'm not sure I follow you here (what you mean by 'too late'), but
the JSVGCanvas has events that you can listen to, in particular the
'GVTTreeRenderer' events include the 'BufferedImage' in the completed
event.  This is how I would get the results of the rendering.

    Is there a reason you can't just add the JSVGCanvas to the JLayered
Pane and bypass all this buffered image nonsense?

>
> I'd appreciate any help to solve this timing problem, or a suggestion on a
> better approach to do the conversion.



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


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


Re: JSVGCanvas Thread Timing Problem

Posted by Thomas DeWeese <Th...@Kodak.com>.
Bob Carpenter wrote:

> I need some help getting my head around how best to convert my app to use
> SVG files.
> 
> I have a Swing client that currently uses BufferedImages that are generated
> from DXF files. These images are typically floor plans. There are other
> bufImgs that are icons that get dropped on a floor plan. All images are
> placed in a JLayeredPane - on various layers - which is then added to a
> JPanel. I want to quit using DXF files and start using SVG files.
> 
> To get started down the conversion path I thought I could simply create a
> JSVGCanvas of the floorplan.svg and call svgCanvas.getOffScreen() to grab
> the bufImg, and place that in the layeredPane. 

    If you just want to convert SVG to buffered images you could look
at the 'slideshow' application as this is what it does.

> But I'm having a thread
> timing problem. The svgCanvas doesn't start rendering the bufImg until after
> it has been added to the layeredPane. I've tried using a sleep thread that
> wakes up to see if the tree build is done, but the svgCanvas thread doesn't
> start until it's too late to grab the bufImg.

    I'm not sure I follow you here (what you mean by 'too late'), but
the JSVGCanvas has events that you can listen to, in particular the
'GVTTreeRenderer' events include the 'BufferedImage' in the completed
event.  This is how I would get the results of the rendering.

    Is there a reason you can't just add the JSVGCanvas to the JLayered
Pane and bypass all this buffered image nonsense?

> 
> I'd appreciate any help to solve this timing problem, or a suggestion on a
> better approach to do the conversion.



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