Initial revision
authorSebastien Lugan <slugan@users.noreply.github.com>
Tue, 17 Feb 2004 16:33:43 +0000 (16:33 +0000)
committerSebastien Lugan <slugan@users.noreply.github.com>
Tue, 17 Feb 2004 16:33:43 +0000 (16:33 +0000)
j2kviewer/build.xml [new file with mode: 0644]
j2kviewer/src/Exec.java [new file with mode: 0644]
j2kviewer/src/ImageViewer.java [new file with mode: 0644]
j2kviewer/src/MML.java [new file with mode: 0644]
j2kviewer/src/PgmImage.java [new file with mode: 0644]

diff --git a/j2kviewer/build.xml b/j2kviewer/build.xml
new file mode 100644 (file)
index 0000000..e327511
--- /dev/null
@@ -0,0 +1,35 @@
+<project name="seb_j2kviewer" default="dist" basedir=".">
+  <description>Seb's J2K viewer</description>
+  <property name="src"   location="src"  />
+  <property name="build" location="build"/>
+  <property name="dist"  location="dist" />
+
+  <target name="init">
+    <tstamp/>
+    <mkdir dir="${build}"/>
+  </target>
+  <target name="compile" depends="init">
+    <javac srcdir="${src}" destdir="${build}"/>
+  </target>
+  <target name="dist" depends="compile">
+    <mkdir dir="${dist}"/>
+    <jar jarfile="${dist}/seb_j2kviewer-${DSTAMP}.jar"
+         basedir="${build}" manifest="${dist}/manifest.txt"/>
+    <exec dir="${dist}" executable="ln">
+      <arg line="-sf seb_j2kviewer-${DSTAMP}.jar seb_j2kviewer.jar"/>
+    </exec>
+  </target>
+  <target name="clean">
+    <delete dir="${build}"/>
+    <delete dir="${dist}"/>
+  </target>
+  <target name="test" depends="dist">
+    <exec executable="appletviewer"><arg line="dist.html"/></exec>
+  </target>
+  <target name="build_test" depends="compile">
+    <exec executable="appletviewer"><arg line="compile.html"/></exec>
+  </target>
+  <target name="build_testj" depends="compile">
+    <exec executable="java"><arg line="-classpath build ImageViewer girl"/></exec>
+  </target>
+</project>
diff --git a/j2kviewer/src/Exec.java b/j2kviewer/src/Exec.java
new file mode 100644 (file)
index 0000000..c8b09ab
--- /dev/null
@@ -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:
+ *  <OL>
+ *     <LI><B>exec</B>: Execute the command, returning
+ *         immediately even if the command is still
+ *         running. This would be appropriate
+ *         for printing a file.
+ *     <LI><B>execWait</B>: 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.
+ *         <CODE>javac</CODE> followed by
+ *         <CODE>java</CODE>).
+ *     <LI><B>execPrint</B>: Execute the command and
+ *         print the output. This would be appropriate
+ *         for the UNIX command <CODE>ls</CODE>.
+ *  </OL>
+ *  Note that the PATH is not taken into account,
+ *  so  you must specify the <B>full</B> pathname to
+ *  the command, and shell builtin commands
+ *  will not work. For instance, on Unix the above
+ *  three examples might look like:
+ *  <OL>
+ *    <LI><PRE>Exec.exec("/usr/ucb/lpr Some-File");</PRE>
+ *    <LI><PRE>
+ *        Exec.execWait("/usr/local/bin/javac Foo.java");
+ *        Exec.execWait("/usr/local/bin/java Foo");
+ *        </PRE>
+ *    <LI><PRE>Exec.execPrint("/usr/bin/ls -al");</PRE>
+ *  </OL>
+ *
+ * @author Marty Hall
+ *  (<A HREF="mailto:hall@apl.jhu.edu">
+ *   hall@apl.jhu.edu</A>)
+ * @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 <B>full</B> 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 <B>full</B> 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 <B>full</B> 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 (file)
index 0000000..1eabc60
--- /dev/null
@@ -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 (file)
index 0000000..7c49ff2
--- /dev/null
@@ -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]\a";
+      }
+    }    
+  }
+}
diff --git a/j2kviewer/src/PgmImage.java b/j2kviewer/src/PgmImage.java
new file mode 100644 (file)
index 0000000..324fbfa
--- /dev/null
@@ -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;
+  }
+}