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: + *
    + *
  1. exec: Execute the command, returning + * immediately even if the command is still + * running. This would be appropriate + * for printing a file. + *
  2. 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). + *
  3. 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: + *
    + *
  1. Exec.exec("/usr/ucb/lpr Some-File");
    + *
  2. + *        Exec.execWait("/usr/local/bin/javac Foo.java");
    + *        Exec.execWait("/usr/local/bin/java Foo");
    + *        
    + *
  3. 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; + } +}