/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.apps.slideshow;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;
import javax.swing.JComponent;
import javax.swing.JWindow;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.bridge.ViewBox;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.renderer.StaticRenderer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;
public class Main extends JComponent {
StaticRenderer renderer;
UserAgent userAgent;
DocumentLoader loader;
BridgeContext ctx;
BufferedImage image;
BufferedImage display;
File [] files;
static int duration = 3000;
static int frameDelay = duration+7000;
boolean done = false;
public Main(File []files, Dimension size) {
setBackground(Color.black);
this.files = files;
renderer = new StaticRenderer();
userAgent = new UserAgentAdapter();
loader = new DocumentLoader(userAgent);
ctx = new BridgeContext(userAgent, loader);
boolean frameless = false;
if (size == null) {
size = Toolkit.getDefaultToolkit().getScreenSize();
frameless = true;
}
setPreferredSize(size);
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
if (done)
System.exit(0);
else
togglePause();
}
});
size.width += 2;
size.height += 2;
display = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_BGR);
Thread t = new RenderThread();
t.start();
JWindow w = new JWindow();
w.setBackground(Color.black);
w.getContentPane().setBackground(Color.black);
w.getContentPane().add(this);
w.pack();
w.setLocation(new Point(-1, -1));
w.setVisible(true);
}
class RenderThread extends Thread {
public void run() {
renderer.setDoubleBuffered(true);
for (int i=0; i<files.length; i++) {
GraphicsNode gvtRoot = null;
GVTBuilder builder = new GVTBuilder();
try {
System.out.println("Reading: " + files[i]);
Document svgDoc = loader.loadDocument
(files[i].toURL().toString());
System.out.println("Building: " + files[i]);
gvtRoot = builder.build(ctx, svgDoc);
System.out.println("Rendering: " + files[i]);
renderer.setTree(gvtRoot);
Element elt = ((SVGDocument)svgDoc).getRootElement();
renderer.setTransform
(ViewBox.getViewTransform
(null, elt, display.getWidth(), display.getHeight()));
renderer.updateOffScreen(display.getWidth(),
display.getHeight());
Rectangle r = new Rectangle(0, 0,
display.getWidth(),
display.getHeight());
renderer.repaint(r);
System.out.println("Painting: " + files[i]);
image = renderer.getOffScreen();
setTransition(image);
} catch (Throwable t) {
t.printStackTrace();
}
}
if (transitionThread != null) {
try {
transitionThread.join();
} catch (InterruptedException ie) { }
done = true;
setCursor(new Cursor(Cursor.WAIT_CURSOR));
}
}
}
Thread transitionThread = null;
public void setTransition(BufferedImage newImg) {
synchronized (this) {
while (transitionThread != null) {
try {
wait();
} catch (InterruptedException ie) { }
}
transitionThread = new TransitionThread(newImg);
transitionThread.start();
}
}
long startLastTransition=0;
boolean paused = false;
public void togglePause() {
synchronized(this) {
paused = !paused;
Cursor c;
if (paused) {
c = new Cursor(Cursor.WAIT_CURSOR);
} else {
c = new Cursor(Cursor.DEFAULT_CURSOR);
if (transitionThread != null) {
synchronized (transitionThread) {
transitionThread.notifyAll();
}
}
}
setCursor(c);
}
}
class TransitionThread extends Thread {
BufferedImage src;
int blockw = 75;
int blockh = 75;
public TransitionThread(BufferedImage bi) {
src = bi;
}
public void run() {
int xblocks = (display.getWidth()+blockw-1)/blockw;
int yblocks = (display.getHeight()+blockh-1)/blockh;
int nblocks = xblocks*yblocks;
int tblock = duration/nblocks;
Point [] rects = new Point[nblocks];
for (int y=0; y<yblocks; y++)
for (int x=0; x<xblocks; x++)
rects[y*xblocks+x] = new Point(x, y);
Graphics2D g2d = display.createGraphics();
g2d.setColor(new Color(0,0,0));
long currTrans = System.currentTimeMillis();
while ((currTrans-startLastTransition) < frameDelay) {
try {
long stime = frameDelay-(currTrans-startLastTransition);
if (stime > 500) {
System.gc();
currTrans = System.currentTimeMillis();
stime = frameDelay-(currTrans-startLastTransition);
}
if (stime > 0) sleep(stime);
} catch (InterruptedException ie) { }
currTrans = System.currentTimeMillis();
}
synchronized(this) {
while (paused) {
try {
wait();
} catch (InterruptedException ie) { }
}
}
long last = startLastTransition = System.currentTimeMillis();
for (int i=0; i<rects.length; i++) {
int idx = (int)(Math.random()*(rects.length-i));
Point pt = rects[idx];
for (int j=idx+1; j<rects.length-i;j++)
rects[j-1] = rects[j];
int x=pt.x*blockw, y=pt.y*blockh;
int w=blockw, h = blockh;
if (x+w > src.getWidth()) w = src.getWidth()-x;
if (y+h > src.getHeight()) h = src.getHeight()-y;
synchronized (display) {
g2d.fillRect(x, y, w, h);
BufferedImage sub;
sub = src.getSubimage(x, y, w, h);
g2d.drawImage(sub, null, x, y);
}
repaint(x, y, w, h);
long current = System.currentTimeMillis();
try {
long dt = current-last;
if (dt < tblock)
sleep(tblock-dt);
} catch (InterruptedException ie) { }
last = current;
}
synchronized (Main.this) {
transitionThread = null;
Main.this.notifyAll();
}
}
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
if (display == null) return;
// System.out.println("Drawing Image: " + display);
g2d.drawImage(display, null, 0, 0);
}
public static void readFileList(String file, Vector fileVec) {
BufferedReader br;
try {
br = new BufferedReader(new FileReader(file));
} catch(FileNotFoundException fnfe) {
System.err.println("Unable to open file-list: " + file);
return;
}
try {
URL flURL = new File(file).toURL();
String line;
while ((line = br.readLine()) != null) {
String str = line;
int idx = str.indexOf('#');
if (idx != -1)
str = str.substring(0, idx);
str.trim();
if (str.length() == 0)
continue;
try {
URL imgURL = new URL(flURL, str);
fileVec.add(imgURL.getFile());
} catch (MalformedURLException mue) {
System.err.println("Can't make sense of line:\n " + line);
}
}
} catch (IOException ioe) {
System.err.println("Error while reading file-list: " + file);
}
}
public static void main(String []args) {
Vector fileVec = new Vector();
Dimension d = null;
if (args.length == 0) {
showUsage();
return;
}
for (int i=0; i<args.length; i++) {
if ((args[i].equals("-h")) ||
(args[i].equals("-help")) ||
(args[i].equals("--help"))){
showUsage();
return;
} else if (args[i].equals("--")) {
i++;
while(i < args.length) {
fileVec.add(args[i++]);
}
break;
} else if ((args[i].equals("-fl"))||
(args[i].equals("--file-list"))) {
if (i+1 == args.length) {
System.err.println
("Must provide name of file list file after " +
args[i]);
break;
}
readFileList(args[i+1], fileVec);
i++;
} else if ((args[i].equals("-ft"))||
(args[i].equals("--frame-time"))) {
if (i+1 == args.length) {
System.err.println
("Must provide time in millis after " + args[i]);
break;
}
try {
frameDelay = Integer.decode(args[i+1]).intValue();
i++;
} catch (NumberFormatException nfe) {
System.err.println
("Can't parse frame time: " + args[i+1]);
}
} else if ((args[i].equals("-tt"))||
(args[i].equals("--transition-time"))) {
if (i+1 == args.length) {
System.err.println
("Must provide time in millis after " + args[i]);
break;
}
try {
duration = Integer.decode(args[i+1]).intValue();
i++;
} catch (NumberFormatException nfe) {
System.err.println
("Can't parse transition time: " + args[i+1]);
}
} else if ((args[i].equals("-ws"))||
(args[i].equals("--window-size"))) {
if (i+1 == args.length) {
System.err.println
("Must provide window size [w,h] after " + args[i]);
break;
}
try {
int idx = args[i+1].indexOf(',');
int w, h;
if (idx == -1)
w = h = Integer.decode(args[i+1]).intValue();
else {
String wStr = args[i+1].substring(0,idx);
String hStr = args[i+1].substring(idx+1);
w = Integer.decode(wStr).intValue();
h = Integer.decode(hStr).intValue();
}
d = new Dimension(w, h);
i++;
} catch (NumberFormatException nfe) {
System.err.println
("Can't parse window size: " + args[i+1]);
}
} else
fileVec.add(args[i]);
}
File [] files = new File[fileVec.size()];
for (int i=0; i<fileVec.size(); i++) {
try {
files[i] = new File((String)fileVec.get(i));
} catch (Throwable t) {
t.printStackTrace();
}
}
new Main(files, d);
}
public static void showUsage() {
System.out.println
("Options:\n" +
" -- : Remaining args are file names\n" +
" -fl <file>\n" +
" --file-list <file> : file contains list of images to\n" +
" show one per line\n" +
" -ws <width>[,<height>]\n" +
" -window-size <width>[,<height>] : Set the size of slideshow window\n" +
" defaults to full screen\n" +
" -ft <int>\n" +
" --frame-time <int> : Amount of time in millisecs to\n" +
" show each frame.\n" +
" Includes transition time.\n" +
" -tt <int>\n" +
" --transition-time <int> : Amount of time in millisecs to\n" +
" transition between frames.\n" +
" <file> : SVG file to display");
}
}