package net.xoetrope.optional.svg;
import com.tinyline.svg.ImageLoader;
import com.tinyline.svg.SVGAttr;
import com.tinyline.svg.SVGDocument;
import com.tinyline.svg.SVGImageElem;
import com.tinyline.svg.SVGParser;
import com.tinyline.svg.SVGRaster;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import javax.swing.Icon;
import javax.swing.JComponent;
import com.tinyline.tiny2d.TinyBitmap;
import com.tinyline.tiny2d.TinyPixbuf;
import com.tinyline.tiny2d.TinyString;
import com.tinyline.tiny2d.TinyVector;
import java.awt.MediaTracker;
import java.util.Hashtable;
import net.xoetrope.optional.svg.tinyline.PPSVGBitmap;
import net.xoetrope.optional.svg.tinyline.SVGEventQueue;
/**
* Render the SVG image as an icon
* <p>Copyright (c) Xoetrope 2001-2006, see license.txt for more details</p>
* $Revision: 1.6 $
*/
public class XSvgIcon implements Icon, ImageLoader, ImageObserver, Runnable
{
private boolean imageComplete = false;
// Data Structure
/** The canvas offscreen image */
Image bimg;
/** The SVG renderer */
public SVGRaster raster;
/** The SVGImageProducer implementation */
XSVGImageProducer imageProducer;
/** The events queue */
public SVGEventQueue eventQueue;
/** The events listeners */
TinyVector listeners;
/** The image cash */
Hashtable imageCash;
MediaTracker tracker;
/**
* the icon width
*/
int width;
/**
* the icon height
*/
int height;
/** The SVG player thread */
Thread thread;
/** The base URL */
URL baseURL;
/** True if the loading is finished */
boolean loaded;
/** The current URL to go */
String currentURL = "";
/**
* the owner of this icon
*/
JComponent owner;
/**
* Constructs a new SVGCanvas instance.
*/
public XSvgIcon()
{
this( null, 100, 100 );
}
/**
* Constructs a new SVGCanvas instance.
* @param uri the location of the svg file
* @param w The width of this canvas.
* @param h The height of this canvas.
*/
public XSvgIcon( String uri, int w, int h )
{
TinyPixbuf buffer = new TinyPixbuf(w, h);
raster = new SVGRaster(buffer);
imageProducer = new XSVGImageProducer(raster);
raster.setSVGImageProducer(imageProducer);
// Sets the SVG raster size and the color model
imageProducer.setColorModel(ColorModel.getRGBdefault());
// Sets the ImageLoader implementation needed for
// loading bitmaps
SVGImageElem.setImageLoader(this);
// Uncomment the following line for full antialiasing
raster.setAntialiased(true);
// Makes the events queues
eventQueue = new SVGEventQueue();
listeners = new TinyVector(4);
// Makes the image cash
imageCash = new Hashtable();
}
/**
* Returns a TinyBitmap for the given image URL or path.
* @param uri The image URL or path.
* @return a TinyBitmap object which gets its pixel data from
* the specified URL or path.
*/
public TinyBitmap createTinyBitmap(TinyString uri)
{
String imgRef = new String(uri.data);
PPSVGBitmap bitmap = null;
try
{
URL url = new URL(baseURL,imgRef);
// check in the cash
bitmap = (PPSVGBitmap)imageCash.get(url);
// not found
if(bitmap == null)
{
bitmap = new PPSVGBitmap(tracker,url);
imageCash.put(url, bitmap);
}
}
catch (Exception ex)
{
}
return bitmap;
}
/**
* Is the image completely loaded?
*@return true if the image is fully loaded
*/
public boolean isImageComplete()
{
return imageComplete;
}
/**
* Returns a TinyBitmap for the given image URL or path.
* @param imgRef The image URL or path.
* @return a TinyBitmap object which gets its pixel data from
* the specified URL or path.
*/
public TinyBitmap createTinyBitmap( String imgRef )
{
return null; //new PPSVGBitmap(baseURL, imgRef);
}
/**
* Creates a TinyBitmap which decodes the image stored in the specified
* byte array, and at the specified offset and length.
* @param imageData an array of bytes, representing
* image data in a supported image format.
* @param imageOffset the offset of the beginning
* of the data in the array.
* @param imageLength the length of the data in the array.
* @return a TinyBitmap object.
*/
public TinyBitmap createTinyBitmap( byte[] imageData, int imageOffset, int imageLength )
{
return null; //new PPSVGBitmap(imageData, imageOffset, imageLength);
}
/** Starts the SVG player thread */
public synchronized void start()
{
thread = new Thread( this );
thread.setPriority( Thread.MIN_PRIORITY );
thread.start();
}
/** Stops the SVG player thread */
public synchronized void stop()
{
thread = null;
}
/**
* Fetch the specified currentURL in a separate thread and plays it
* in the renderer.
* If the user cancels it, the thread be changed from this thread.
*/
public void run()
{
Thread currentThread = Thread.currentThread();
try
{
while (currentThread == thread)
{
eventQueue.handleEvent(eventQueue.getNextEvent());
try
{
Thread.currentThread().sleep(50);
}
catch (InterruptedException e)
{
}
Thread.currentThread().yield();
}
}
catch( Throwable thr)
{
thr.printStackTrace();
alertError("Internal Error");
}
}
/**
* Loads and dispalys an SVG document from the given URL.
* External hyperlinks handling
* @param url the location of the svg file
*/
synchronized public void goURL( String url )
{
currentURL = url;
start();
}
/**
* This method is called when information about an image which was
* previously requested using an asynchronous interface becomes
* available. Asynchronous interfaces are method calls such as
* getWidth(ImageObserver) and drawImage(img, x, y, ImageObserver)
* which take an ImageObserver object as an argument.
*
* @param img the image being observed.
* @param flags the image status flags.
* @param x the <i>x</i> coordinate.
* @param y the <i>y</i> coordinate.
* @param width the width.
* @param height the height.
* @return <code>false</code> if the infoflags indicate that the
* image is completely loaded; <code>true</code> otherwise.
*/
public boolean imageUpdate( Image img, int flags, int x, int y, int width, int height )
{
if ( ( ( flags & 0x30 ) != 0 ) && ( owner != null ) )
owner.repaint( x, y, width, height );
return ( flags & 0x60 ) == 0;
}
/**
* Returns the icon's width.
*
* @return an int specifying the fixed width of the icon.
*/
public int getIconWidth()
{
return width;
}
/**
* Returns the icon's height.
*
* @return an int specifying the fixed height of the icon.
*/
public int getIconHeight()
{
return height;
}
/**
* Draw the icon at the specified location. Icon implementations
* may use the Component argument to get properties useful for
* painting, e.g. the foreground or background color.
* @param c the component displaying the icon
* @param g the graphics context
* @param x the x location
* @param y the y location
*/
public void paintIcon( Component c, Graphics g, int x, int y )
{
if(bimg == null)
{
raster.setCamera();
raster.update();
raster.sendPixels();
bimg = Toolkit.getDefaultToolkit().createImage(imageProducer);
}
if(bimg != null)
{
g.drawImage(bimg, 0, 0, this);
Toolkit.getDefaultToolkit().sync();// ????
}
}
/**
* The minimum size of the canvas.
*
* @return The minimum size of the canvas.
*/
public Dimension getMinimumSize()
{
return new Dimension( width, height );
}
/**
* The preferred size of the canvas.
*
* @return The preferred size of the canvas.
*/
public Dimension getPreferredSize()
{
return new Dimension( width, height );
}
/** Flushes allocated resources */
public void flush()
{
raster.flush();
if(bimg!= null)
{
bimg.flush();
bimg = null;
}
}
/**
* Loads an SVGT document from the given URL.
* @param urlStr The SVGT document URL or path.
* @return An SVGT document.
*/
public SVGDocument loadSVG( String urlStr )
{
System.out.println(""+urlStr);
alertWait("Wait...");
InputStream is = null;
try
{
URL url = new URL(baseURL,urlStr);
baseURL = url;
is = url.openStream();
if(url.toString().endsWith("svgz"))
{
is = new GZIPInputStream(is);
}
}
catch( Exception ex)
{
//System.out.println("ioe" + ex);
alertError("Not in SVGT format");
}
return loadSVG(is);
}
/**
* Loads an SVGT document from the given InputStream.
* @param is The InputStream.
* @return An SVGT document.
*/
public SVGDocument loadSVG(InputStream is)
{
alertWait("Wait...");
String str = "";
loaded = false;
SVGDocument doc = raster.createSVGDocument();
try {
// Read and parse the SVGT stream
TinyPixbuf pixbuf = raster.getPixelBuffer();
// Create the SVGT attributes parser
SVGAttr attrParser = new SVGAttr(pixbuf.width, pixbuf.height);
// Create the SVGT stream parser
SVGParser parser = new SVGParser(attrParser);
// Parse the input SVGT stream parser into the document
parser.load(doc,is);
str = "www.tinyline.com";
loaded = true;
alertInit(str);
}
catch(OutOfMemoryError memerror)
{
doc = null;
Runtime.getRuntime().gc();
alertError("Not enought memory");
}
catch(SecurityException secex)
{
doc = null;
alertError("Security violation");
}
catch( Exception ex)
{
//System.out.println("ioe" + ex);
doc = null;
alertError("Not in SVGT format");
}
catch( Throwable thr)
{
//System.out.println("ioe" + thr);
doc = null;
alertError("Not in SVGT format");
}
finally
{
try
{
if (is != null) is.close();
}
catch( IOException ioe)
{
//System.out.println("ioe" + ioe);
alertError(ioe.getMessage());
}
}
return doc;
}
/**
* StatusBar: shows an alert
* @param s the message
*/
public void alertError( String s )
{
if ( owner != null )
owner.repaint();
System.out.println( s );
}
/**
* StatusBar: shows a wait
* @param s the message
*/
public void alertWait( String s )
{
if ( owner != null )
owner.repaint();
System.out.println( s );
}
/**
* StatusBar: inits the bar
* @param s the message
*/
public void alertInit( String s )
{
if ( owner != null )
owner.repaint();
System.out.println( s );
}
}