summaryrefslogtreecommitdiff
path: root/japi/ScanIt.java
diff options
context:
space:
mode:
Diffstat (limited to 'japi/ScanIt.java')
-rw-r--r--japi/ScanIt.java391
1 files changed, 391 insertions, 0 deletions
diff --git a/japi/ScanIt.java b/japi/ScanIt.java
new file mode 100644
index 0000000..21afba0
--- /dev/null
+++ b/japi/ScanIt.java
@@ -0,0 +1,391 @@
+/* sane - Scanner Access Now Easy.
+ Copyright (C) 1997 Jeffrey S. Freedman
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice. */
+
+/**
+ ** ScanIt.java - Do the actual scanning for SANE.
+ **
+ ** Written: 11/3/97 - JSF
+ **/
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.awt.image.ImageProducer;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ColorModel;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.BufferedWriter;
+import java.io.IOException;
+
+/*
+ * This class uses SANE to scan an image.
+ */
+public class ScanIt implements ImageProducer
+ {
+ // # lines we incr. image height.
+ private static final int STRIP_HEIGHT = 256;
+ private Sane sane;
+ private int handle = 0; // SANE device handle.
+ private Vector consumers = new Vector();
+ // File to write to.
+ private OutputStream outputFile = null;
+ private SaneParameters parms = new SaneParameters();
+ private ColorModel cm; // RGB color model.
+ private int width, height; // Dimensions.
+ private int x, y; // Position.
+ private int image[] = null; // Image that we build as we scan.
+ private int offset; // Offset within image in pixels if
+ // doing separate frames, bytes
+ // (3/word) if RBG.
+
+ /*
+ * Tell consumers our status. The scan is also terminated de-
+ * pending on the status.
+ */
+ private void tellStatus(int s)
+ {
+ Enumeration next = consumers.elements();
+ while (next.hasMoreElements())
+ {
+ ImageConsumer ic = (ImageConsumer) next.nextElement();
+ ic.imageComplete(s);
+ }
+ // Done? Stop scan.
+ if (s == ImageConsumer.STATICIMAGEDONE ||
+ s == ImageConsumer.IMAGEERROR)
+ sane.cancel(handle);
+ }
+
+ /*
+ * Tell consumers the image size.
+ */
+ private void tellDimensions(int w, int h)
+ {
+ System.out.println("tellDimensions: " + w + ", " + h);
+ Enumeration next = consumers.elements();
+ while (next.hasMoreElements())
+ {
+ ImageConsumer ic = (ImageConsumer) next.nextElement();
+ ic.setDimensions(w, h);
+ }
+ }
+
+ /*
+ * Send pixels to the clients.
+ */
+ private void tellPixels(int x, int y, int w, int h)
+ {
+/*
+ System.out.println("image length=" + image.length);
+ System.out.println("width=" + width);
+ System.out.println("tellPixels: x="+x +" y="+y + " w="+w
+ + " h="+h);
+ */
+ Enumeration next = consumers.elements();
+ while (next.hasMoreElements())
+ {
+ ImageConsumer ic = (ImageConsumer) next.nextElement();
+ ic.setPixels(x, y, w, h, cm, image, 0, width);
+ }
+ }
+
+ /*
+ * Construct.
+ */
+ public ScanIt(Sane s, int hndl)
+ {
+ sane = s;
+ handle = hndl;
+ }
+
+ /*
+ * Add a consumer.
+ */
+ public synchronized void addConsumer(ImageConsumer ic)
+ {
+ if (consumers.contains(ic))
+ return; // Already here.
+ consumers.addElement(ic);
+ }
+
+ /*
+ * Is a consumer in the list?
+ */
+ public synchronized boolean isConsumer(ImageConsumer ic)
+ { return consumers.contains(ic); }
+
+ /*
+ * Remove consumer.
+ */
+ public synchronized void removeConsumer(ImageConsumer ic)
+ { consumers.removeElement(ic); }
+
+ /*
+ * Add a consumer and start scanning.
+ */
+ public void startProduction(ImageConsumer ic)
+ {
+ System.out.println("In startProduction()");
+ addConsumer(ic);
+ scan();
+ }
+
+ /*
+ * Set file to write to.
+ */
+ public void setOutputFile(OutputStream o)
+ { outputFile = o; }
+
+ /*
+ * Ignore this:
+ */
+ public void requestTopDownLeftRightResend(ImageConsumer ic)
+ { }
+
+ /*
+ * Go to next line in image, reallocating if necessary.
+ */
+ private void nextLine()
+ {
+ x = 0;
+ ++y;
+ if (y >= height || image == null)
+ { // Got to reallocate.
+ int oldSize = image == null ? 0 : width*height;
+ height += STRIP_HEIGHT; // Add more lines.
+ int newSize = width*height;
+ int[] newImage = new int[newSize];
+ int i;
+ if (oldSize != 0) // Copy old data.
+ for (i = 0; i < oldSize; i++)
+ newImage[i] = image[i];
+ // Fill new pixels with 0's, setting
+ // alpha channel.
+ for (i = oldSize; i < newSize; i++)
+ newImage[i] = (255 << 24);
+ image = newImage;
+ System.out.println("nextLine: newSize="+newSize);
+ // Tell clients.
+ tellDimensions(width, height);
+ }
+ }
+
+ /*
+ * Process a buffer of data.
+ */
+ private boolean process(byte[] data, int readLen)
+ {
+ int prevY = y > 0 ? y : 0; // Save current Y-coord.
+ int i;
+ switch (parms.format)
+ {
+ case SaneParameters.FRAME_RED:
+ case SaneParameters.FRAME_GREEN:
+ case SaneParameters.FRAME_BLUE:
+ System.out.println("Process RED, GREEN or BLUE");
+ int cindex = 2 - (parms.format - SaneParameters.FRAME_RED);
+ // Single frame.
+ for (i = 0; i < readLen; ++i)
+ { // Doing a single color frame.
+ image[offset + i] |=
+ (((int) data[i]) & 0xff) << (8*cindex);
+ ++x;
+ if (x >= width)
+ nextLine();
+ }
+ break;
+ case SaneParameters.FRAME_RGB:
+ for (i = 0; i < readLen; ++i)
+ {
+ int b = 2 - (offset + i)%3;
+ image[(offset + i)/3] |=
+ (((int) data[i]) & 0xff) << (8*b);
+ if (b == 0)
+ {
+ ++x;
+ if (x >= width)
+ nextLine();
+ }
+ }
+ break;
+ case SaneParameters.FRAME_GRAY:
+ System.out.println("Process GREY");
+ // Single frame.
+ for (i = 0; i < readLen; ++i)
+ {
+ int v = ((int) data[i]) & 0xff;
+ image[offset + i] |= (v<<16) | (v<<8) | (v);
+ ++x;
+ if (x >= width)
+ nextLine();
+ }
+ break;
+ }
+ offset += readLen; // Update where we are.
+ // Show it.
+ System.out.println("PrevY = " + prevY + ", y = " + y);
+// tellPixels(0, prevY, width, y - prevY);
+ tellPixels(0, 0, width, height);
+ return true;
+ }
+
+ /*
+ * Start scanning.
+ */
+ public void scan()
+ {
+ int dataLen = 32*1024;
+ byte [] data = new byte[dataLen];
+ int [] readLen = new int[1];
+ int frameCnt = 0;
+ // For now, use default RGB model.
+ cm = ColorModel.getRGBdefault();
+ int status;
+ image = null;
+ do // Do each frame.
+ {
+ frameCnt++;
+ x = 0; // Init. position.
+ y = -1;
+ offset = 0;
+ System.out.println("Reading frame #" + frameCnt);
+ status = sane.start(handle);
+ if (status != Sane.STATUS_GOOD)
+ {
+ System.out.println("start() failed. Status= "
+ + status);
+ tellStatus(ImageConsumer.IMAGEERROR);
+ return;
+ }
+ status = sane.getParameters(handle, parms);
+ if (status != Sane.STATUS_GOOD)
+ {
+ System.out.println("getParameters() failed. Status= "
+ + status);
+ tellStatus(ImageConsumer.IMAGEERROR);
+ return; //++++cleanup.
+ }
+ if (frameCnt == 1) // First time?
+ {
+ width = parms.pixelsPerLine;
+ if (parms.lines >= 0)
+ height = parms.lines - STRIP_HEIGHT + 1;
+ else // Hand-scanner.
+ height = 0;
+ nextLine(); // Allocate image.
+ }
+ while ((status = sane.read(handle, data, dataLen, readLen))
+ == Sane.STATUS_GOOD)
+ {
+ System.out.println("Read " + readLen[0] + " bytes.");
+ if (!process(data, readLen[0]))
+ {
+ tellStatus(ImageConsumer.IMAGEERROR);
+ return;
+ }
+ }
+ if (status != Sane.STATUS_EOF)
+ {
+ System.out.println("read() failed. Status= "
+ + status);
+ tellStatus(ImageConsumer.IMAGEERROR);
+ return;
+ }
+ }
+ while (!parms.lastFrame);
+ height = y; // For now, send whole image here.
+ tellDimensions(width, height);
+ tellPixels(0, 0, width, height);
+ if (outputFile != null) // Write to file.
+ {
+ try
+ {
+ write(outputFile);
+ }
+ catch (IOException e)
+ { //+++++++++++++++
+ System.out.println("I/O error writing file.");
+ }
+ outputFile = null; // Clear for next time.
+ }
+ tellStatus(ImageConsumer.STATICIMAGEDONE);
+ image = null; // Allow buffer to be freed.
+ }
+
+ /*
+ * Write ppm/pnm output for last scan to a file.
+ */
+ private void write(OutputStream out) throws IOException
+ {
+ PrintWriter pout = new PrintWriter(out);
+ BufferedWriter bout = new BufferedWriter(pout);
+ int len = width*height; // Get # of pixels.
+ int i;
+ switch (parms.format)
+ {
+ case SaneParameters.FRAME_RED:
+ case SaneParameters.FRAME_GREEN:
+ case SaneParameters.FRAME_BLUE:
+ case SaneParameters.FRAME_RGB:
+ pout.print("P6\n# SANE data follows\n" +
+ width + ' ' + height + "\n255\n");
+ for (i = 0; i < len; i++)
+ {
+ int pix = image[i];
+ bout.write((pix >> 16) & 0xff);
+ bout.write((pix >> 8) & 0xff);
+ bout.write(pix & 0xff);
+ }
+ break;
+ case SaneParameters.FRAME_GRAY:
+ pout.print("P5\n# SANE data follows\n" +
+ width + ' ' + height + "\n255\n");
+ for (i = 0; i < len; i++)
+ {
+ int pix = image[i];
+ bout.write(pix & 0xff);
+ }
+ break;
+ }
+
+ bout.flush(); // Flush output.
+ pout.flush();
+ }
+ }