diff --git a/j2kviewer/build.xml b/j2kviewer/build.xml
new file mode 100644
index 00000000..e3275112
--- /dev/null
+++ b/j2kviewer/build.xml
@@ -0,0 +1,35 @@
+
+ Seb's J2K viewer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/j2kviewer/src/Exec.java b/j2kviewer/src/Exec.java
new file mode 100644
index 00000000..c8b09abc
--- /dev/null
+++ b/j2kviewer/src/Exec.java
@@ -0,0 +1,212 @@
+import java.io.*;
+
+// This appears in Core Web Programming from
+// Prentice Hall Publishers, and may be freely used
+// or adapted. 1997 Marty Hall, hall@apl.jhu.edu.
+
+/** A class that eases the pain of running external
+ * processes from applications.
+ * Lets you run a program three ways:
+ *
+ * - exec: Execute the command, returning
+ * immediately even if the command is still
+ * running. This would be appropriate
+ * for printing a file.
+ *
- execWait: Execute the command, but
+ * don't return until the command finishes.
+ * This would be appropriate for
+ * sequential commands where the first depends
+ * on the second having finished (e.g.
+ *
javac
followed by
+ * java
).
+ * - execPrint: Execute the command and
+ * print the output. This would be appropriate
+ * for the UNIX command
ls
.
+ *
+ * Note that the PATH is not taken into account,
+ * so you must specify the full pathname to
+ * the command, and shell builtin commands
+ * will not work. For instance, on Unix the above
+ * three examples might look like:
+ *
+ * Exec.exec("/usr/ucb/lpr Some-File");
+ *
+ * Exec.execWait("/usr/local/bin/javac Foo.java");
+ * Exec.execWait("/usr/local/bin/java Foo");
+ *
+ * Exec.execPrint("/usr/bin/ls -al");
+ *
+ *
+ * @author Marty Hall
+ * (
+ * hall@apl.jhu.edu)
+ * @version 1.0 1997
+ */
+
+public class Exec {
+ //----------------------------------------------------
+
+ private static boolean verbose = true;
+
+ /** Determines if the Exec class should print which
+ * commands are being executed, and print error
+ * messages if a problem is found. Default is true.
+ *
+ * @param verboseFlag true: print messages.
+ * false: don't.
+ */
+
+ public static void setVerbose(boolean verboseFlag) {
+ verbose = verboseFlag;
+ }
+
+ /** Will Exec print status messages? */
+
+ public static boolean getVerbose() {
+ return(verbose);
+ }
+
+ //----------------------------------------------------
+ /** Starts a process to execute the command. Returns
+ * immediately, even if the new process is still
+ * running.
+ *
+ * @param command The full pathname of the
+ * command to be executed. No shell builtins
+ * (e.g. "cd") or shell meta-chars (e.g. ">")
+ * allowed.
+ * @return false if a problem is known to occur, but
+ * since this returns immediately, problems
+ * aren't usually found in time.
+ * Returns true otherwise.
+ */
+
+ public static boolean exec(String command) {
+ return(exec(command, false, false));
+ }
+
+ //----------------------------------------------------
+ /** Starts a process to execute the command. Waits
+ * for the process to finish before returning.
+ *
+ * @param command The full pathname of the
+ * command to be executed. No shell builtins
+ * or shell meta-chars allowed.
+ * @return false if a problem is known to occur,
+ * either due to an exception or from the
+ * subprocess returning a non-zero value.
+ * Returns true otherwise.
+ */
+
+ public static boolean execWait(String command) {
+ return(exec(command, false, true));
+ }
+
+ //----------------------------------------------------
+ /** Starts a process to execute the command. Prints
+ * all output the command gives.
+ *
+ * @param command The full pathname of the
+ * command to be executed. No shell builtins
+ * or shell meta-chars allowed.
+ * @return false if a problem is known to occur,
+ * either due to an exception or from the
+ * subprocess returning a non-zero value.
+ * Returns true otherwise.
+ */
+
+ public static boolean execPrint(String command) {
+ return(exec(command, true, false));
+ }
+
+ //----------------------------------------------------
+ // This creates a Process object via
+ // Runtime.getRuntime.exec(). Depending on the
+ // flags, it may call waitFor on the process
+ // to avoid continuing until the process terminates,
+ // or open an input stream from the process to read
+ // the results.
+
+ private static boolean exec(String command,
+ boolean printResults,
+ boolean wait) {
+ if (verbose) {
+ printSeparator();
+ System.out.println("Executing '" + command + "'.");
+ }
+ try {
+ // Start running command, returning immediately.
+ Process p = Runtime.getRuntime().exec(command);
+
+ // Print the output. Since we read until
+ // there is no more input, this causes us
+ // to wait until the process is completed
+ if(printResults) {
+ BufferedInputStream buffer =
+ new BufferedInputStream(p.getInputStream());
+ DataInputStream commandResult =
+ new DataInputStream(buffer);
+ String s = null;
+ try {
+ while ((s = commandResult.readLine()) != null)
+ System.out.println("Output: " + s);
+ commandResult.close();
+ if (p.exitValue() != 0) {
+ if (verbose)
+ printError(command +
+ " -- p.exitValue() != 0");
+ return(false);
+ }
+ // Ignore read errors; they mean process is done
+ } catch (Exception e) {}
+
+ // If you don't print the results, then you
+ // need to call waitFor to stop until the process
+ // is completed
+ } else if (wait) {
+ try {
+ System.out.println(" ");
+ int returnVal = p.waitFor();
+ if (returnVal != 0) {
+ if (verbose)
+ printError(command);
+ return(false);
+ }
+ } catch (Exception e) {
+ if (verbose)
+ printError(command, e);
+ return(false);
+ }
+ }
+ } catch (Exception e) {
+ if (verbose)
+ printError(command, e);
+ return(false);
+ }
+ return(true);
+ }
+
+ //----------------------------------------------------
+
+ private static void printError(String command,
+ Exception e) {
+ System.out.println("Error doing exec(" +
+ command + "): " + e.getMessage());
+ System.out.println("Did you specify the full " +
+ "pathname?");
+ }
+
+ private static void printError(String command) {
+ System.out.println("Error executing '" +
+ command + "'.");
+ }
+
+ //----------------------------------------------------
+
+ private static void printSeparator() {
+ System.out.println
+ ("==============================================");
+ }
+
+ //----------------------------------------------------
+}
diff --git a/j2kviewer/src/ImageViewer.java b/j2kviewer/src/ImageViewer.java
new file mode 100644
index 00000000..1eabc60d
--- /dev/null
+++ b/j2kviewer/src/ImageViewer.java
@@ -0,0 +1,222 @@
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.awt.image.*;
+import java.awt.geom.*;
+import java.net.URL;
+import javax.swing.border.*;
+import java.util.*;
+import java.io.*;
+
+public class ImageViewer extends JApplet
+{
+ private class zoomLevel {
+ int x1, y1, x2, y2, zf;
+
+ zoomLevel() {}
+ zoomLevel(zoomLevel zl)
+ {
+ x1 = zl.x1;
+ y1 = zl.y1;
+ x2 = zl.x2;
+ y2 = zl.y2;
+ zf = zl.zf;
+ }
+ }
+
+ private BufferedImage bi;
+ private Graphics2D big;
+ private MML myMML;
+ private int iw, ih;
+ private int selected = 0, imgId;
+ private Image img;
+ private PgmImage pgm = new PgmImage();
+ private String cmdline = new String();
+ private static String hostname;
+ private static boolean isApplet = true;
+ private boolean fullRefresh = false;
+ private Point offset = new Point(0,0);
+ private zoomLevel zl = new zoomLevel();
+ private Rectangle rect = new Rectangle();
+ private Stack zoomStack = new Stack();
+ private static String j2kfilename;
+
+ public int getX() { return offset.x; }
+ public int getY() { return offset.y; }
+ public int getWidth() { return iw; }
+ public int getHeight() { return ih; }
+
+ public void destroy()
+ {
+ }
+
+ public void zoomIn()
+ {
+ Dimension asz = this.getSize();
+ int maxzf = 3;
+ int coef = 1;
+ int r;
+
+ cmdline =
+ "/bin/sh get.sh " + j2kfilename + " " + iw
+ + " " + ih + " " + rect.x + " " + rect.y + " "
+ + rect.width + " " + rect.height;
+ Exec.execPrint(cmdline);
+
+ rect.x = rect.y = rect.width = rect.height = 0;
+
+ img = pgm.open("out.pgm");
+
+ iw = img.getWidth(this);
+ ih = img.getHeight(this);
+ bi = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+ big = bi.createGraphics();
+ selected = 0;
+ fullRefresh = true;
+ repaint();
+ }
+
+ public void zoomOut()
+ {
+ }
+
+ public void init()
+ {
+ String str;
+ int port;
+
+ imgId = 4;
+ if (isApplet && (((hostname = this.getParameter("hostname")) == null)
+ || hostname.equals("")))
+ hostname = "localhost";
+ if (!isApplet || ((str = this.getParameter("cmdPort")) == null)) {
+ port = 3000;
+ } else {
+ port = new Integer(str).intValue();
+ }
+
+ this.setSize(512, 512);
+ Dimension asz = this.getSize();
+ zl.x2 = asz.width;
+ zl.y2 = asz.height;
+
+ cmdline =
+ "/bin/sh get.sh " + j2kfilename + " " + asz.width
+ + " " + asz.height + " " + zl.x1 + " " + zl.y1 + " "
+ + zl.x2 + " " + zl.y2;
+ Exec.execPrint(cmdline);
+ img = pgm.open("out.pgm");
+
+ iw = img.getWidth(this);
+ ih = img.getHeight(this);
+
+ setBackground(Color.black);
+ bi = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+ big = bi.createGraphics();
+ myMML = new MML(this);
+ addMouseListener(myMML);
+ addMouseMotionListener(myMML);
+ }
+
+ public void setSelected(int state)
+ {
+ if (state != selected) {
+ selected = state;
+ repaint();
+ }
+ }
+
+ public boolean isInsideRect(int x, int y)
+ {
+ return rect.contains(x - offset.x, y - offset.y);
+ }
+
+ public void setRGeom(int x1, int y1, int x2, int y2)
+ {
+ rect.x = Math.min(x1,x2) - offset.x;
+ rect.y = Math.min(y1,y2) - offset.y;
+ rect.width = Math.abs(x2-x1);
+ rect.height = Math.abs(y2-y1);
+ }
+
+ public void paint(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ Dimension asz = this.getSize();
+
+ if (fullRefresh) {
+ g2.clearRect(0, 0, asz.width, asz.height);
+ fullRefresh = false;
+ }
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ big.setColor(Color.black);
+ offset.x = (int) (asz.width - iw) / 2;
+ offset.y = (int) (asz.height - ih) / 2;
+ big.drawImage(img, 0, 0, this);
+ big.setPaint(Color.red);
+ if ((rect.width > 0) && (rect.height > 0))
+ big.draw(rect);
+ if (selected == 1)
+ shadeExt(big, 0, 0, 0, 64);
+ else if (selected == 2) {
+ shadeExt(big, 0, 0, 0, 255);
+ selected = 1;
+ }
+ g2.drawImage(bi, offset.x, offset.y, this);
+ }
+
+ private void shadeRect(Graphics2D g2, int r, int g, int b, int a)
+ {
+ g2.setPaint(new Color(r, g, b, a));
+ g2.fillRect(rect.x + 1, rect.y + 1, rect.width - 1, rect.height - 1);
+ }
+
+ private void shadeExt(Graphics2D g2, int r, int g, int b, int a)
+ {
+ g2.setPaint(new Color(r, g, b, a));
+ g2.fillRect(0, 0, iw, rect.y); /* _N_ */
+ g2.fillRect(rect.x + rect.width + 1, rect.y,
+ iw - rect.x - rect.width - 1, rect.height + 1); /* E */
+ g2.fillRect(0, rect.y, rect.x, rect.height + 1); /* W */
+ g2.fillRect(0, rect.y + rect.height + 1,
+ iw, ih - rect.y - rect.height - 1); /* _S_ */
+ }
+
+ protected URL getURL(String filename)
+ {
+ URL codeBase = this.getCodeBase();
+ URL url = null;
+
+ try {
+ url = new URL(codeBase, filename);
+ } catch (java.net.MalformedURLException e) {
+ System.out.println("Couldn't create image: badly specified URL");
+ return null;
+ }
+
+ return url;
+ }
+
+ public static void main(String s[])
+ {
+ if (s.length > 0)
+ j2kfilename = s[0];
+ else
+ j2kfilename = "girl";
+ System.out.println(j2kfilename);
+ isApplet = false;
+ JFrame f = new JFrame("ImageViewer");
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {System.exit(0);}
+ });
+ JApplet applet = new ImageViewer();
+ f.getContentPane().add("Center", applet);
+ applet.init();
+ f.pack();
+ f.setSize(new Dimension(550,550));
+ f.show();
+ }
+}
diff --git a/j2kviewer/src/MML.java b/j2kviewer/src/MML.java
new file mode 100644
index 00000000..7c49ff2f
--- /dev/null
+++ b/j2kviewer/src/MML.java
@@ -0,0 +1,85 @@
+import java.awt.event.*;
+
+class MML implements MouseMotionListener, MouseListener
+{
+ public void mouseExited(MouseEvent e) {}
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseClicked(MouseEvent e) {}
+
+ private ImageViewer applet;
+ private int x1, y1, x2, y2, zf, btn;
+ private boolean zoomrq;
+
+ public MML(ImageViewer iv)
+ {
+ x1 = y1 = -1;
+ applet = iv;
+ zoomrq = false;
+ zf = 0;
+ }
+
+ private boolean isInside(int x, int y)
+ {
+ x -= applet.getX();
+ y -= applet.getY();
+ return (x >= 0) && (x < applet.getWidth())
+ && (y >= 0) && (y < applet.getHeight());
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ btn = e.getButton();
+ if (applet.isInsideRect(e.getX(), e.getY())) {
+ applet.setSelected(2);
+ applet.repaint();
+ zoomrq = true;
+ } else {
+ applet.setRGeom(0, 0, 0, 0);
+ applet.setSelected(0);
+ applet.repaint();
+ x1 = y1 = -1;
+ }
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ if (zoomrq && (e.getButton() == 1)) {
+ applet.zoomIn();
+ zoomrq = false;
+ } else if (e.getButton() == 3) {
+ applet.zoomOut();
+ zoomrq = false;
+ }
+ }
+
+ public void mouseMoved(MouseEvent e)
+ {
+ applet.setSelected(applet.isInsideRect(e.getX(), e.getY()) ? 1 : 0);
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ String str;
+
+ if (btn == 1) {
+ x2 = e.getX();
+ y2 = e.getY();
+
+ applet.setSelected(0);
+ zoomrq = false;
+
+ if (isInside(x2, y2)) {
+ str = "[IN ]";
+ if (x1 == -1) {
+ x1 = x2;
+ y1 = y2;
+ } else {
+ applet.setRGeom(x1, y1, x2, y2);
+ applet.repaint();
+ }
+ } else {
+ str = "[OUT]";
+ }
+ }
+ }
+}
diff --git a/j2kviewer/src/PgmImage.java b/j2kviewer/src/PgmImage.java
new file mode 100644
index 00000000..324fbfab
--- /dev/null
+++ b/j2kviewer/src/PgmImage.java
@@ -0,0 +1,93 @@
+import java.awt.*;
+import java.awt.image.*;
+import java.net.*;
+import java.io.*;
+import java.util.regex.*;
+
+class PgmImage extends Component
+{
+ private Socket s;
+ private BufferedReader in;
+ private int x, y;
+
+ PgmImage()
+ {
+ }
+
+ private String read()
+ {
+ try { return in.readLine(); }
+ catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public Image open(String filename)
+ {
+ String str;
+ Pattern pat;
+ Matcher mat;
+ int bytes, width, height, depth;
+ FileInputStream fis;
+
+ try {
+ in = new BufferedReader(
+ new InputStreamReader(
+ fis = new FileInputStream(
+ new File(filename))));
+
+ pat = Pattern.compile("^P5$");
+ mat = pat.matcher(str = read());
+ mat.matches();
+ pat = Pattern.compile("^(\\d+) (\\d+)$");
+ mat = pat.matcher(str = read());
+ mat.matches();
+ x = new Integer(mat.group(1)).intValue();
+ y = new Integer(mat.group(2)).intValue();
+ width = x;
+ height = y;
+ depth = 1;
+ pat = Pattern.compile("^255$");
+ mat = pat.matcher(str = read());
+ mat.matches();
+ bytes = x*y;
+ char[] buf = new char[bytes];
+ int r, offset = 0;
+ while (bytes > 0) {
+ try { r = in.read(buf, offset, bytes); offset += r; bytes -= r; }
+ catch (IOException e) { e.printStackTrace(); }
+ }
+ int[] buf2 = new int[buf.length];
+ if (depth == 3) {
+ for (int i = 0; i < buf.length/3; ++i)
+ buf2[i] = 0xFF << 24 | buf[3*i] << 16 | buf[3*i+1] << 8 | buf[3*i+2];
+ } else {
+ for (int i = 0; i < buf.length; ++i)
+ buf2[i] = 0xFF << 24 | buf[i] << 16 | buf[i] << 8 | buf[i];
+ }
+ fis.close();
+ return createImage(new MemoryImageSource(width, height, buf2, 0, width));
+ } catch (IOException e) { e.printStackTrace(); }
+ return null;
+ }
+
+ public void close()
+ {
+ }
+
+ public boolean bye()
+ {
+ return true;
+ }
+
+ public int getXOffset()
+ {
+ return x;
+ }
+
+ public int getYOffset()
+ {
+ return y;
+ }
+}