| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  | /* sane - Scanner Access Now Easy.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-27 14:41:30 +00:00
										 |  |  |    Copyright (C) 2005, 2006 Pierre Willenbrock <pierre@pirsoft.dnsalias.org> | 
					
						
							| 
									
										
										
										
											2016-02-12 07:11:20 +00:00
										 |  |  |    Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr> | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    This file is part of the SANE package. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    As a special exception, the authors of SANE give permission for | 
					
						
							|  |  |  |    additional uses of the libraries contained in this release of SANE. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    This exception does not, however, invalidate any other reasons why | 
					
						
							|  |  |  |    the executable file might be covered by the GNU General Public | 
					
						
							|  |  |  |    License. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |    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. | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  |    If you do not wish that, delete this exception notice. | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Conversion filters for genesys backend | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:27 +00:00
										 |  |  | static void genesys_reverse_bits(uint8_t* src_data, uint8_t* dst_data, size_t bytes) | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2005-11-19 22:51:01 +00:00
										 |  |  |     size_t i; | 
					
						
							|  |  |  |     for(i = 0; i < bytes; i++) { | 
					
						
							|  |  |  | 	*dst_data++ = ~ *src_data++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * uses the threshold/threshold_curve to control software binarization | 
					
						
							| 
									
										
										
										
											2012-10-24 19:28:42 +00:00
										 |  |  |  * This code was taken from the epjistsu backend by m. allan noah | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  |  * @param dev device set up for the scan | 
					
						
							|  |  |  |  * @param src pointer to raw data | 
					
						
							|  |  |  |  * @param dst pointer where to store result | 
					
						
							|  |  |  |  * @param width width of the processed line | 
					
						
							|  |  |  |  * */ | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  | static void binarize_line(Genesys_Device* dev, uint8_t* src, uint8_t* dst, int width) | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  |   int j, windowX, sum = 0; | 
					
						
							|  |  |  |   int thresh; | 
					
						
							|  |  |  |   int offset, addCol, dropCol; | 
					
						
							|  |  |  |   unsigned char mask; | 
					
						
							| 
									
										
										
										
											2013-12-16 04:45:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-23 16:21:36 +00:00
										 |  |  |   int x; | 
					
						
							| 
									
										
										
										
											2010-01-31 15:47:53 +00:00
										 |  |  |   uint8_t min, max; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* normalize line */ | 
					
						
							|  |  |  |   min = 255; | 
					
						
							|  |  |  |   max = 0; | 
					
						
							|  |  |  |     for (x = 0; x < width; x++) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	if (src[x] > max) | 
					
						
							|  |  |  | 	  { | 
					
						
							|  |  |  | 	    max = src[x]; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	if (src[x] < min) | 
					
						
							|  |  |  | 	  { | 
					
						
							|  |  |  | 	    min = src[x]; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2010-02-08 05:19:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* safeguard against dark or white areas */ | 
					
						
							| 
									
										
										
										
											2010-02-03 05:20:52 +00:00
										 |  |  |     if(min>80) | 
					
						
							|  |  |  | 	    min=0; | 
					
						
							|  |  |  |     if(max<80) | 
					
						
							|  |  |  | 	    max=255; | 
					
						
							| 
									
										
										
										
											2010-01-31 15:47:53 +00:00
										 |  |  |     for (x = 0; x < width; x++) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	src[x] = ((src[x] - min) * 255) / (max - min); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* ~1mm works best, but the window needs to have odd # of pixels */ | 
					
						
							| 
									
										
										
										
											2010-01-31 15:47:53 +00:00
										 |  |  |   windowX = (6 * dev->settings.xres) / 150; | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  |   if (!(windowX % 2)) | 
					
						
							|  |  |  |     windowX++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* second, prefill the sliding sum */ | 
					
						
							|  |  |  |   for (j = 0; j < windowX; j++) | 
					
						
							|  |  |  |     sum += src[j]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* third, walk the input buffer, update the sliding sum, */ | 
					
						
							|  |  |  |   /* determine threshold, output bits */ | 
					
						
							|  |  |  |   for (j = 0; j < width; j++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* output image location */ | 
					
						
							|  |  |  |       offset = j % 8; | 
					
						
							|  |  |  |       mask = 0x80 >> offset; | 
					
						
							|  |  |  |       thresh = dev->settings.threshold; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* move sum/update threshold only if there is a curve */ | 
					
						
							|  |  |  |       if (dev->settings.threshold_curve) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  addCol = j + windowX / 2; | 
					
						
							|  |  |  | 	  dropCol = addCol - windowX; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if (dropCol >= 0 && addCol < width) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      sum -= src[dropCol]; | 
					
						
							|  |  |  | 	      sum += src[addCol]; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	  thresh = dev->lineart_lut[sum / windowX]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* use average to lookup threshold */ | 
					
						
							|  |  |  |       if (src[j] > thresh) | 
					
						
							|  |  |  | 	*dst &= ~mask;		/* white */ | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	*dst |= mask;		/* black */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (offset == 7) | 
					
						
							|  |  |  | 	dst++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * software lineart using data from a 8 bit gray scan. We assume true gray | 
					
						
							|  |  |  |  * or monochrome scan as input. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  | static void genesys_gray_lineart(Genesys_Device* dev, | 
					
						
							|  |  |  |                                  uint8_t* src_data, uint8_t* dst_data, | 
					
						
							|  |  |  |                                  size_t pixels, size_t lines, uint8_t threshold) | 
					
						
							| 
									
										
										
										
											2005-12-05 20:50:57 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2010-01-31 15:47:53 +00:00
										 |  |  |   size_t y; | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 20:48:23 +00:00
										 |  |  |   DBG(DBG_io2, "%s: converting %lu lines of %lu pixels\n", __func__, (unsigned long)lines, | 
					
						
							|  |  |  |       (unsigned long)pixels); | 
					
						
							|  |  |  |   DBG(DBG_io2, "%s: threshold=%d\n", __func__, threshold); | 
					
						
							| 
									
										
										
										
											2010-01-20 20:48:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-31 15:47:53 +00:00
										 |  |  |   for (y = 0; y < lines; y++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       binarize_line (dev, src_data + y * pixels, dst_data, pixels); | 
					
						
							|  |  |  |       dst_data += pixels / 8; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-05 20:50:57 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-09 04:20:44 +00:00
										 |  |  | /** Look in image for likely left/right/bottom paper edges, then crop image.
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  | static void genesys_crop(Genesys_Scanner* s) | 
					
						
							| 
									
										
										
										
											2010-09-09 04:20:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2010-09-09 04:20:44 +00:00
										 |  |  |   Genesys_Device *dev = s->dev; | 
					
						
							|  |  |  |   int top = 0; | 
					
						
							|  |  |  |   int bottom = 0; | 
					
						
							|  |  |  |   int left = 0; | 
					
						
							|  |  |  |   int right = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     // first find edges if any
 | 
					
						
							|  |  |  |     TIE(sanei_magic_findEdges(&s->params, dev->img_buffer.data(), | 
					
						
							|  |  |  |                               dev->settings.xres, dev->settings.yres, | 
					
						
							|  |  |  |                               &top, &bottom, &left, &right)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-05 09:48:59 +00:00
										 |  |  |   DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left, | 
					
						
							| 
									
										
										
										
											2010-09-09 04:20:44 +00:00
										 |  |  |        right); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     // now crop the image
 | 
					
						
							|  |  |  |     TIE(sanei_magic_crop (&(s->params), dev->img_buffer.data(), top, bottom, left, right)); | 
					
						
							| 
									
										
										
										
											2010-09-09 04:20:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* update counters to new image size */ | 
					
						
							|  |  |  |   dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | /** Look in image for likely upper and left paper edges, then rotate
 | 
					
						
							|  |  |  |  * image so that upper left corner of paper is upper left of image. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  | static void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor) | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  |   Genesys_Device *dev = s->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int x = 0, y = 0, bg; | 
					
						
							|  |  |  |   double slope = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bg=0; | 
					
						
							|  |  |  |   if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       bg=0xff; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     TIE(sanei_magic_findSkew(&s->params, dev->img_buffer.data(), | 
					
						
							|  |  |  |                              sensor.optical_res, sensor.optical_res, | 
					
						
							|  |  |  |                              &x, &y, &slope)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-05 09:48:59 +00:00
										 |  |  |   DBG(DBG_info, "%s: slope=%f => %f\n",__func__,slope, (slope/M_PI_2)*90); | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     // rotate image slope is in [-PI/2,PI/2]. Positive values rotate trigonometric direction wise
 | 
					
						
							|  |  |  |     TIE(sanei_magic_rotate(&s->params, dev->img_buffer.data(), | 
					
						
							|  |  |  |                            x, y, slope, bg)); | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** remove lone dots
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  | static void genesys_despeck(Genesys_Scanner* s) | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     TIE(sanei_magic_despeck(&s->params, s->dev->img_buffer.data(), s->despeck)); | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-05 19:08:37 +00:00
										 |  |  | /** Look if image needs rotation and apply it
 | 
					
						
							|  |  |  |  * */ | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  | static void genesys_derotate (Genesys_Scanner * s) | 
					
						
							| 
									
										
										
										
											2011-06-05 19:08:37 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-14 20:40:43 +00:00
										 |  |  |     DBG_HELPER(dbg); | 
					
						
							| 
									
										
										
										
											2011-06-05 19:08:37 +00:00
										 |  |  |   int angle = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     TIE(sanei_magic_findTurn(&s->params, s->dev->img_buffer.data(), | 
					
						
							|  |  |  |                              s->resolution, s->resolution, &angle)); | 
					
						
							| 
									
										
										
										
											2010-09-12 19:24:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     // apply rotation angle found
 | 
					
						
							|  |  |  |     TIE(sanei_magic_turn(&s->params, s->dev->img_buffer.data(), angle)); | 
					
						
							| 
									
										
										
										
											2011-06-05 19:08:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 07:12:32 +00:00
										 |  |  |     // update counters to new image size
 | 
					
						
							|  |  |  |     s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; | 
					
						
							| 
									
										
										
										
											2011-06-05 19:08:37 +00:00
										 |  |  | } |