• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 1997 Jeffrey S. Freedman
3    This file is part of the SANE package.
4 
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 
18    As a special exception, the authors of SANE give permission for
19    additional uses of the libraries contained in this release of SANE.
20 
21    The exception is that, if you link a SANE library with other files
22    to produce an executable, this does not by itself cause the
23    resulting executable to be covered by the GNU General Public
24    License.  Your use of that executable is in no way restricted on
25    account of linking the SANE library code into it.
26 
27    This exception does not, however, invalidate any other reasons why
28    the executable file might be covered by the GNU General Public
29    License.
30 
31    If you submit changes to SANE to the maintainers to be included in
32    a subsequent release, you agree by submitting the changes that
33    those changes may be distributed with this exception intact.
34 
35    If you write modifications of your own for SANE, it is your choice
36    whether to permit this exception to apply to your modifications.
37    If you do not wish that, delete this exception notice.  */
38 
39 /**
40  **	ScanIt.java - Do the actual scanning for SANE.
41  **
42  **	Written: 11/3/97 - JSF
43  **/
44 
45 import java.util.Vector;
46 import java.util.Enumeration;
47 import java.awt.image.ImageProducer;
48 import java.awt.image.ImageConsumer;
49 import java.awt.image.ColorModel;
50 import java.io.OutputStream;
51 import java.io.PrintWriter;
52 import java.io.BufferedWriter;
53 import java.io.IOException;
54 
55 /*
56  *	This class uses SANE to scan an image.
57  */
58 public class ScanIt implements ImageProducer
59     {
60 					// # lines we incr. image height.
61     private static final int STRIP_HEIGHT = 256;
62     private Sane sane;
63     private int handle = 0;		// SANE device handle.
64     private Vector consumers = new Vector();
65 					// File to write to.
66     private OutputStream outputFile = null;
67     private SaneParameters parms = new SaneParameters();
68     private ColorModel cm;		// RGB color model.
69     private int width, height;		// Dimensions.
70     private int x, y;			// Position.
71     private int image[] = null;		// Image that we build as we scan.
72     private int offset;			// Offset within image in pixels if
73 					//   doing separate frames, bytes
74 					//   (3/word) if RBG.
75 
76 	/*
77 	 *	Tell consumers our status.  The scan is also terminated de-
78 	 *	pending on the status.
79 	 */
tellStatus(int s)80     private void tellStatus(int s)
81 	{
82 	Enumeration next = consumers.elements();
83 	while (next.hasMoreElements())
84 		{
85 		ImageConsumer ic = (ImageConsumer) next.nextElement();
86 		ic.imageComplete(s);
87 		}
88 					// Done?  Stop scan.
89 	if (s == ImageConsumer.STATICIMAGEDONE ||
90 	    s == ImageConsumer.IMAGEERROR)
91 		sane.cancel(handle);
92 	}
93 
94 	/*
95 	 *	Tell consumers the image size.
96 	 */
tellDimensions(int w, int h)97     private void tellDimensions(int w, int h)
98 	{
99 	System.out.println("tellDimensions:  " + w + ", " + h);
100 	Enumeration next = consumers.elements();
101 	while (next.hasMoreElements())
102 		{
103 		ImageConsumer ic = (ImageConsumer) next.nextElement();
104 		ic.setDimensions(w, h);
105 		}
106 	}
107 
108 	/*
109 	 *	Send pixels to the clients.
110 	 */
tellPixels(int x, int y, int w, int h)111     private void tellPixels(int x, int y, int w, int h)
112 	{
113 /*
114 	System.out.println("image length=" + image.length);
115 	System.out.println("width=" + width);
116 	System.out.println("tellPixels:  x="+x +" y="+y + " w="+w
117 					+ " h="+h);
118  */
119 	Enumeration next = consumers.elements();
120 	while (next.hasMoreElements())
121 		{
122 		ImageConsumer ic = (ImageConsumer) next.nextElement();
123 		ic.setPixels(x, y, w, h, cm, image, 0, width);
124 		}
125 	}
126 
127 	/*
128 	 *	Construct.
129 	 */
ScanIt(Sane s, int hndl)130     public ScanIt(Sane s, int hndl)
131 	{
132 	sane = s;
133 	handle = hndl;
134 	}
135 
136 	/*
137 	 *	Add a consumer.
138 	 */
addConsumer(ImageConsumer ic)139     public synchronized void addConsumer(ImageConsumer ic)
140 	{
141 	if (consumers.contains(ic))
142 		return;			// Already here.
143 	consumers.addElement(ic);
144 	}
145 
146 	/*
147 	 *	Is a consumer in the list?
148 	 */
isConsumer(ImageConsumer ic)149     public synchronized boolean isConsumer(ImageConsumer ic)
150 	{ return consumers.contains(ic); }
151 
152 	/*
153 	 *	Remove consumer.
154 	 */
removeConsumer(ImageConsumer ic)155     public synchronized void removeConsumer(ImageConsumer ic)
156 	{ consumers.removeElement(ic); }
157 
158 	/*
159 	 *	Add a consumer and start scanning.
160 	 */
startProduction(ImageConsumer ic)161     public void startProduction(ImageConsumer ic)
162 	{
163 	System.out.println("In startProduction()");
164 	addConsumer(ic);
165 	scan();
166 	}
167 
168 	/*
169 	 *	Set file to write to.
170 	 */
setOutputFile(OutputStream o)171     public void setOutputFile(OutputStream o)
172 	{ outputFile = o; }
173 
174 	/*
175 	 *	Ignore this:
176 	 */
requestTopDownLeftRightResend(ImageConsumer ic)177     public void requestTopDownLeftRightResend(ImageConsumer ic)
178 	{  }
179 
180 	/*
181 	 *	Go to next line in image, reallocating if necessary.
182 	 */
nextLine()183     private void nextLine()
184 	{
185 	x = 0;
186 	++y;
187 	if (y >= height || image == null)
188 		{			// Got to reallocate.
189 		int oldSize = image == null ? 0 : width*height;
190 		height += STRIP_HEIGHT;	// Add more lines.
191 		int newSize = width*height;
192 		int[] newImage = new int[newSize];
193 		int i;
194 		if (oldSize != 0)	// Copy old data.
195 			for (i = 0; i < oldSize; i++)
196 				newImage[i] = image[i];
197 					// Fill new pixels with 0's, setting
198 					//   alpha channel.
199 		for (i = oldSize; i < newSize; i++)
200 			newImage[i] = (255 << 24);
201 		image = newImage;
202 		System.out.println("nextLine:  newSize="+newSize);
203 					// Tell clients.
204 		tellDimensions(width, height);
205 		}
206 	}
207 
208 	/*
209 	 *	Process a buffer of data.
210 	 */
process(byte[] data, int readLen)211     private boolean process(byte[] data, int readLen)
212 	{
213 	int prevY = y > 0 ? y : 0;	// Save current Y-coord.
214 	int i;
215 	switch (parms.format)
216 		{
217 	case SaneParameters.FRAME_RED:
218 	case SaneParameters.FRAME_GREEN:
219 	case SaneParameters.FRAME_BLUE:
220 		System.out.println("Process RED, GREEN or BLUE");
221 		int cindex = 2 - (parms.format - SaneParameters.FRAME_RED);
222 					// Single frame.
223 		for (i = 0; i < readLen; ++i)
224 			{		// Doing a single color frame.
225 			image[offset + i] |=
226 				(((int) data[i]) & 0xff) << (8*cindex);
227 			++x;
228 			if (x >= width)
229 				nextLine();
230 			}
231 		break;
232 	case SaneParameters.FRAME_RGB:
233 		for (i = 0; i < readLen; ++i)
234 			{
235 			int b = 2 - (offset + i)%3;
236 			image[(offset + i)/3] |=
237 				(((int) data[i]) & 0xff) << (8*b);
238 			if (b == 0)
239 				{
240 				++x;
241 				if (x >= width)
242 					nextLine();
243 				}
244 			}
245 		break;
246 	case SaneParameters.FRAME_GRAY:
247 		System.out.println("Process GREY");
248 					// Single frame.
249 		for (i = 0; i < readLen; ++i)
250 			{
251 			int v = ((int) data[i]) & 0xff;
252 			image[offset + i] |= (v<<16) | (v<<8) | (v);
253 			++x;
254 			if (x >= width)
255 				nextLine();
256 			}
257 		break;
258 		}
259 	offset += readLen;		// Update where we are.
260 					// Show it.
261 	System.out.println("PrevY = " + prevY + ", y = " + y);
262 //	tellPixels(0, prevY, width, y - prevY);
263 	tellPixels(0, 0, width, height);
264 	return true;
265 	}
266 
267 	/*
268 	 *	Start scanning.
269 	 */
scan()270     public void scan()
271 	{
272 	int dataLen = 32*1024;
273 	byte [] data = new byte[dataLen];
274 	int [] readLen = new int[1];
275 	int frameCnt = 0;
276 					// For now, use default RGB model.
277 	cm = ColorModel.getRGBdefault();
278 	int status;
279 	image = null;
280 	do				// Do each frame.
281 		{
282 		frameCnt++;
283 		x = 0;			// Init. position.
284 		y = -1;
285 		offset = 0;
286 		System.out.println("Reading frame #" + frameCnt);
287 		status = sane.start(handle);
288 		if (status != Sane.STATUS_GOOD)
289 			{
290 			System.out.println("start() failed.  Status= "
291 								+ status);
292 			tellStatus(ImageConsumer.IMAGEERROR);
293 			return;
294 			}
295 		status = sane.getParameters(handle, parms);
296 		if (status != Sane.STATUS_GOOD)
297 			{
298 			System.out.println("getParameters() failed.  Status= "
299 								+ status);
300 			tellStatus(ImageConsumer.IMAGEERROR);
301 			return;	//++++cleanup.
302 			}
303 		if (frameCnt == 1)	// First time?
304 			{
305 			width = parms.pixelsPerLine;
306 			if (parms.lines >= 0)
307 				height = parms.lines - STRIP_HEIGHT + 1;
308 			else		// Hand-scanner.
309 				height = 0;
310 			nextLine();	// Allocate image.
311 			}
312 		while ((status = sane.read(handle, data, dataLen, readLen))
313 							== Sane.STATUS_GOOD)
314 			{
315 			System.out.println("Read " + readLen[0] + " bytes.");
316 			if (!process(data, readLen[0]))
317 				{
318 				tellStatus(ImageConsumer.IMAGEERROR);
319 				return;
320 				}
321 			}
322 		if (status != Sane.STATUS_EOF)
323 			{
324 			System.out.println("read() failed.  Status= "
325 								+ status);
326 			tellStatus(ImageConsumer.IMAGEERROR);
327 			return;
328 			}
329 		}
330 	while (!parms.lastFrame);
331 	height = y;			// For now, send whole image here.
332 	tellDimensions(width, height);
333 	tellPixels(0, 0, width, height);
334 	if (outputFile != null)		// Write to file.
335 		{
336 		try
337 			{
338 			write(outputFile);
339 			}
340 		catch (IOException e)
341 			{	//+++++++++++++++
342 			System.out.println("I/O error writing file.");
343 			}
344 		outputFile = null;	// Clear for next time.
345 		}
346 	tellStatus(ImageConsumer.STATICIMAGEDONE);
347 	image = null;			// Allow buffer to be freed.
348 	}
349 
350 	/*
351 	 *	Write ppm/pnm output for last scan to a file.
352 	 */
write(OutputStream out)353     private void write(OutputStream out) throws IOException
354 	{
355 	PrintWriter pout = new PrintWriter(out);
356 	BufferedWriter bout = new BufferedWriter(pout);
357 	int len = width*height;		// Get # of pixels.
358 	int i;
359 	switch (parms.format)
360 		{
361 	case SaneParameters.FRAME_RED:
362 	case SaneParameters.FRAME_GREEN:
363 	case SaneParameters.FRAME_BLUE:
364 	case SaneParameters.FRAME_RGB:
365 		pout.print("P6\n# SANE data follows\n" +
366 			width + ' ' + height + "\n255\n");
367 		for (i = 0; i < len; i++)
368 			{
369 			int pix = image[i];
370 			bout.write((pix >> 16) & 0xff);
371 			bout.write((pix >> 8) & 0xff);
372 			bout.write(pix & 0xff);
373 			}
374 		break;
375 	case SaneParameters.FRAME_GRAY:
376 		pout.print("P5\n# SANE data follows\n" +
377 			width + ' ' + height + "\n255\n");
378 		for (i = 0; i < len; i++)
379 			{
380 			int pix = image[i];
381 			bout.write(pix & 0xff);
382 			}
383 		break;
384 		}
385 
386 	bout.flush();			// Flush output.
387 	pout.flush();
388 	}
389     }
390