kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			2686 wiersze
		
	
	
		
			67 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			2686 wiersze
		
	
	
		
			67 KiB
		
	
	
	
		
			C
		
	
	
| /* sane - Scanner Access Now Easy.
 | |
| 
 | |
|    Copyright (C) 2000-2005 Mustek.
 | |
|    Originally maintained by Mustek
 | |
| 
 | |
|    Copyright (C) 2001-2005 by Henning Meier-Geinitz.
 | |
| 
 | |
|    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.
 | |
| 
 | |
|    This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro
 | |
|    and similar USB2 scanners. */
 | |
| 
 | |
| #define BUILD 10
 | |
| 
 | |
| #include "../include/sane/config.h"
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <limits.h>
 | |
| #include <signal.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| #include <math.h>
 | |
| 
 | |
| #include <sys/time.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/wait.h>
 | |
| 
 | |
| #include "../include/sane/sane.h"
 | |
| #include "../include/sane/sanei.h"
 | |
| #include "../include/sane/saneopts.h"
 | |
| 
 | |
| #define BACKEND_NAME mustek_usb2
 | |
| 
 | |
| #include "../include/sane/sanei_backend.h"
 | |
| #include "mustek_usb2_high.c"
 | |
| 
 | |
| #include "mustek_usb2.h"
 | |
| 
 | |
| static SANE_Int num_devices;
 | |
| static const SANE_Device **devlist = 0;
 | |
| 
 | |
| static const SANE_Range u8_range = {
 | |
|   0,				/* minimum */
 | |
|   255,				/* maximum */
 | |
|   0				/* quantization */
 | |
| };
 | |
| static SANE_Range x_range = {
 | |
|   SANE_FIX (0.0),		/* minimum */
 | |
|   SANE_FIX (8.3 * MM_PER_INCH),	/* maximum */
 | |
|   SANE_FIX (0.0)		/* quantization */
 | |
| };
 | |
| 
 | |
| static SANE_Range y_range = {
 | |
|   SANE_FIX (0.0),		/* minimum */
 | |
|   SANE_FIX (11.6 * MM_PER_INCH),	/* maximum */
 | |
|   SANE_FIX (0.0)		/* quantization */
 | |
| };
 | |
| 
 | |
| static SANE_Range gamma_range = {
 | |
|   SANE_FIX (0.01),		/* minimum */
 | |
|   SANE_FIX (5.0),		/* maximum */
 | |
|   SANE_FIX (0.01)		/* quantization */
 | |
| };
 | |
| static SANE_String_Const mode_list[] = {
 | |
|   SANE_I18N ("Color48"),
 | |
|   SANE_I18N ("Color24"),
 | |
|   SANE_I18N ("Gray16"),
 | |
|   SANE_I18N ("Gray8"),
 | |
|   SANE_VALUE_SCAN_MODE_LINEART,
 | |
|   0
 | |
| };
 | |
| 
 | |
| static SANE_String_Const negative_mode_list[] = {
 | |
|   SANE_I18N ("Color24"),
 | |
|   0
 | |
| };
 | |
| 
 | |
| static SANE_String_Const source_list[] = {
 | |
|   SANE_I18N ("Reflective"),
 | |
|   SANE_I18N ("Positive"),
 | |
|   SANE_I18N ("Negative"),
 | |
|   0
 | |
| };
 | |
| static Scanner_Model mustek_A2nu2_model = {
 | |
|   "mustek-A2nu2",		/* Name */
 | |
|   "Mustek",			/* Device vendor string */
 | |
| 
 | |
|   "BearPaw 2448TA Pro",		/* Device model name */
 | |
|   "",				/* Name of the firmware file */
 | |
| 
 | |
|   {1200, 600, 300, 150, 75, 0},	/* possible resolutions */
 | |
| 
 | |
|   SANE_FIX (0.0),		/* Start of scan area in mm  (x) */
 | |
|   SANE_FIX (0.0),		/* Start of scan area in mm (y) */
 | |
|   SANE_FIX (8.3 * MM_PER_INCH),	/* Size of scan area in mm (x) */
 | |
|   SANE_FIX (11.6 * MM_PER_INCH),	/* Size of scan area in mm (y) */
 | |
| 
 | |
|   SANE_FIX (0.0),		/* Start of scan area in TA mode in mm (x) */
 | |
|   SANE_FIX (0.0),		/* Start of scan area in TA mode in mm (y) */
 | |
|   SANE_FIX (1.46 * MM_PER_INCH),	/* Size of scan area in TA mode in mm (x) */
 | |
|   SANE_FIX (6.45 * MM_PER_INCH),	/* Size of scan area in TA mode in mm (y) */
 | |
| 
 | |
|   0,				/* Order of the CCD/CIS colors 0:RO_RGB 1:RO_BGR */
 | |
|   SANE_FIX (2.0),		/* Default gamma value */
 | |
| 
 | |
|   SANE_FALSE,			/* Is this a CIS scanner? */
 | |
|   0				/* Which flags are needed for this scanner? */
 | |
|     /* Setup and tested */
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Forward declarations */
 | |
| 
 | |
| static SANE_Bool GetDeviceStatus (void);
 | |
| static SANE_Bool PowerControl (SANE_Bool isLampOn, SANE_Bool isTaLampOn);
 | |
| static SANE_Bool CarriageHome (void);
 | |
| static SANE_Bool SetParameters (LPSETPARAMETERS pSetParameters);
 | |
| static SANE_Bool GetParameters (LPGETPARAMETERS pGetParameters);
 | |
| static SANE_Bool StartScan (void);
 | |
| static SANE_Bool ReadScannedData (LPIMAGEROWS pImageRows);
 | |
| static SANE_Bool StopScan (void);
 | |
| static SANE_Bool IsTAConnected (void);
 | |
| static void AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines,
 | |
| 		unsigned int BytesPerLine);
 | |
| static size_t max_string_size (const SANE_String_Const strings[]);
 | |
| static SANE_Status calc_parameters (Mustek_Scanner * s);
 | |
| #ifdef SANE_UNUSED
 | |
| static SANE_Bool GetGammaInfo (LPGAMMAINFO pGamaInfo);
 | |
| static SANE_Bool GetKeyStatus (SANE_Byte * pKey);
 | |
| static void QBetChange (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines,
 | |
| 		 unsigned int BytesPerLine);
 | |
| static void QBETDetectAutoLevel (void *pDIB, unsigned int ImageWidth, unsigned int ImageHeight);
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| static size_t
 | |
| max_string_size (const SANE_String_Const strings[])
 | |
| {
 | |
|   size_t size, max_size = 0;
 | |
|   SANE_Int i;
 | |
| 
 | |
|   for (i = 0; strings[i]; ++i)
 | |
|     {
 | |
|       size = strlen (strings[i]) + 1;
 | |
|       if (size > max_size)
 | |
| 	max_size = size;
 | |
|     }
 | |
|   return max_size;
 | |
| }
 | |
| 
 | |
| static SANE_Status
 | |
| calc_parameters (Mustek_Scanner * s)
 | |
| {
 | |
|   SANE_String val, val_source;
 | |
|   val = s->val[OPT_MODE].s;
 | |
|   val_source = s->val[OPT_SOURCE].s;
 | |
| 
 | |
|   s->params.last_frame = SANE_TRUE;
 | |
| 
 | |
|   if (strcmp (val, "Color48") == 0)	/* Color48 */
 | |
|     {
 | |
|       s->params.format = SANE_FRAME_RGB;
 | |
|       s->params.depth = 16;
 | |
|       s->setpara.smScanMode = SM_RGB48;
 | |
|       if (s->val[OPT_PREVIEW].w)
 | |
| 	{
 | |
| 	  DBG (DBG_DET, "calc_parameters : preview set ScanMode SM_RGB24\n");
 | |
| 	  s->params.depth = 8;
 | |
| 	  s->setpara.smScanMode = SM_RGB24;
 | |
| 	}
 | |
|     }
 | |
|   else if (strcmp (val, "Color24") == 0)	/* Color24 */
 | |
|     {
 | |
|       s->params.format = SANE_FRAME_RGB;
 | |
|       s->params.depth = 8;
 | |
|       s->setpara.smScanMode = SM_RGB24;
 | |
|     }
 | |
|   else if (strcmp (val, "Gray16") == 0)
 | |
|     {
 | |
|       s->params.format = SANE_FRAME_GRAY;
 | |
|       s->params.depth = 16;
 | |
|       s->setpara.smScanMode = SM_GRAY16;
 | |
|       if (s->val[OPT_PREVIEW].w)
 | |
| 	{
 | |
| 	  s->params.depth = 8;
 | |
| 	  DBG (DBG_DET, "calc_parameters : preview set ScanMode SM_GRAY\n");
 | |
| 	  s->setpara.smScanMode = SM_GRAY;
 | |
| 	}
 | |
|     }
 | |
|   else if (strcmp (val, "Gray8") == 0)
 | |
|     {
 | |
|       s->params.format = SANE_FRAME_GRAY;
 | |
|       s->params.depth = 8;
 | |
|       s->setpara.smScanMode = SM_GRAY;
 | |
|     }
 | |
|   else if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0)
 | |
|     {
 | |
|       s->params.format = SANE_FRAME_GRAY;
 | |
|       s->params.depth = 1;
 | |
|       s->setpara.smScanMode = SM_TEXT;
 | |
|     }
 | |
| 
 | |
|   /*set Scan Source */
 | |
|   DBG (DBG_DET, "calc_parameters :scan Source = %s\n", val_source);
 | |
|   if (strcmp (val_source, "Reflective") == 0)
 | |
|     {
 | |
|       s->setpara.ssScanSource = SS_Reflective;
 | |
|     }
 | |
|   else if (strcmp (val_source, "Positive") == 0)
 | |
|     {
 | |
|       s->setpara.ssScanSource = SS_Positive;
 | |
|     }
 | |
|   else if (strcmp (val_source, "Negative") == 0)
 | |
|     {
 | |
|       s->setpara.ssScanSource = SS_Negative;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   s->setpara.fmArea.x1 =
 | |
|     (unsigned short) ((SANE_UNFIX (s->val[OPT_TL_X].w) * 300.0) / MM_PER_INCH + 0.5);
 | |
|   s->setpara.fmArea.x2 =
 | |
|     (unsigned short) ((SANE_UNFIX (s->val[OPT_BR_X].w) * 300.0) / MM_PER_INCH + 0.5);
 | |
|   s->setpara.fmArea.y1 =
 | |
|     (unsigned short) ((SANE_UNFIX (s->val[OPT_TL_Y].w) * 300.0) / MM_PER_INCH + 0.5);
 | |
|   s->setpara.fmArea.y2 =
 | |
|     (unsigned short) ((SANE_UNFIX (s->val[OPT_BR_Y].w) * 300.0) / MM_PER_INCH + 0.5);
 | |
| 
 | |
|   if (s->val[OPT_PREVIEW].w)
 | |
|     {
 | |
|       s->setpara.fmArea.y1 = s->setpara.fmArea.y1 + PER_ADD_START_LINES;
 | |
|       s->setpara.fmArea.x1 += PRE_ADD_START_X;
 | |
|     }				/*just for range bug. */
 | |
| 
 | |
|   s->setpara.pfPixelFlavor = PF_BlackIs0;
 | |
|   s->setpara.wLinearThreshold = s->val[OPT_THRESHOLD].w;
 | |
| 
 | |
|   s->setpara.wTargetDPI = s->val[OPT_RESOLUTION].w;
 | |
|   if (s->val[OPT_PREVIEW].w)
 | |
|     {
 | |
|       s->setpara.wTargetDPI = 75;
 | |
|     }
 | |
| 
 | |
|   s->setpara.pGammaTable = NULL;
 | |
| 
 | |
|   s->params.pixels_per_line =
 | |
|     (SANE_Int) ((s->setpara.fmArea.x2 -
 | |
| 		 s->setpara.fmArea.x1) * s->setpara.wTargetDPI / 300.0 + 0.5);
 | |
| 
 | |
|   switch (s->params.format)
 | |
|     {
 | |
|     case SANE_FRAME_RGB:
 | |
|       if (s->params.depth == 8)
 | |
| 	s->params.bytes_per_line = s->params.pixels_per_line * 3;
 | |
|       if (s->params.depth == 16)
 | |
| 	s->params.bytes_per_line = s->params.pixels_per_line * 6;
 | |
|       break;
 | |
|     case SANE_FRAME_GRAY:
 | |
|       if (s->params.depth == 1)
 | |
| 	s->params.bytes_per_line = s->params.pixels_per_line / 8;
 | |
|       if (s->params.depth == 8)
 | |
| 	s->params.bytes_per_line = s->params.pixels_per_line;
 | |
|       if (s->params.depth == 16)
 | |
| 	s->params.bytes_per_line = s->params.pixels_per_line * 2;
 | |
|       break;
 | |
|     default:
 | |
|       DBG (DBG_DET, "sane_star:sane params .format = %d\n", s->params.format);
 | |
|     }
 | |
| 
 | |
|   s->params.lines =
 | |
|     (SANE_Int) ((s->setpara.fmArea.y2 -
 | |
| 		 s->setpara.fmArea.y1) * s->setpara.wTargetDPI / 300 + 0.5);
 | |
| 
 | |
|   DBG (DBG_FUNC, "calc_parameters: end\n");
 | |
| 
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| static SANE_Status
 | |
| init_options (Mustek_Scanner * s)
 | |
| {
 | |
|   SANE_Int option, count;
 | |
|   SANE_Word *dpi_list;		/*Resolution Support */
 | |
| 
 | |
|   DBG (DBG_FUNC, "init_options: start\n");
 | |
| 
 | |
|   memset (s->opt, 0, sizeof (s->opt));
 | |
|   memset (s->val, 0, sizeof (s->val));
 | |
| 
 | |
|   for (option = 0; option < NUM_OPTIONS; ++option)
 | |
|     {
 | |
|       s->opt[option].size = sizeof (SANE_Word);
 | |
|       s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 | |
|     }
 | |
|   /*  Option num */
 | |
|   s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
 | |
|   s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
 | |
|   s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
 | |
|   s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
 | |
|   s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
 | |
| 
 | |
|   /* "Mode" group: */
 | |
|   s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
 | |
|   s->opt[OPT_MODE_GROUP].desc = "";
 | |
|   s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_MODE_GROUP].size = 0;
 | |
|   s->opt[OPT_MODE_GROUP].cap = 0;
 | |
|   s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* scan mode */
 | |
|   s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
 | |
|   s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
 | |
|   s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
 | |
|   s->opt[OPT_MODE].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_MODE].size = max_string_size (mode_list);
 | |
|   s->opt[OPT_MODE].constraint.string_list = mode_list;
 | |
|   s->val[OPT_MODE].s = strdup ("Color24");
 | |
| 
 | |
|   /* Scan Source */
 | |
|   s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
 | |
|   s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
 | |
|   s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
 | |
|   s->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
 | |
|   s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 | |
|   s->opt[OPT_SOURCE].size = max_string_size (source_list);
 | |
|   s->opt[OPT_SOURCE].constraint.string_list = source_list;
 | |
|   s->val[OPT_SOURCE].s = strdup ("Reflective");
 | |
| 
 | |
|   if (!IsTAConnected ())
 | |
|     {
 | |
|       DISABLE (OPT_SOURCE);
 | |
|     }
 | |
| 
 | |
| 
 | |
|   /* resolution */
 | |
| 
 | |
|   for (count = 0; s->model.dpi_values[count] != 0; count++)
 | |
|     {
 | |
|     }
 | |
|   dpi_list = malloc ((count + 1) * sizeof (SANE_Word));
 | |
|   if (!dpi_list)
 | |
|     return SANE_STATUS_NO_MEM;
 | |
|   dpi_list[0] = count;
 | |
| 
 | |
|   for (count = 0; s->model.dpi_values[count] != 0; count++)
 | |
|     dpi_list[count + 1] = s->model.dpi_values[count];
 | |
| 
 | |
|   s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
 | |
|   s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
 | |
| 
 | |
| 
 | |
|   s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
 | |
|   s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
 | |
|   s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 | |
|   s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list;
 | |
|   s->val[OPT_RESOLUTION].w = 300;
 | |
| 
 | |
|   /* preview */
 | |
|   s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
 | |
|   s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
 | |
|   s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
 | |
|   s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
 | |
|   s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
 | |
|   s->val[OPT_PREVIEW].w = SANE_FALSE;
 | |
| 
 | |
|   /* "Debug" group: */
 | |
|   s->opt[OPT_DEBUG_GROUP].title = SANE_I18N ("Debugging Options");
 | |
|   s->opt[OPT_DEBUG_GROUP].desc = "";
 | |
|   s->opt[OPT_DEBUG_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_DEBUG_GROUP].size = 0;
 | |
|   s->opt[OPT_DEBUG_GROUP].cap = 0;
 | |
|   s->opt[OPT_DEBUG_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* auto warmup */
 | |
|   s->opt[OPT_AUTO_WARMUP].name = "auto-warmup";
 | |
|   s->opt[OPT_AUTO_WARMUP].title = SANE_I18N ("Automatic warmup");
 | |
|   s->opt[OPT_AUTO_WARMUP].desc =
 | |
|     SANE_I18N ("Warm-up until the lamp's brightness is constant "
 | |
| 	       "instead of insisting on 40 seconds warm-up time.");
 | |
|   s->opt[OPT_AUTO_WARMUP].type = SANE_TYPE_BOOL;
 | |
|   s->opt[OPT_AUTO_WARMUP].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_AUTO_WARMUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
|   s->val[OPT_AUTO_WARMUP].w = SANE_FALSE;
 | |
|   if (s->model.is_cis)
 | |
|     DISABLE (OPT_AUTO_WARMUP);
 | |
| 
 | |
|   /* "Enhancement" group: */
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
 | |
| 
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].size = 0;
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
 | |
|   s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   /* threshold */
 | |
|   s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
 | |
|   s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
 | |
|   s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
 | |
|   s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
 | |
|   s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_THRESHOLD].constraint.range = &u8_range;
 | |
|   s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
 | |
|   s->val[OPT_THRESHOLD].w = DEF_LINEARTTHRESHOLD;
 | |
| 
 | |
|   /* internal gamma value */
 | |
|   s->opt[OPT_GAMMA_VALUE].name = "gamma-value";
 | |
|   s->opt[OPT_GAMMA_VALUE].title = SANE_I18N ("Gamma value");
 | |
|   s->opt[OPT_GAMMA_VALUE].desc =
 | |
|     SANE_I18N ("Sets the gamma value of all channels.");
 | |
|   s->opt[OPT_GAMMA_VALUE].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_GAMMA_VALUE].unit = SANE_UNIT_NONE;
 | |
|   s->opt[OPT_GAMMA_VALUE].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_GAMMA_VALUE].constraint.range = &gamma_range;
 | |
|   s->opt[OPT_GAMMA_VALUE].cap |= SANE_CAP_EMULATED;
 | |
|   s->val[OPT_GAMMA_VALUE].w = s->model.default_gamma_value;
 | |
| 
 | |
|   DISABLE (OPT_GAMMA_VALUE);
 | |
| 
 | |
|   /* "Geometry" group: */
 | |
|   s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
 | |
|   s->opt[OPT_GEOMETRY_GROUP].desc = "";
 | |
|   s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
 | |
|   s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
 | |
|   s->opt[OPT_GEOMETRY_GROUP].size = 0;
 | |
|   s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
 | |
| 
 | |
|   x_range.max = s->model.x_size;
 | |
|   y_range.max = s->model.y_size;
 | |
| 
 | |
|   /* top-left x */
 | |
|   s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
 | |
|   s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
 | |
|   s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
 | |
|   s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_TL_X].constraint.range = &x_range;
 | |
| 
 | |
|   s->val[OPT_TL_X].w = 0;
 | |
| 
 | |
|   /* top-left y */
 | |
|   s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
 | |
|   s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
 | |
|   s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
 | |
|   s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_TL_Y].constraint.range = &y_range;
 | |
|   s->val[OPT_TL_Y].w = 0;
 | |
| 
 | |
|   /* bottom-right x */
 | |
|   s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
 | |
|   s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
 | |
|   s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
 | |
|   s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_BR_X].constraint.range = &x_range;
 | |
|   s->val[OPT_BR_X].w = x_range.max;
 | |
| 
 | |
|   /* bottom-right y */
 | |
|   s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
 | |
|   s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
 | |
|   s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
 | |
|   s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
 | |
|   s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
 | |
|   s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 | |
|   s->opt[OPT_BR_Y].constraint.range = &y_range;
 | |
|   s->val[OPT_BR_Y].w = y_range.max;
 | |
| 
 | |
|   calc_parameters (s);
 | |
| 
 | |
|   DBG (DBG_FUNC, "init_options: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /***************************** Code from spicall.c *****************************/
 | |
| 
 | |
| static SANE_Byte * g_lpNegImageData = NULL;
 | |
| static SANE_Bool g_bIsFirstGetNegData = TRUE;
 | |
| static SANE_Bool g_bIsMallocNegData = FALSE;
 | |
| static unsigned int g_dwAlreadyGetNegLines = 0;
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| Routine Description:
 | |
| 	Check the device connect status
 | |
| Parameters:
 | |
| 	none
 | |
| Return value:
 | |
| 	if the device is connected
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| GetDeviceStatus ()
 | |
| {
 | |
|   DBG (DBG_FUNC, "GetDeviceStatus: start\n");
 | |
|   return MustScanner_GetScannerState ();
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| Routine Description:
 | |
| 	Turn the lamp on or off
 | |
| Parameters:
 | |
| 	isLampOn: turn the lamp on or off
 | |
| 	isTALampOn: turn the TA lamp on or off
 | |
| Return value:
 | |
| 	if operation success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| PowerControl (SANE_Bool isLampOn, SANE_Bool isTALampOn)
 | |
| {
 | |
|   DBG (DBG_FUNC, "PowerControl: start\n");
 | |
|   return MustScanner_PowerControl (isLampOn, isTALampOn);
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| Routine Description:
 | |
| 	Turn the carriage home
 | |
| Parameters:
 | |
| 	none
 | |
| Return value:
 | |
| 	if the operation success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| CarriageHome ()
 | |
| {
 | |
|   DBG (DBG_FUNC, "CarriageHome: start\n");
 | |
|   return MustScanner_BackHome ();
 | |
| }
 | |
| 
 | |
| #ifdef SANE_UNUSED
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| Routine Description:
 | |
| 	Get gamma input/output bit count
 | |
| Parameters:
 | |
| 	pGammaInfo: the gamma information
 | |
| Return value:
 | |
| 	if the operation success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| GetGammaInfo (LPGAMMAINFO pGammaInfo)
 | |
| {
 | |
|   DBG (DBG_FUNC, "GetGammaInfo: start\n");
 | |
| 
 | |
|   switch (pGammaInfo->smScanMode)
 | |
|     {
 | |
|     case SM_GRAY:
 | |
|       pGammaInfo->wInputGammaBits = 12;
 | |
|       pGammaInfo->wOutputGammaBits = 8;
 | |
|       break;
 | |
|     case SM_RGB24:
 | |
|       pGammaInfo->wInputGammaBits = 12;
 | |
|       pGammaInfo->wOutputGammaBits = 8;
 | |
|       break;
 | |
|     case SM_GRAY16:
 | |
|       pGammaInfo->wInputGammaBits = 16;
 | |
|       pGammaInfo->wOutputGammaBits = 16;
 | |
|       break;
 | |
|     case SM_RGB48:
 | |
|       pGammaInfo->wInputGammaBits = 16;
 | |
|       pGammaInfo->wOutputGammaBits = 16;
 | |
|       break;
 | |
|     default:
 | |
|       pGammaInfo->wInputGammaBits = 0;
 | |
|       pGammaInfo->wOutputGammaBits = 0;
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_FUNC, "GetGammaInfo: exit\n");
 | |
|   return TRUE;
 | |
| }
 | |
| #endif
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| Routine Description:
 | |
| 	set scan parameters
 | |
| Parameters:
 | |
| 	pSetParameters: the information of scaning
 | |
| Return value:
 | |
| 	if the operation success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| SetParameters (LPSETPARAMETERS pSetParameters)
 | |
| {
 | |
|   unsigned short X1inTargetDpi;
 | |
|   unsigned short Y1inTargetDpi;
 | |
|   unsigned short X2inTargetDpi;
 | |
|   unsigned short Y2inTargetDpi;
 | |
| 
 | |
|   DBG (DBG_FUNC, "SetParameters: start\n");
 | |
| 
 | |
|   /*0. Reset */
 | |
|   if (ST_Reflective == g_ScanType)
 | |
|     {
 | |
|       Reflective_Reset ();
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       Transparent_Reset ();
 | |
|     }
 | |
| 
 | |
|   /*1. Scan mode */
 | |
|   switch (pSetParameters->smScanMode)
 | |
|     {
 | |
|     case SM_TEXT:
 | |
|       g_tiTarget.cmColorMode = CM_TEXT;
 | |
|       break;
 | |
|     case SM_GRAY:
 | |
|       g_tiTarget.cmColorMode = CM_GRAY8;
 | |
|       break;
 | |
|     case SM_GRAY16:
 | |
|       g_tiTarget.cmColorMode = CM_GRAY16;
 | |
|       break;
 | |
|     case SM_RGB24:
 | |
|       g_tiTarget.cmColorMode = CM_RGB24;
 | |
|       break;
 | |
|     case SM_RGB48:
 | |
|       g_tiTarget.cmColorMode = CM_RGB48;
 | |
|       break;
 | |
|     default:
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   /*2. Scan source */
 | |
|   g_ssScanSource = pSetParameters->ssScanSource;
 | |
|   g_tiTarget.bScanSource = pSetParameters->ssScanSource;
 | |
| 
 | |
| 
 | |
|   if (SS_Reflective == pSetParameters->ssScanSource)
 | |
|     {
 | |
|       g_ScanType = ST_Reflective;
 | |
|     }
 | |
|   else if (SS_Positive == pSetParameters->ssScanSource
 | |
| 	   || SS_Negative == pSetParameters->ssScanSource
 | |
| 	   || SS_ADF == pSetParameters->ssScanSource)
 | |
|     {
 | |
|       g_ScanType = ST_Transparent;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: ScanSource error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   /*3. pixel flavor */
 | |
|   if (PF_BlackIs0 == pSetParameters->pfPixelFlavor
 | |
|       || PF_WhiteIs0 == pSetParameters->pfPixelFlavor)
 | |
|     {
 | |
|       g_PixelFlavor = pSetParameters->pfPixelFlavor;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: PixelFlavor error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   /*4. Scan area */
 | |
|   if (pSetParameters->fmArea.x1 >= pSetParameters->fmArea.x2)
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: x1 > x2, error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
|   if (pSetParameters->fmArea.y1 >= pSetParameters->fmArea.y2)
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: y1 >= y2, error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
|   if (pSetParameters->fmArea.x2 > MAX_SCANNING_WIDTH)	/* Just for A4 size */
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: x2 > MAX_SCANNING_WIDTH, error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
|   if (pSetParameters->fmArea.y2 > MAX_SCANNING_HEIGHT)	/* Just for A4 size */
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: y2 > MAX_SCANNING_HEIGHT, error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   X1inTargetDpi =
 | |
|     (unsigned short) ((unsigned int) (pSetParameters->fmArea.x1) *
 | |
| 	    (unsigned int) (pSetParameters->wTargetDPI) / 300L);
 | |
|   Y1inTargetDpi =
 | |
|     (unsigned short) ((unsigned int) (pSetParameters->fmArea.y1) *
 | |
| 	    (unsigned int) (pSetParameters->wTargetDPI) / 300L);
 | |
|   X2inTargetDpi =
 | |
|     (unsigned short) ((unsigned int) (pSetParameters->fmArea.x2) *
 | |
| 	    (unsigned int) (pSetParameters->wTargetDPI) / 300L);
 | |
|   Y2inTargetDpi =
 | |
|     (unsigned short) ((unsigned int) (pSetParameters->fmArea.y2) *
 | |
| 	    (unsigned int) (pSetParameters->wTargetDPI) / 300L);
 | |
| 
 | |
|   g_tiTarget.isOptimalSpeed = TRUE;
 | |
|   g_tiTarget.wDpi = pSetParameters->wTargetDPI;
 | |
|   g_tiTarget.wX = X1inTargetDpi;
 | |
|   g_tiTarget.wY = Y1inTargetDpi;
 | |
|   g_tiTarget.wWidth = X2inTargetDpi - X1inTargetDpi;
 | |
|   g_tiTarget.wHeight = Y2inTargetDpi - Y1inTargetDpi;
 | |
| 
 | |
|   DBG (DBG_INFO, "SetParameters: g_tiTarget.wDpi=%d\n", g_tiTarget.wDpi);
 | |
|   DBG (DBG_INFO, "SetParameters: g_tiTarget.wX=%d\n", g_tiTarget.wX);
 | |
|   DBG (DBG_INFO, "SetParameters: g_tiTarget.wY=%d\n", g_tiTarget.wY);
 | |
|   DBG (DBG_INFO, "SetParameters: g_tiTarget.wWidth=%d\n", g_tiTarget.wWidth);
 | |
|   DBG (DBG_INFO, "SetParameters: g_tiTarget.wHeight=%d\n",
 | |
|        g_tiTarget.wHeight);
 | |
| 
 | |
|   /*5.Prepare */
 | |
|   if (FALSE == MustScanner_Prepare (g_tiTarget.bScanSource))
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: MustScanner_Prepare fail\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   /*6. Linear threshold */
 | |
|   if (pSetParameters->wLinearThreshold > 256
 | |
|       && pSetParameters->smScanMode == SM_TEXT)
 | |
|     {
 | |
|       DBG (DBG_ERR, "SetParameters: LinearThreshold error\n");
 | |
|       return FALSE;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_wLineartThreshold = pSetParameters->wLinearThreshold;
 | |
|     }
 | |
| 
 | |
|   /*7. Gamma table */
 | |
|   if (NULL != pSetParameters->pGammaTable)
 | |
|     {
 | |
|       DBG (DBG_INFO, "SetParameters: IN gamma table not NULL\n");
 | |
|       g_pGammaTable = pSetParameters->pGammaTable;
 | |
|       g_isSelfGamma = FALSE;
 | |
|     }
 | |
|   else if (pSetParameters->smScanMode == SM_GRAY
 | |
| 	   || pSetParameters->smScanMode == SM_RGB24)
 | |
|     {
 | |
|       unsigned short i;
 | |
|       SANE_Byte byGammaData;
 | |
|       double pow_d;
 | |
|       double pow_z = (double) 10 / 16.0;
 | |
| 
 | |
|       g_pGammaTable = (unsigned short *) malloc (sizeof (unsigned short) * 4096 * 3);
 | |
| 
 | |
|       DBG (DBG_INFO, "SetParameters: gamma table malloc %ld Bytes\n",
 | |
| 	   (long int) sizeof (unsigned short) * 4096 * 3);
 | |
|       DBG (DBG_INFO, "SetParameters: address of g_pGammaTable=%p\n",
 | |
| 	   (void *) g_pGammaTable);
 | |
| 
 | |
|       if (NULL == g_pGammaTable)
 | |
| 	{
 | |
| 	  DBG (DBG_ERR, "SetParameters: gamma table malloc fail\n");
 | |
| 	  return FALSE;
 | |
| 	}
 | |
|       g_isSelfGamma = TRUE;
 | |
| 
 | |
|       for (i = 0; i < 4096; i++)
 | |
| 	{
 | |
| 	  pow_d = (double) i / (double) 4096;
 | |
| 
 | |
| 	  byGammaData = (SANE_Byte) (pow (pow_d, pow_z) * 255);
 | |
| 
 | |
| 	  *(g_pGammaTable + i) = byGammaData;
 | |
| 	  *(g_pGammaTable + i + 4096) = byGammaData;
 | |
| 	  *(g_pGammaTable + i + 8192) = byGammaData;
 | |
| 	}
 | |
|     }
 | |
|   else if (pSetParameters->smScanMode == SM_GRAY16
 | |
| 	   || pSetParameters->smScanMode == SM_RGB48)
 | |
|     {
 | |
|       unsigned int i, wGammaData;
 | |
|       g_pGammaTable = (unsigned short *) malloc (sizeof (unsigned short) * 65536 * 3);
 | |
| 
 | |
|       if (g_pGammaTable == NULL)
 | |
| 	{
 | |
| 	  DBG (DBG_ERR, "SetParameters: gamma table malloc fail\n");
 | |
| 	  return FALSE;
 | |
| 	}
 | |
|       g_isSelfGamma = TRUE;
 | |
| 
 | |
|       for (i = 0; i < 65536; i++)
 | |
| 	{
 | |
| 	  wGammaData =
 | |
| 	    (unsigned short) (pow ((((float) i) / 65536.0), (((float) 10) / 16.0)) *
 | |
| 		    65535);
 | |
| 
 | |
| 	  *(g_pGammaTable + i) = wGammaData;
 | |
| 	  *(g_pGammaTable + i + 65536) = wGammaData;
 | |
| 	  *(g_pGammaTable + i + 65536 * 2) = wGammaData;
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       DBG (DBG_INFO, "SetParameters: set g_pGammaTable to NULL\n");
 | |
|       g_pGammaTable = NULL;
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_FUNC, "SetParameters: exit\n");
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| Routine Description:
 | |
| 	get the optical dpi and scan area
 | |
| Parameters:
 | |
| 	pGetParameters: the information of scan
 | |
| Return value:
 | |
| 	if the operation is success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| GetParameters (LPGETPARAMETERS pGetParameters)
 | |
| {
 | |
|   DBG (DBG_FUNC, "GetParameters: start\n");
 | |
|   if (ST_Reflective == g_ScanType)
 | |
|     {
 | |
|       if (FALSE == Reflective_ScanSuggest (&g_tiTarget, &g_ssSuggest))
 | |
| 	{
 | |
| 	  DBG (DBG_ERR, "GetParameters: Reflective_ScanSuggest error\n");
 | |
| 	  return FALSE;
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (FALSE == Transparent_ScanSuggest (&g_tiTarget, &g_ssSuggest))
 | |
| 	{
 | |
| 	  DBG (DBG_ERR, "GetParameters: Transparent_ScanSuggest error\n");
 | |
| 	  return FALSE;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   pGetParameters->wSourceXDPI = g_ssSuggest.wXDpi;
 | |
|   pGetParameters->wSourceYDPI = g_ssSuggest.wYDpi;
 | |
|   pGetParameters->dwLength = (unsigned int) g_ssSuggest.wHeight;
 | |
|   pGetParameters->dwLineByteWidth = g_ssSuggest.dwBytesPerRow;
 | |
| 
 | |
|   DBG (DBG_FUNC, "GetParameters: exit\n");
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack            Date: 2005/05/13
 | |
| 
 | |
| Routine Description:
 | |
| 	start scan image
 | |
| Parameters:
 | |
| 	none
 | |
| Return value:
 | |
| 	if operation is success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| StartScan ()
 | |
| {
 | |
|   DBG (DBG_FUNC, "StartScan: start\n");
 | |
|   if (ST_Reflective == g_ScanType)
 | |
|     {
 | |
|       DBG (DBG_INFO, "StartScan: g_ScanType==ST_Reflective\n");
 | |
| 
 | |
|       return Reflective_SetupScan (g_ssSuggest.cmScanMode,
 | |
| 				   g_ssSuggest.wXDpi,
 | |
| 				   g_ssSuggest.wYDpi,
 | |
| 				   PF_BlackIs0,
 | |
| 				   g_ssSuggest.wX,
 | |
| 				   g_ssSuggest.wY,
 | |
| 				   g_ssSuggest.wWidth, g_ssSuggest.wHeight);
 | |
|     }
 | |
|   else
 | |
| 
 | |
|     {
 | |
| 
 | |
|       DBG (DBG_INFO, "StartScan: g_ScanType==ST_Transparent\n");
 | |
| 
 | |
|       return Transparent_SetupScan (g_ssSuggest.cmScanMode,
 | |
| 				    g_ssSuggest.wXDpi,
 | |
| 				    g_ssSuggest.wYDpi,
 | |
| 				    PF_BlackIs0,
 | |
| 				    g_ssSuggest.wX,
 | |
| 				    g_ssSuggest.wY,
 | |
| 				    g_ssSuggest.wWidth, g_ssSuggest.wHeight);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Read the scanner data
 | |
| Parameters:
 | |
| 
 | |
| 	pImageRows: the information of the data
 | |
| Return value:
 | |
| 	if the operation is seccuss
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| ReadScannedData (LPIMAGEROWS pImageRows)
 | |
| {
 | |
|   SANE_Bool isRGBInvert;
 | |
|   unsigned short Rows = 0;
 | |
|   SANE_Byte *lpBlock = (SANE_Byte *) pImageRows->pBuffer;
 | |
|   SANE_Byte *lpReturnData = (SANE_Byte *) pImageRows->pBuffer;
 | |
|   int i = 0;
 | |
| 
 | |
|   DBG (DBG_FUNC, "ReadScannedData: start\n");
 | |
| 
 | |
|   if (pImageRows->roRgbOrder == RO_RGB)
 | |
|     isRGBInvert = FALSE;
 | |
|   else
 | |
|     isRGBInvert = TRUE;
 | |
| 
 | |
|   Rows = pImageRows->wWantedLineNum;
 | |
| 
 | |
|   DBG (DBG_INFO, "ReadScannedData: wanted Rows = %d\n", Rows);
 | |
| 
 | |
|   if (ST_Reflective == g_ScanType)
 | |
|     {
 | |
|       if (FALSE == Reflective_GetRows (lpBlock, &Rows, isRGBInvert))
 | |
| 	return FALSE;
 | |
|     }
 | |
|   else if (SS_Positive == g_ssScanSource)
 | |
|     {
 | |
|       if (FALSE == Transparent_GetRows (lpBlock, &Rows, isRGBInvert))
 | |
| 	return FALSE;
 | |
|     }
 | |
| 
 | |
|   pImageRows->wXferedLineNum = Rows;
 | |
| 
 | |
|   if (g_PixelFlavor == PF_WhiteIs0 || g_ScanMode == CM_TEXT)
 | |
|     {
 | |
|       int TotalSize = Rows * g_ssSuggest.dwBytesPerRow;
 | |
|       for (i = 0; i < TotalSize; i++)
 | |
| 	{
 | |
| 	  *(lpBlock++) ^= 0xff;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (SS_Negative == g_ssScanSource)
 | |
|     {
 | |
|       DBG (DBG_INFO, "ReadScannedData: deal with the Negative\n");
 | |
| 
 | |
|       if (g_bIsFirstGetNegData)
 | |
| 	{
 | |
| 	  unsigned int TotalImgeSize = g_SWHeight * g_ssSuggest.dwBytesPerRow;
 | |
| 	  g_lpNegImageData = (SANE_Byte *) malloc (TotalImgeSize);
 | |
| 	  if (NULL != g_lpNegImageData)
 | |
| 	    {
 | |
| 	      SANE_Byte * lpTempData = g_lpNegImageData;
 | |
| 	      DBG (DBG_INFO,
 | |
| 		   "ReadScannedData: malloc the negative data is success!\n");
 | |
| 	      g_bIsMallocNegData = TRUE;
 | |
| 	      if (!Transparent_GetRows
 | |
| 		  (g_lpNegImageData, &g_SWHeight, isRGBInvert))
 | |
| 		{
 | |
| 		  return FALSE;
 | |
| 		}
 | |
| 
 | |
| 	      DBG (DBG_INFO, "ReadScannedData: get image data is over!\n");
 | |
| 
 | |
| 	      for (i = 0; i < (int) TotalImgeSize; i++)
 | |
| 		{
 | |
| 		  *(g_lpNegImageData++) ^= 0xff;
 | |
| 		}
 | |
| 	      g_lpNegImageData = lpTempData;
 | |
| 	      AutoLevel (g_lpNegImageData, g_ScanMode, g_SWHeight,
 | |
| 			 g_ssSuggest.dwBytesPerRow);
 | |
| 	      DBG (DBG_INFO, "ReadScannedData: autolevel is ok\n");
 | |
| 	    }
 | |
| 	  g_bIsFirstGetNegData = FALSE;
 | |
| 	}
 | |
| 
 | |
|       if (g_bIsMallocNegData)
 | |
| 	{
 | |
| 	  memcpy (pImageRows->pBuffer,
 | |
| 		  g_lpNegImageData +
 | |
| 		  g_ssSuggest.dwBytesPerRow * g_dwAlreadyGetNegLines,
 | |
| 		  g_ssSuggest.dwBytesPerRow * Rows);
 | |
| 
 | |
| 	  DBG (DBG_INFO, "ReadScannedData: copy the data over!\n");
 | |
| 
 | |
| 	  g_dwAlreadyGetNegLines += Rows;
 | |
| 	  if (g_dwAlreadyGetNegLines >= g_SWHeight)
 | |
| 	    {
 | |
| 	      DBG (DBG_INFO, "ReadScannedData: free the image data!\n");
 | |
| 	      free (g_lpNegImageData);
 | |
| 	      g_lpNegImageData = NULL;
 | |
| 	      g_bIsFirstGetNegData = TRUE;
 | |
| 	      g_dwAlreadyGetNegLines = 0;
 | |
| 	      g_bIsMallocNegData = FALSE;
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  int TotalSize = Rows * g_ssSuggest.dwBytesPerRow;
 | |
| 	  DBG (DBG_INFO,
 | |
| 	       "ReadScannedData: malloc the negative data is fail!\n");
 | |
| 	  if (!Transparent_GetRows (lpReturnData, &Rows, isRGBInvert))
 | |
| 	    {
 | |
| 	      return FALSE;
 | |
| 	    }
 | |
| 
 | |
| 	  for (i = 0; i < TotalSize; i++)
 | |
| 	    {
 | |
| 	      *(lpReturnData++) ^= 0xff;
 | |
| 	    }
 | |
| 	  pImageRows->wXferedLineNum = Rows;
 | |
| 
 | |
| 	  g_dwAlreadyGetNegLines += Rows;
 | |
| 	  if (g_dwAlreadyGetNegLines >= g_SWHeight)
 | |
| 	    {
 | |
| 	      g_bIsFirstGetNegData = TRUE;
 | |
| 	      g_dwAlreadyGetNegLines = 0;
 | |
| 	      g_bIsMallocNegData = FALSE;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_FUNC, "ReadScannedData: leave ReadScannedData\n");
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Stop scan
 | |
| Parameters:
 | |
| 	none
 | |
| Return value:
 | |
| 	if operation is success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| StopScan ()
 | |
| {
 | |
|   SANE_Bool rt;
 | |
|   int i;
 | |
| 
 | |
|   DBG (DBG_FUNC, "StopScan: start\n");
 | |
| 
 | |
|   /*stop read data and kill thread */
 | |
|   if (ST_Reflective == g_ScanType)
 | |
|     {
 | |
|       rt = Reflective_StopScan ();
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       rt = Transparent_StopScan ();
 | |
|     }
 | |
| 
 | |
|   /*free gamma table */
 | |
|   if (g_isSelfGamma && g_pGammaTable != NULL)
 | |
|     {
 | |
|       for (i = 0; i < 20; i++)
 | |
| 	{
 | |
| 	  if (!g_isScanning)
 | |
| 	    {
 | |
| 	      free (g_pGammaTable);
 | |
| 	      g_pGammaTable = NULL;
 | |
| 	      break;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      sleep (1);	/*waiting ReadScannedData return. */
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   /*free image buffer */
 | |
|   if (g_lpReadImageHead != NULL)
 | |
| 
 | |
|     {
 | |
|       free (g_lpReadImageHead);
 | |
|       g_lpReadImageHead = NULL;
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_FUNC, "StopScan: exit\n");
 | |
|   return rt;
 | |
| }
 | |
| 
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Check the status of TA
 | |
| Parameters:
 | |
| 	none
 | |
| Return value:
 | |
| 	if operation is success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| IsTAConnected ()
 | |
| {
 | |
|   SANE_Bool hasTA;
 | |
| 
 | |
|   DBG (DBG_FUNC, "StopScan: start\n");
 | |
| 
 | |
|   if (Asic_Open (&g_chip, g_pDeviceFile) != STATUS_GOOD)
 | |
|     {
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   if (Asic_IsTAConnected (&g_chip, &hasTA) != STATUS_GOOD)
 | |
|     {
 | |
|       Asic_Close (&g_chip);
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   Asic_Close (&g_chip);
 | |
| 
 | |
|   DBG (DBG_FUNC, "StopScan: exit\n");
 | |
|   return hasTA;
 | |
| }
 | |
| 
 | |
| #ifdef SANE_UNUSED
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Get the status of the HK
 | |
| Parameters:
 | |
| 	pKey: the status of key
 | |
| Return value:
 | |
| 	if the operation is success
 | |
| 	return TRUE
 | |
| 	else
 | |
| 	return FALSE
 | |
| ***********************************************************************/
 | |
| static SANE_Bool
 | |
| GetKeyStatus (SANE_Byte * pKey)
 | |
| {
 | |
|   SANE_Byte pKeyTemp = 0x00;
 | |
|   STATUS status = Asic_CheckFunctionKey (&g_chip, &pKeyTemp);
 | |
|   DBG (DBG_FUNC, "GetKeyStatus: start\n");
 | |
| 
 | |
|   if (STATUS_GOOD != Asic_Open (&g_chip, g_pDeviceFile))
 | |
|     {
 | |
|       DBG (DBG_ERR, "GetKeyStatus: Asic_Open is fail\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   if (STATUS_GOOD != status)
 | |
|     {
 | |
|       DBG (DBG_ERR, "GetKeyStatus: Asic_CheckFunctionKey is fail\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   if (0x01 == pKeyTemp)
 | |
|     {
 | |
|       *pKey = 0x01;		/*Scan key pressed */
 | |
|     }
 | |
| 
 | |
|   if (0x02 == pKeyTemp)
 | |
|     {
 | |
|       *pKey = 0x02;		/*Copy key pressed */
 | |
|     }
 | |
|   if (0x04 == pKeyTemp)
 | |
|     {
 | |
|       *pKey = 0x03;		/*Fax key pressed */
 | |
|     }
 | |
|   if (0x08 == pKeyTemp)
 | |
|     {
 | |
|       *pKey = 0x04;		/*Email key pressed */
 | |
|     }
 | |
|   if (0x10 == pKeyTemp)
 | |
|     {
 | |
|       *pKey = 0x05;		/*Panel key pressed */
 | |
|     }
 | |
| 
 | |
|   if (STATUS_GOOD != Asic_Close (&g_chip))
 | |
|     {
 | |
|       DBG (DBG_ERR, "GetKeyStatus: Asic_Close is fail\n");
 | |
|       return FALSE;
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_FUNC, "GetKeyStatus: exit\n");
 | |
|   return TRUE;
 | |
| }
 | |
| #endif
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Deal with the image with auto level
 | |
| Parameters:
 | |
| 	lpSource: the data of image
 | |
| 	scanMode: the scan mode
 | |
| 	ScanLines: the rows of image
 | |
| 	BytesPerLine: the bytes of per line
 | |
| Return value:
 | |
| 	none
 | |
| ***********************************************************************/
 | |
| static void
 | |
| AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines,
 | |
| 	   unsigned int BytesPerLine)
 | |
| {
 | |
|   int ii;
 | |
|   unsigned int i, j;
 | |
|   unsigned int tLines, CountPixels, TotalImgSize;
 | |
|   unsigned short R, G, B, max_R, max_G, max_B, min_R, min_G, min_B;
 | |
|   float fmax_R, fmax_G, fmax_B;
 | |
|   unsigned int sum_R = 0, sum_G = 0, sum_B = 0;
 | |
|   unsigned int hisgram_R[256], hisgram_G[256], hisgram_B[256];
 | |
| 
 | |
|   unsigned int iWidth = BytesPerLine / 3;
 | |
|   unsigned int iHeight = ScanLines;
 | |
|   SANE_Byte *pbmpdata = (SANE_Byte *) lpSource;
 | |
| 
 | |
|   unsigned short imin_threshold[3];
 | |
|   unsigned short imax_threshold[3];
 | |
| 
 | |
|   DBG (DBG_FUNC, "AutoLevel: start\n");
 | |
| 
 | |
|   if (scanMode != CM_RGB24ext)
 | |
|     {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   i = j = 0;
 | |
|   tLines = CountPixels = TotalImgSize = 0;
 | |
| 
 | |
|   TotalImgSize = iWidth * iHeight;
 | |
| 
 | |
| 
 | |
| 
 | |
|   for (i = 0; i < 256; i++)
 | |
|     {
 | |
| 
 | |
|       hisgram_R[i] = 0;
 | |
|       hisgram_G[i] = 0;
 | |
|       hisgram_B[i] = 0;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   DBG (DBG_INFO, "AutoLevel: init data is over\n");
 | |
| 
 | |
|   /* Find min , max, mean */
 | |
|   max_R = max_G = max_B = 0;
 | |
|   min_R = min_G = min_B = 255;
 | |
|   tLines = 0;
 | |
|   DBG (DBG_INFO, "AutoLevel: iHeight = %d, iWidth = %d\n", iHeight, iWidth);
 | |
| 
 | |
|   for (j = 0; j < iHeight; j++)
 | |
|     {
 | |
|       tLines = j * iWidth * 3;
 | |
| 
 | |
| 
 | |
|       for (i = 0; i < iWidth; i++)
 | |
| 	{
 | |
| 	  R = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 2));
 | |
| 	  G = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 1));
 | |
| 	  B = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3));
 | |
| 
 | |
| 	  max_R = _MAX (R, max_R);
 | |
| 	  max_G = _MAX (G, max_G);
 | |
| 	  max_B = _MAX (B, max_B);
 | |
| 
 | |
| 	  min_R = _MIN (R, min_R);
 | |
| 	  min_G = _MIN (G, min_G);
 | |
| 	  min_B = _MIN (B, min_B);
 | |
| 
 | |
| 	  hisgram_R[(SANE_Byte) R]++;
 | |
| 	  hisgram_G[(SANE_Byte) G]++;
 | |
| 	  hisgram_B[(SANE_Byte) B]++;
 | |
| 
 | |
| 	  sum_R += R;
 | |
| 	  sum_G += G;
 | |
| 	  sum_B += B;
 | |
| 
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 2)) = (SANE_Byte) R;
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 1)) = (SANE_Byte) G;
 | |
| 	  *(pbmpdata + (tLines + i * 3)) = (SANE_Byte) B;
 | |
| 
 | |
| 	  CountPixels++;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_INFO, "AutoLevel: Find min , max is over!\n");
 | |
| 
 | |
| 
 | |
|   imin_threshold[0] = 0;
 | |
|   imin_threshold[1] = 0;
 | |
|   imin_threshold[2] = 0;
 | |
|   imax_threshold[0] = 0;
 | |
|   imax_threshold[1] = 0;
 | |
|   imax_threshold[2] = 0;
 | |
| 
 | |
|   for (ii = 0; ii < 256; ii++)
 | |
|     {
 | |
|       if (hisgram_R[ii] > 0)
 | |
| 	if (hisgram_R[ii] >= imin_threshold[0])
 | |
| 	  {
 | |
| 	    min_R = ii;
 | |
| 	    break;
 | |
| 	  }
 | |
|     }
 | |
| 
 | |
|   for (ii = 255; ii >= 0; ii--)
 | |
|     {
 | |
|       if (hisgram_R[ii] > 0)
 | |
| 	if (hisgram_R[ii] >= imax_threshold[0])
 | |
| 	  {
 | |
| 	    max_R = ii;
 | |
| 	    break;
 | |
| 	  }
 | |
|     }
 | |
| 
 | |
|   for (ii = 0; ii < 256; ii++)
 | |
|     {
 | |
|       if (hisgram_G[ii] > 0)
 | |
| 	if (hisgram_G[ii] >= imin_threshold[1])
 | |
| 	  {
 | |
| 	    min_G = ii;
 | |
| 	    break;
 | |
| 	  }
 | |
|     }
 | |
| 
 | |
|   for (ii = 255; ii >= 0; ii--)
 | |
|     {
 | |
|       if (hisgram_G[ii] > 0)
 | |
| 	if (hisgram_G[ii] >= imax_threshold[1])
 | |
| 	  {
 | |
| 	    max_G = ii;
 | |
| 	    break;
 | |
| 	  }
 | |
|     }
 | |
| 
 | |
|   for (ii = 0; ii < 256; ii++)
 | |
|     {
 | |
|       if (hisgram_B[ii] > 0)
 | |
| 	if (hisgram_B[ii] >= imin_threshold[2])
 | |
| 	  {
 | |
| 	    min_B = ii;
 | |
| 	    break;
 | |
| 	  }
 | |
|     }
 | |
| 
 | |
|   for (ii = 255; ii >= 0; ii--)
 | |
|     {
 | |
|       if (hisgram_B[ii] > 0)
 | |
| 	if (hisgram_B[ii] >= imax_threshold[2])
 | |
| 	  {
 | |
| 	    max_B = ii;
 | |
| 	    break;
 | |
| 	  }
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_INFO, "AutoLevel: Set min , max is over!\n");
 | |
| 
 | |
|   /*Autolevel: */
 | |
|   sum_R = max_R - min_R;
 | |
|   sum_G = max_G - min_G;
 | |
|   sum_B = max_B - min_B;
 | |
| 
 | |
|   for (j = 0; j < iHeight; j++)
 | |
|     {
 | |
|       tLines = j * iWidth * 3;
 | |
|       for (i = 0; i < iWidth; i++)
 | |
| 	{
 | |
| 	  R = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 2));
 | |
| 	  G = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 1));
 | |
| 	  B = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3));
 | |
| 
 | |
| 	   /*R*/ if (sum_R == 0)
 | |
| 	    R = max_R;
 | |
| 	  else if (R < min_R)
 | |
| 	    R = 0;
 | |
| 	  else if (R <= 255)
 | |
| 	    {
 | |
| 	      fmax_R = ((float) ((R - min_R) * 255) / (float) sum_R);
 | |
| 	      R = (unsigned short) fmax_R;
 | |
| 	      fmax_R = (fmax_R - R) * 10;
 | |
| 
 | |
| 	      if (fmax_R >= 5)
 | |
| 		R++;
 | |
| 	    }
 | |
| 	  if (R > 255)
 | |
| 	    R = 255;
 | |
| 
 | |
| 	   /*G*/ if (sum_G == 0)
 | |
| 	    G = max_G;
 | |
| 	  else if (G < min_G)
 | |
| 	    G = 0;
 | |
| 	  else if (G <= 255)
 | |
| 	    {
 | |
| 	      fmax_G = ((float) ((G - min_G) * 255) / (float) sum_G);
 | |
| 	      G = (unsigned short) fmax_G;
 | |
| 	      fmax_G = (fmax_G - G) * 10;
 | |
| 	      if (fmax_G >= 5)
 | |
| 		G++;
 | |
| 
 | |
| 	    }
 | |
| 	  if (G > 255)
 | |
| 	    G = 255;
 | |
| 
 | |
| 	   /*B*/ if (sum_B == 0)
 | |
| 	    B = max_B;
 | |
| 	  else if (B < min_B)
 | |
| 	    B = 0;
 | |
| 	  else if (B <= 255)
 | |
| 	    {
 | |
| 	      fmax_B = ((float) (B - min_B) * 255 / (float) sum_B);
 | |
| 	      B = (unsigned short) fmax_B;
 | |
| 	      fmax_B = (fmax_B - B) * 10;
 | |
| 	      if (fmax_B >= 5)
 | |
| 		B++;
 | |
| 	    }
 | |
| 	  if (B > 255)
 | |
| 	    B = 255;
 | |
| 
 | |
| 	  hisgram_R[(SANE_Byte) R]++;
 | |
| 	  hisgram_G[(SANE_Byte) G]++;
 | |
| 	  hisgram_B[(SANE_Byte) B]++;
 | |
| 
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 2)) = (SANE_Byte) R;
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 1)) = (SANE_Byte) G;
 | |
| 	  *(pbmpdata + (tLines + i * 3)) = (SANE_Byte) B;
 | |
| 
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   DBG (DBG_FUNC, "AutoLevel: exit\n");
 | |
|   return;
 | |
| }
 | |
| 
 | |
| #ifdef SANE_UNUSED
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Deal with image with auto level
 | |
| Parameters:
 | |
| 	pDIB: the data of image
 | |
| 	ImageWidth: the width of image
 | |
| 	ImageHeight: the height of image
 | |
| Return value:
 | |
| 	none
 | |
| ***********************************************************************/
 | |
| static void
 | |
| QBETDetectAutoLevel (void *pDIB, unsigned int ImageWidth, unsigned int ImageHeight)
 | |
| {
 | |
|   unsigned short *pbmpdata;
 | |
|   float fRPercent = 0.0;
 | |
|   float fGPercent = 0.0;
 | |
|   float fBPercent = 0.0;
 | |
|   float fRSum, fGSum, fBSum;
 | |
| 
 | |
|   int i, j;
 | |
|   unsigned int tLines, CountPixels, TotalImgSize;
 | |
|   unsigned short R, G, B, max_R, max_G, max_B, min_R, min_G, min_B;
 | |
|   unsigned short wIndexR, wIndexG, wIndexB;
 | |
|   float fmax_R, fmax_G, fmax_B;
 | |
|   unsigned int sum_R = 0, sum_G = 0, sum_B = 0;
 | |
|   unsigned int hisgram_R[1024], hisgram_G[1024], hisgram_B[1024];
 | |
| 
 | |
|   if (!pDIB)
 | |
|     {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   pbmpdata = (unsigned short *) pDIB;
 | |
| 
 | |
|   CountPixels = 0;
 | |
|   TotalImgSize = ImageWidth * ImageHeight;
 | |
| 
 | |
| 
 | |
|   for (i = 0; i < 1024; i++)
 | |
|     {
 | |
| 
 | |
|       hisgram_R[i] = 0;
 | |
|       hisgram_G[i] = 0;
 | |
|       hisgram_B[i] = 0;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   /*Find min , max, mean */
 | |
|   max_R = max_G = max_B = 0;
 | |
|   min_R = min_G = min_B = 1023;
 | |
|   tLines = 0;
 | |
| 
 | |
|   for (j = 0; j < (int) ImageHeight; j++)
 | |
|     {
 | |
|       tLines = j * ImageWidth * 3;
 | |
|       for (i = 0; i < (int) ImageWidth; i++)
 | |
| 	{
 | |
| 	  R = *(pbmpdata + (tLines + i * 3 + 2));
 | |
| 	  G = *(pbmpdata + (tLines + i * 3 + 1));
 | |
| 	  B = *(pbmpdata + (tLines + i * 3));
 | |
| 
 | |
| 	  max_R = _MAX (R, max_R);
 | |
| 	  max_G = _MAX (G, max_G);
 | |
| 	  max_B = _MAX (B, max_B);
 | |
| 
 | |
| 	  min_R = _MIN (R, min_R);
 | |
| 	  min_G = _MIN (G, min_G);
 | |
| 	  min_B = _MIN (B, min_B);
 | |
| 
 | |
| 	  hisgram_R[R]++;
 | |
| 	  hisgram_G[G]++;
 | |
| 	  hisgram_B[B]++;
 | |
| 
 | |
| 	  sum_R += R;
 | |
| 	  sum_G += G;
 | |
| 	  sum_B += B;
 | |
| 
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 2)) = R;
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 1)) = G;
 | |
| 	  *(pbmpdata + (tLines + i * 3)) = B;
 | |
| 
 | |
| 	  CountPixels++;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|   fRSum = 0.0;
 | |
|   fGSum = 0.0;
 | |
|   fBSum = 0.0;
 | |
| 
 | |
|   wIndexR = 511;
 | |
|   wIndexG = 511;
 | |
|   wIndexB = 511;
 | |
| 
 | |
|   for (i = 0; i < 1024; i++)
 | |
|     {
 | |
|       fRSum += (float) hisgram_R[i];
 | |
|       fRPercent = (fRSum / CountPixels) * 100;
 | |
|       if (fRPercent > 50)
 | |
| 	{
 | |
| 	  wIndexR = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < 1024; i++)
 | |
|     {
 | |
|       fGSum += (float) hisgram_G[i];
 | |
|       fGPercent = (fGSum / CountPixels) * 100;
 | |
|       if (fGPercent > 50)
 | |
| 	{
 | |
| 	  wIndexG = i;
 | |
| 	  break;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < 1024; i++)
 | |
|     {
 | |
|       fBSum += (float) hisgram_B[i];
 | |
|       fBPercent = (fBSum / CountPixels) * 100;
 | |
|       if (fBPercent > 50)
 | |
| 	{
 | |
| 	  wIndexB = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|   fRSum = 0.0;
 | |
| 
 | |
|   for (i = wIndexR; i >= 0; i--)
 | |
|     {
 | |
|       fRSum += (float) hisgram_R[i];
 | |
|       fRPercent = (fRSum / CountPixels) * 100;
 | |
|       if (fRPercent >= 48)
 | |
| 	{
 | |
| 	  min_R = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   fRSum = 0.0;
 | |
|   for (i = wIndexR; i < 1024; i++)
 | |
|     {
 | |
|       fRSum += (float) hisgram_R[i];
 | |
|       fRPercent = (fRSum / CountPixels) * 100;
 | |
|       if (fRPercent >= 47)
 | |
| 	{
 | |
| 	  max_R = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|   fGSum = 0.0;
 | |
|   for (i = wIndexG; i >= 0; i--)
 | |
|     {
 | |
|       fGSum += (float) hisgram_G[i];
 | |
|       fGPercent = (fGSum / CountPixels) * 100;
 | |
|       if (fGPercent >= 48)
 | |
| 	{
 | |
| 	  min_G = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   fGSum = 0.0;
 | |
|   for (i = wIndexG; i < 1024; i++)
 | |
|     {
 | |
|       fGSum += (float) hisgram_G[i];
 | |
|       fGPercent = (fGSum / CountPixels) * 100;
 | |
|       if (fGPercent >= 47)
 | |
| 	{
 | |
| 	  max_G = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   fBSum = 0.0;
 | |
|   for (i = wIndexB; i >= 0; i--)
 | |
|     {
 | |
|       fBSum += (float) hisgram_B[i];
 | |
|       fBPercent = (fBSum / CountPixels) * 100;
 | |
|       if (fBPercent >= 46)
 | |
| 	{
 | |
| 	  min_B = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
|   fBSum = 0.0;
 | |
|   for (i = wIndexB; i < 1024; i++)
 | |
|     {
 | |
|       fBSum += (float) hisgram_B[i];
 | |
|       fBPercent = (fBSum / CountPixels) * 100;
 | |
|       if (fBPercent >= 47)
 | |
| 	{
 | |
| 	  max_B = i;
 | |
| 	  break;
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|   /*Autolevel: */
 | |
|   sum_R = max_R - min_R;
 | |
|   sum_G = max_G - min_G;
 | |
|   sum_B = max_B - min_B;
 | |
| 
 | |
|   for (j = 0; j < (int) ImageHeight; j++)
 | |
|     {
 | |
|       tLines = j * ImageWidth * 3;
 | |
|       for (i = 0; i < (int) ImageWidth; i++)
 | |
| 	{
 | |
| 	  R = *(pbmpdata + (tLines + i * 3 + 2));
 | |
| 	  G = *(pbmpdata + (tLines + i * 3 + 1));
 | |
| 	  B = *(pbmpdata + (tLines + i * 3));
 | |
| 
 | |
| 
 | |
| 	   /*R*/ if (sum_R == 0)
 | |
| 	    R = max_R;
 | |
| 	  else if (R < min_R)
 | |
| 	    {
 | |
| 
 | |
| 	      R = 0;
 | |
| 	    }
 | |
| 	  else if ((R >= min_R) && (R <= 1023))
 | |
| 	    {
 | |
| 	      fmax_R = ((float) ((R - min_R) * 923) / (float) sum_R) + 100;
 | |
| 	      R = (unsigned short) fmax_R;
 | |
| 	      fmax_R = (fmax_R - R) * 10;
 | |
| 	      if (fmax_R >= 5)
 | |
| 		R++;
 | |
| 	    }
 | |
| 	  if (R > 1023)
 | |
| 	    R = 1023;
 | |
| 
 | |
| 	   /*G*/ if (sum_G == 0)
 | |
| 	    G = max_G;
 | |
| 	  else if (G < min_G)
 | |
| 	    {
 | |
| 
 | |
| 	      G = 0;
 | |
| 	    }
 | |
| 	  else if ((G >= min_G) && (G <= 1023))
 | |
| 	    {
 | |
| 	      fmax_G = ((float) ((G - min_G) * 923) / (float) sum_G) + 100;
 | |
| 	      G = (unsigned short) fmax_G;
 | |
| 	      fmax_G = (fmax_G - G) * 10;
 | |
| 	      if (fmax_G >= 5)
 | |
| 		G++;
 | |
| 	    }
 | |
| 	  if (G > 1023)
 | |
| 	    G = 1023;
 | |
| 
 | |
| 	   /*B*/ if (sum_B == 0)
 | |
| 	    B = max_B;
 | |
| 	  else if (B < min_R)
 | |
| 	    {
 | |
| 
 | |
| 	      B = 0;
 | |
| 	    }
 | |
| 	  else if ((B >= min_B) && (R <= 1023))
 | |
| 	    {
 | |
| 	      fmax_B = ((float) (B - min_B) * 923 / (float) sum_B) + 100;
 | |
| 
 | |
| 	      B = (unsigned short) fmax_B;
 | |
| 	      fmax_B = (fmax_B - B) * 10;
 | |
| 	      if (fmax_B >= 5)
 | |
| 		B++;
 | |
| 	    }
 | |
| 	  if (B > 1023)
 | |
| 	    B = 1023;
 | |
| 
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 2)) = R;
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 1)) = G;
 | |
| 	  *(pbmpdata + (tLines + i * 3)) = B;
 | |
| 
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef SANE_UNUSED
 | |
| /**********************************************************************
 | |
| Author: Jack             Date: 2005/05/14
 | |
| Routine Description:
 | |
| 	Change the image data and deal with auto level
 | |
| Parameters:
 | |
| 	lpSource: the data of image
 | |
| 	scanMode: the scan mode
 | |
| 	ScanLines: the rows of image
 | |
| 	BytesPerLine: the bytes of per line
 | |
| Return value:
 | |
| 	none
 | |
| ***********************************************************************/
 | |
| static void
 | |
| QBetChange (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines,
 | |
| 	    unsigned int BytesPerLine)
 | |
| {
 | |
|   unsigned short i, j;
 | |
|   unsigned int tLines, TotalImgSize;
 | |
|   unsigned short R1, G1, B1, R, G, B, R2, G2, B2, QBET_RGB = 0, PointF, PointB;
 | |
|   unsigned short *pwRGB;
 | |
| 
 | |
|   int k;
 | |
| 
 | |
|   unsigned int ImageWidth = BytesPerLine / 3;
 | |
|   unsigned int ImageHeight = ScanLines;
 | |
|   SANE_Byte *pbmpdata = (SANE_Byte *) lpSource;
 | |
| 
 | |
|   if (scanMode != CM_RGB24ext)
 | |
|     {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   TotalImgSize = ImageWidth * ImageHeight * 3 * 2;
 | |
|   if ((pwRGB = (unsigned short *) malloc (TotalImgSize)) == NULL)
 | |
|     {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   for (j = 0; j < ImageHeight; j++)
 | |
|     {
 | |
|       tLines = j * ImageWidth * 3;
 | |
|       for (i = 0; i < ImageWidth; i++)
 | |
| 	{
 | |
| 	  if (i == 0)
 | |
| 	    {
 | |
| 	      R1 = R = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 2));
 | |
| 	      G1 = G = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 1));
 | |
| 	      B1 = B = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3));
 | |
| 	      R2 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i + 1) * 3 + 2));
 | |
| 	      G2 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i + 1) * 3 + 1));
 | |
| 	      B2 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i + 1) * 3));
 | |
| 	    }
 | |
| 	  else if (i == (ImageWidth - 1))
 | |
| 	    {
 | |
| 	      R1 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i - 1) * 3 + 2));
 | |
| 	      G1 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i - 1) * 3 + 1));
 | |
| 	      B1 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i - 1) * 3));
 | |
| 	      R2 = R = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 2));
 | |
| 	      G2 = G = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 1));
 | |
| 	      B2 = B = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3));
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      R1 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i - 1) * 3 + 2));
 | |
| 	      G1 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i - 1) * 3 + 1));
 | |
| 	      B1 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i - 1) * 3));
 | |
| 
 | |
| 	      R = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 2));
 | |
| 	      G = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3 + 1));
 | |
| 	      B = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + i * 3));
 | |
| 
 | |
| 	      R2 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i + 1) * 3 + 2));
 | |
| 	      G2 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i + 1) * 3 + 1));
 | |
| 	      B2 = (unsigned short) (SANE_Byte) * (pbmpdata + (tLines + (i + 1) * 3));
 | |
| 	    }
 | |
| 
 | |
| 	  R1 = R1 & 0x0003;
 | |
| 	  G1 = G1 & 0x0003;
 | |
| 	  B1 = B1 & 0x0003;
 | |
| 
 | |
| 	  R2 = R2 & 0x0003;
 | |
| 	  G2 = G2 & 0x0003;
 | |
| 	  B2 = B2 & 0x0003;
 | |
| 	  for (k = 0; k < 3; k++)
 | |
| 	    {
 | |
| 	      if (k == 0)
 | |
| 		{
 | |
| 		  PointF = R1;
 | |
| 		  PointB = R2;
 | |
| 		}
 | |
| 	      else if (k == 1)
 | |
| 		{
 | |
| 		  PointF = G1;
 | |
| 		  PointB = G2;
 | |
| 		}
 | |
| 	      else if (k == 2)
 | |
| 		{
 | |
| 		  PointF = B1;
 | |
| 		  PointB = B2;
 | |
| 		}
 | |
| 
 | |
| 	      switch (PointF)
 | |
| 		{
 | |
| 		case 0:
 | |
| 		case 1:
 | |
| 		  if (PointB == 0)
 | |
| 		    QBET_RGB = 0xFFFC;
 | |
| 		  else if (PointB == 1)
 | |
| 		    QBET_RGB = 0xFFFC;
 | |
| 		  else if (PointB == 2)
 | |
| 		    QBET_RGB = 0xFFFD;
 | |
| 		  else if (PointB == 3)
 | |
| 		    QBET_RGB = 0xFFFE;
 | |
| 		  break;
 | |
| 		case 2:
 | |
| 		  if (PointB == 0)
 | |
| 		    QBET_RGB = 0xFFFD;
 | |
| 		  else if (PointB == 1)
 | |
| 		    QBET_RGB = 0xFFFD;
 | |
| 		  else if (PointB == 2)
 | |
| 		    QBET_RGB = 0xFFFF;
 | |
| 		  else if (PointB == 3)
 | |
| 		    QBET_RGB = 0xFFFF;
 | |
| 		  break;
 | |
| 		case 3:
 | |
| 		  if (PointB == 0)
 | |
| 		    QBET_RGB = 0xFFFE;
 | |
| 		  else if (PointB == 1)
 | |
| 		    QBET_RGB = 0xFFFE;
 | |
| 		  else if (PointB == 2)
 | |
| 		    QBET_RGB = 0xFFFF;
 | |
| 		  else if (PointB == 3)
 | |
| 		    QBET_RGB = 0xFFFF;
 | |
| 		  break;
 | |
| 		default:
 | |
| 		  break;
 | |
| 		}
 | |
| 
 | |
| 	      if (k == 0)
 | |
| 		{
 | |
| 		  R = R << 2;
 | |
| 		  R = R + 0x0003;
 | |
| 		  R = R & QBET_RGB;
 | |
| 		}
 | |
| 	      else if (k == 1)
 | |
| 		{
 | |
| 		  G = G << 2;
 | |
| 		  G = G + 0x0003;
 | |
| 		  G = G & QBET_RGB;
 | |
| 		}
 | |
| 	      else if (k == 2)
 | |
| 		{
 | |
| 		  B = B << 2;
 | |
| 		  B = B + 0x0003;
 | |
| 		  B = B & QBET_RGB;
 | |
| 		}
 | |
| 
 | |
| 	    }
 | |
| 
 | |
| 	  *(pwRGB + (tLines + i * 3 + 2)) = R;
 | |
| 	  *(pwRGB + (tLines + i * 3 + 1)) = G;
 | |
| 	  *(pwRGB + (tLines + i * 3)) = B;
 | |
| 
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|   QBETDetectAutoLevel (pwRGB, ImageWidth, ImageHeight);
 | |
| 
 | |
| 
 | |
|   for (j = 0; j < ImageHeight; j++)
 | |
|     {
 | |
|       tLines = j * ImageWidth * 3;
 | |
| 
 | |
|       for (i = 0; i < ImageWidth; i++)
 | |
| 	{
 | |
| 	  R = *(pwRGB + (tLines + i * 3 + 2));
 | |
| 	  G = *(pwRGB + (tLines + i * 3 + 1));
 | |
| 	  B = *(pwRGB + (tLines + i * 3));
 | |
| 
 | |
| 	  R = R >> 2;
 | |
| 	  G = G >> 2;
 | |
| 
 | |
| 	  B = B >> 2;
 | |
| 	  if (R > 255)
 | |
| 	    R = 255;
 | |
| 	  if (G > 255)
 | |
| 	    G = 255;
 | |
| 	  if (B > 255)
 | |
| 	    B = 255;
 | |
| 
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 2)) = (SANE_Byte) R;
 | |
| 	  *(pbmpdata + (tLines + i * 3 + 1)) = (SANE_Byte) G;
 | |
| 	  *(pbmpdata + (tLines + i * 3)) = (SANE_Byte) B;
 | |
| 
 | |
| 	}
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|   if (pwRGB != NULL)
 | |
|     {
 | |
|       free (pwRGB);
 | |
|     }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /****************************** SANE API functions *****************************/
 | |
| 
 | |
| SANE_Status
 | |
| sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
 | |
| {
 | |
|   DBG_INIT ();
 | |
|   DBG (DBG_FUNC, "sane_init: start\n");
 | |
|   DBG (DBG_ERR, "SANE Mustek USB2 backend version %d.%d build %d from %s\n",
 | |
|        SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING);
 | |
| 
 | |
|   num_devices = 1;		/* HOLD: only one device in this backend */
 | |
| 
 | |
|   if (version_code != NULL)
 | |
|     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD);
 | |
| 
 | |
|   DBG (DBG_INFO, "sane_init: authorize %s null\n", authorize ? "!=" : "==");
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_init: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| void
 | |
| sane_exit (void)
 | |
| {
 | |
|   DBG (DBG_FUNC, "sane_exit: start\n");
 | |
| 
 | |
|   if (devlist != NULL)
 | |
|     {
 | |
|       free (devlist);
 | |
|       devlist = NULL;
 | |
|     }
 | |
| 
 | |
|   devlist = NULL;
 | |
|   DBG (DBG_FUNC, "sane_exit: exit\n");
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
 | |
| {
 | |
|   SANE_Int dev_num;
 | |
|   DBG (DBG_FUNC, "sane_get_devices: start: local_only = %s\n",
 | |
|        local_only == SANE_TRUE ? "true" : "false");
 | |
| 
 | |
|   if (devlist != NULL)
 | |
|     {
 | |
|       free (devlist);
 | |
|       devlist = NULL;
 | |
|     }
 | |
| 
 | |
|   devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
 | |
|   if (devlist == NULL)
 | |
|     return SANE_STATUS_NO_MEM;
 | |
| 
 | |
|   dev_num = 0;
 | |
|   /* HOLD: This is ugly (only one scanner!) and should go to sane_init */
 | |
|   if (GetDeviceStatus ())
 | |
|     {
 | |
|       SANE_Device *sane_device;
 | |
| 
 | |
|       sane_device = malloc (sizeof (*sane_device));
 | |
|       if (sane_device == NULL)
 | |
| 	return SANE_STATUS_NO_MEM;
 | |
|       sane_device->name = strdup (device_name);
 | |
|       sane_device->vendor = strdup ("Mustek");
 | |
|       sane_device->model = strdup ("BearPaw 2448 TA Pro");
 | |
|       sane_device->type = strdup ("flatbed scanner");
 | |
|       devlist[dev_num++] = sane_device;
 | |
|     }
 | |
|   devlist[dev_num] = 0;
 | |
|   *device_list = devlist;
 | |
|   DBG (DBG_FUNC, "sane_get_devices: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_open (SANE_String_Const devicename, SANE_Handle * handle)
 | |
| {
 | |
|   Mustek_Scanner *s;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_open: start :devicename = %s\n", devicename);
 | |
| 
 | |
|   if (!MustScanner_Init ())
 | |
|     {
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   if (!PowerControl (SANE_FALSE, SANE_FALSE))
 | |
|     {
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   if (!CarriageHome ())
 | |
|     {
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
| 
 | |
|   s = malloc (sizeof (*s));
 | |
|   if (s == NULL)
 | |
|     return SANE_STATUS_NO_MEM;
 | |
|   memset (s, 0, sizeof (*s));
 | |
| 
 | |
|   s->gamma_table = NULL;
 | |
|   memcpy (&s->model, &mustek_A2nu2_model, sizeof (Scanner_Model));
 | |
|   s->next = NULL;
 | |
|   s->bIsScanning = SANE_FALSE;
 | |
|   s->bIsReading = SANE_FALSE;
 | |
| 
 | |
|   init_options (s);
 | |
|   *handle = s;
 | |
| 
 | |
|   s->read_rows = 0;
 | |
|   s->scan_buffer_len = 0;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_open: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| sane_close (SANE_Handle handle)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
|   DBG (DBG_FUNC, "sane_close: start\n");
 | |
| 
 | |
|   PowerControl (SANE_FALSE, SANE_FALSE);
 | |
| 
 | |
|   CarriageHome ();
 | |
| 
 | |
|   if (NULL != g_pDeviceFile)
 | |
|     {
 | |
|       free (g_pDeviceFile);
 | |
|       g_pDeviceFile = NULL;
 | |
|     }
 | |
| 
 | |
|   if (s->Scan_data_buf != NULL)
 | |
|     free (s->Scan_data_buf);
 | |
| 
 | |
|   s->Scan_data_buf = NULL;
 | |
| 
 | |
|   free (handle);
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_close: exit\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| const SANE_Option_Descriptor *
 | |
| sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
| 
 | |
|   if ((unsigned) option >= NUM_OPTIONS)
 | |
|     return 0;
 | |
|   DBG (DBG_FUNC, "sane_get_option_descriptor: option = %s (%d)\n",
 | |
|        s->opt[option].name, option);
 | |
|   return s->opt + option;
 | |
| }
 | |
| 
 | |
| 
 | |
| SANE_Status
 | |
| sane_control_option (SANE_Handle handle, SANE_Int option,
 | |
| 		     SANE_Action action, void *val, SANE_Int * info)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
|   SANE_Status status;
 | |
|   SANE_Word cap;
 | |
|   SANE_Int myinfo = 0;
 | |
| 
 | |
|   DBG (DBG_FUNC,
 | |
|        "sane_control_option: start: action = %s, option = %s (%d)\n",
 | |
|        (action == SANE_ACTION_GET_VALUE) ? "get" : (action ==
 | |
| 						    SANE_ACTION_SET_VALUE) ?
 | |
|        "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown",
 | |
|        s->opt[option].name, option);
 | |
| 
 | |
| 
 | |
|   if (info)
 | |
|     *info = 0;
 | |
| 
 | |
|   if (s->bIsScanning)
 | |
|     {
 | |
|       DBG (DBG_ERR, "sane_control_option: don't call this function while "
 | |
| 	   "scanning\n");
 | |
|       return SANE_STATUS_DEVICE_BUSY;
 | |
|     }
 | |
|   if (option >= NUM_OPTIONS || option < 0)
 | |
|     {
 | |
|       DBG (DBG_ERR,
 | |
| 	   "sane_control_option: option %d >= NUM_OPTIONS || option < 0\n",
 | |
| 	   option);
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
| 
 | |
|   cap = s->opt[option].cap;
 | |
|   if (!SANE_OPTION_IS_ACTIVE (cap))
 | |
|     {
 | |
|       DBG (DBG_ERR, "sane_control_option: option %d is inactive\n", option);
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   if (action == SANE_ACTION_GET_VALUE)
 | |
|     {
 | |
|       switch (option)
 | |
| 	{
 | |
| 	  /* word options: */
 | |
| 	case OPT_NUM_OPTS:
 | |
| 	case OPT_RESOLUTION:
 | |
| 	case OPT_PREVIEW:
 | |
| 	case OPT_AUTO_WARMUP:
 | |
| 	case OPT_GAMMA_VALUE:
 | |
| 	case OPT_THRESHOLD:
 | |
| 	case OPT_TL_X:
 | |
| 	case OPT_TL_Y:
 | |
| 	case OPT_BR_X:
 | |
| 	case OPT_BR_Y:
 | |
| 	  *(SANE_Word *) val = s->val[option].w;
 | |
| 	  break;
 | |
| 	  /* string options: */
 | |
| 	case OPT_MODE:
 | |
| 	  strcpy (val, s->val[option].s);
 | |
| 	  break;
 | |
| 
 | |
| 	case OPT_SOURCE:
 | |
| 	  strcpy (val, s->val[option].s);
 | |
| 	  break;
 | |
| 	default:
 | |
| 	  DBG (DBG_ERR, "sane_control_option: can't get unknown option %d\n",
 | |
| 	       option);
 | |
| 	  ;
 | |
| 	}
 | |
|     }
 | |
|   else if (action == SANE_ACTION_SET_VALUE)
 | |
|     {
 | |
|       if (!SANE_OPTION_IS_SETTABLE (cap))
 | |
| 	{
 | |
| 	  DBG (DBG_ERR, "sane_control_option: option %d is not settable\n",
 | |
| 	       option);
 | |
| 	  return SANE_STATUS_INVAL;
 | |
| 	}
 | |
| 
 | |
|       status = sanei_constrain_value (s->opt + option, val, &myinfo);
 | |
|       if (status != SANE_STATUS_GOOD)
 | |
| 	{
 | |
| 	  DBG (2, "sane_control_option: sanei_constrain_value returned %s\n",
 | |
| 	       sane_strstatus (status));
 | |
| 	  return status;
 | |
| 	}
 | |
| 
 | |
|       switch (option)
 | |
| 	{
 | |
| 	  /* (mostly) side-effect-free word options: */
 | |
| 	case OPT_RESOLUTION:
 | |
| 	case OPT_PREVIEW:
 | |
| 	case OPT_TL_X:
 | |
| 	case OPT_TL_Y:
 | |
| 	case OPT_BR_X:
 | |
| 	case OPT_BR_Y:
 | |
| 	  s->val[option].w = *(SANE_Word *) val;
 | |
| 	  RIE (calc_parameters (s));
 | |
| 	  myinfo |= SANE_INFO_RELOAD_PARAMS;
 | |
| 	  break;
 | |
| 	case OPT_THRESHOLD:
 | |
| 	case OPT_AUTO_WARMUP:
 | |
| 	case OPT_GAMMA_VALUE:
 | |
| 	  s->val[option].w = *(SANE_Word *) val;
 | |
| 	  break;
 | |
| 	  /* side-effect-free word-array options: */
 | |
| 	case OPT_MODE:
 | |
| 	  if (s->val[option].s)
 | |
| 	    free (s->val[option].s);
 | |
| 	  s->val[option].s = strdup (val);
 | |
| 	  if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) == 0)
 | |
| 	    {
 | |
| 	      ENABLE (OPT_THRESHOLD);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      DISABLE (OPT_THRESHOLD);
 | |
| 	    }
 | |
| 	  RIE (calc_parameters (s));
 | |
| 	  myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 | |
| 	  break;
 | |
| 	case OPT_SOURCE:
 | |
| 	  if (strcmp (s->val[option].s, val) != 0)
 | |
| 	    {			/* something changed */
 | |
| 	      if (s->val[option].s)
 | |
| 		free (s->val[option].s);
 | |
| 	      s->val[option].s = strdup (val);
 | |
| 	      if (strcmp (s->val[option].s, "Reflective") == 0)
 | |
| 		{
 | |
| 		  PowerControl (SANE_TRUE, SANE_FALSE);
 | |
| 		  s->opt[OPT_MODE].size = max_string_size (mode_list);
 | |
| 		  s->opt[OPT_MODE].constraint.string_list = mode_list;
 | |
| 		  s->val[OPT_MODE].s = strdup ("Color24");
 | |
| 		  x_range.max = s->model.x_size;
 | |
| 		  y_range.max = s->model.y_size;
 | |
| 		}
 | |
| 	      else if (0 == strcmp (s->val[option].s, "Negative"))
 | |
| 		{
 | |
| 		  PowerControl (SANE_FALSE, SANE_TRUE);
 | |
| 		  s->opt[OPT_MODE].size =
 | |
| 		    max_string_size (negative_mode_list);
 | |
| 		  s->opt[OPT_MODE].constraint.string_list =
 | |
| 		    negative_mode_list;
 | |
| 		  s->val[OPT_MODE].s = strdup ("Color24");
 | |
| 		  x_range.max = s->model.x_size_ta;
 | |
| 		  y_range.max = s->model.y_size_ta;
 | |
| 		}
 | |
| 	      else if (0 == strcmp (s->val[option].s, "Positive"))
 | |
| 		{
 | |
| 		  PowerControl (SANE_FALSE, SANE_TRUE);
 | |
| 		  s->opt[OPT_MODE].size = max_string_size (mode_list);
 | |
| 		  s->opt[OPT_MODE].constraint.string_list = mode_list;
 | |
| 		  s->val[OPT_MODE].s = strdup ("Color24");
 | |
| 		  x_range.max = s->model.x_size_ta;
 | |
| 		  y_range.max = s->model.y_size_ta;
 | |
| 		}
 | |
| 	    }
 | |
| 	  myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 | |
| 	  break;
 | |
| 	default:
 | |
| 	  DBG (DBG_ERR, "sane_control_option: can't set unknown option %d\n",
 | |
| 	       option);
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       DBG (DBG_ERR, "sane_control_option: unknown action %d for option %d\n",
 | |
| 	   action, option);
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   if (info)
 | |
|     *info = myinfo;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_control_option: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_get_parameters: start\n");
 | |
| 
 | |
|   DBG (DBG_INFO, "sane_get_parameters :params.format = %d\n",
 | |
|        s->params.format);
 | |
| 
 | |
|   DBG (DBG_INFO, "sane_get_parameters :params.depth = %d\n", s->params.depth);
 | |
|   DBG (DBG_INFO, "sane_get_parameters :params.pixels_per_line = %d\n",
 | |
|        s->params.pixels_per_line);
 | |
|   DBG (DBG_INFO, "sane_get_parameters :params.bytes_per_line = %d\n",
 | |
|        s->params.bytes_per_line);
 | |
|   DBG (DBG_INFO, "sane_get_parameters :params.lines = %d\n", s->params.lines);
 | |
|   if (params != NULL)
 | |
|     *params = s->params;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_get_parameters: exit\n");
 | |
| 
 | |
|   return SANE_STATUS_GOOD;
 | |
| 
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_start (SANE_Handle handle)
 | |
| {
 | |
|   int i;
 | |
|   Mustek_Scanner *s = handle;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_start: start\n");
 | |
| 
 | |
|   s->scan_buffer_len = 0;
 | |
| 
 | |
|   calc_parameters (s);
 | |
| 
 | |
|   if (s->val[OPT_TL_X].w >= s->val[OPT_BR_X].w)
 | |
|     {
 | |
|       DBG (DBG_CRIT,
 | |
| 	   "sane_start: top left x >= bottom right x --- exiting\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   if (s->val[OPT_TL_Y].w >= s->val[OPT_BR_Y].w)
 | |
|     {
 | |
|       DBG (DBG_CRIT,
 | |
| 	   "sane_start: top left y >= bottom right y --- exiting\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
| 
 | |
|   s->setpara.pGammaTable = NULL;
 | |
| 
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.fmArea.x1=%d\n",
 | |
|        s->setpara.fmArea.x1);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.fmArea.x2=%d\n",
 | |
|        s->setpara.fmArea.x2);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.fmArea.y1=%d\n",
 | |
|        s->setpara.fmArea.y1);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.fmArea.y2=%d\n",
 | |
|        s->setpara.fmArea.y2);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.pfPixelFlavor=%d\n",
 | |
|        s->setpara.pfPixelFlavor);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.wLinearThreshold=%d\n",
 | |
|        s->setpara.wLinearThreshold);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.wTargetDPI=%d\n",
 | |
|        s->setpara.wTargetDPI);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.smScanMode=%d\n",
 | |
|        s->setpara.smScanMode);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.ssScanSource =%d\n",
 | |
|        s->setpara.ssScanSource);
 | |
|   DBG (DBG_INFO, "Sane_start:setpara ,setpara.pGammaTable =%p\n",
 | |
|        (void *) s->setpara.pGammaTable);
 | |
| 
 | |
|   SetParameters (&s->setpara);
 | |
| 
 | |
|   GetParameters (&s->getpara);
 | |
| 
 | |
|   switch (s->params.format)
 | |
|     {
 | |
|     case SANE_FRAME_RGB:
 | |
|       if (s->params.depth == 8)
 | |
| 
 | |
| 	s->params.pixels_per_line = s->getpara.dwLineByteWidth / 3;
 | |
|       if (s->params.depth == 16)
 | |
| 	s->params.pixels_per_line = s->getpara.dwLineByteWidth / 6;
 | |
| 
 | |
| 
 | |
|       break;
 | |
|     case SANE_FRAME_GRAY:
 | |
|       if (s->params.depth == 1)
 | |
| 	s->params.pixels_per_line = s->getpara.dwLineByteWidth * 8;
 | |
|       if (s->params.depth == 8)
 | |
| 	s->params.pixels_per_line = s->getpara.dwLineByteWidth;
 | |
|       if (s->params.depth == 16)
 | |
| 	s->params.pixels_per_line = s->getpara.dwLineByteWidth / 2;
 | |
|       break;
 | |
|     default:
 | |
|       DBG (DBG_INFO, "sane_start: sane_params.format = %d\n",
 | |
| 	   s->params.format);
 | |
|     }
 | |
| 
 | |
|   s->params.bytes_per_line = s->getpara.dwLineByteWidth;
 | |
|   s->params.lines = s->getpara.dwLength;
 | |
| 
 | |
|   s->params.last_frame = TRUE;
 | |
| 
 | |
| 
 | |
|   s->read_rows = s->getpara.dwLength;
 | |
|   DBG (DBG_INFO, "sane_start : read_rows = %d\n", s->read_rows);
 | |
| 
 | |
|   /*warmming up */
 | |
|   if (s->val[OPT_AUTO_WARMUP].w)
 | |
|     {
 | |
|       for (i = 30; i > 0; i--)
 | |
| 	{
 | |
| 	  sleep (1);
 | |
| 	  DBG (DBG_ERR, "warming up: %d\n", i);
 | |
| 	}
 | |
|     }
 | |
|   DBG (DBG_INFO, "SCANNING ... \n");
 | |
| 
 | |
|   s->bIsScanning = SANE_TRUE;
 | |
|   if (s->Scan_data_buf != NULL)
 | |
|     free (s->Scan_data_buf);
 | |
|   s->Scan_data_buf = NULL;
 | |
| 
 | |
|   s->Scan_data_buf = malloc (SCAN_BUFFER_SIZE * sizeof (SANE_Byte));
 | |
|   if (s->Scan_data_buf == NULL)
 | |
|     return SANE_STATUS_NO_MEM;
 | |
| 
 | |
|   StartScan ();
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_start: exit\n");
 | |
| 
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
 | |
| 	   SANE_Int * len)
 | |
| {
 | |
| 
 | |
|   Mustek_Scanner *s = handle;
 | |
|   static SANE_Byte *tempbuf;
 | |
|   SANE_Int lines_to_read, lines_read;
 | |
|   IMAGEROWS image_row;
 | |
| 
 | |
|   int maxbuffersize = max_len;
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_read: start: max_len=%d\n", max_len);
 | |
| 
 | |
|   if (s == NULL)
 | |
|     {
 | |
|       DBG (DBG_ERR, "sane_read: handle is null!\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
| 
 | |
|   if (buf == NULL)
 | |
|     {
 | |
|       DBG (DBG_ERR, "sane_read: buf is null!\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
| 
 | |
|   if (len == NULL)
 | |
|     {
 | |
|       DBG (DBG_ERR, "sane_read: len is null!\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   *len = 0;
 | |
|   if (!s->bIsScanning)
 | |
|     {
 | |
|       DBG (DBG_WARN, "sane_read: scan was cancelled, is over or has not been "
 | |
| 	   "initiated yet\n");
 | |
|       return SANE_STATUS_CANCELLED;
 | |
|     }
 | |
|   DBG (DBG_DBG, "sane_read: before read data read_row=%d\n", s->read_rows);
 | |
|   if (s->scan_buffer_len == 0)
 | |
|     {
 | |
|       if (s->read_rows > 0)
 | |
| 	{
 | |
| 	  lines_to_read = SCAN_BUFFER_SIZE / s->getpara.dwLineByteWidth;
 | |
| 
 | |
| 	  if (lines_to_read > s->read_rows)
 | |
| 	    lines_to_read = s->read_rows;
 | |
| 
 | |
| 	  tempbuf =
 | |
| 	    (SANE_Byte *) malloc (sizeof (SANE_Byte) * lines_to_read *
 | |
| 			     s->getpara.dwLineByteWidth + 3 * 1024 + 1);
 | |
| 	  memset (tempbuf, 0,
 | |
| 		  sizeof (SANE_Byte) * lines_to_read * s->getpara.dwLineByteWidth +
 | |
| 		  3 * 1024 + 1);
 | |
| 
 | |
| 	  DBG (DBG_INFO, "sane_read: buffer size is %ld\n",
 | |
| 	       (long int) sizeof (SANE_Byte) * lines_to_read * s->getpara.dwLineByteWidth +
 | |
| 	       3 * 1024 + 1);
 | |
| 
 | |
| 	  image_row.roRgbOrder = mustek_A2nu2_model.line_mode_color_order;
 | |
| 	  image_row.wWantedLineNum = lines_to_read;
 | |
| 	  image_row.pBuffer = (SANE_Byte *) tempbuf;
 | |
| 	  s->bIsReading = SANE_TRUE;
 | |
| 
 | |
| 	  if (!ReadScannedData (&image_row))
 | |
| 	    {
 | |
| 	      DBG (DBG_ERR, "sane_read: ReadScannedData error\n");
 | |
| 	      s->bIsReading = SANE_FALSE;
 | |
| 	      return SANE_STATUS_INVAL;
 | |
| 	    }
 | |
| 
 | |
| 	  DBG (DBG_DBG, "sane_read: Finish ReadScanedData\n");
 | |
| 	  s->bIsReading = SANE_FALSE;
 | |
| 	  memset (s->Scan_data_buf, 0, SCAN_BUFFER_SIZE);
 | |
| 	  s->scan_buffer_len =
 | |
| 	    image_row.wXferedLineNum * s->getpara.dwLineByteWidth;
 | |
| 	  DBG (DBG_INFO, "sane_read : s->scan_buffer_len = %ld\n",
 | |
| 	       (long int) s->scan_buffer_len);
 | |
| 
 | |
| 	  memcpy (s->Scan_data_buf, tempbuf, s->scan_buffer_len);
 | |
| 
 | |
| 	  DBG (DBG_DBG, "sane_read :after memcpy\n");
 | |
| 	  free (tempbuf);
 | |
| 	  s->Scan_data_buf_start = s->Scan_data_buf;
 | |
| 	  s->read_rows -= image_row.wXferedLineNum;
 | |
| 
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  DBG (DBG_FUNC, "sane_read: scan finished -- exit\n");
 | |
| 	  sane_cancel (handle);
 | |
| 	  return SANE_STATUS_EOF;
 | |
| 	}
 | |
|     }
 | |
|   if (s->scan_buffer_len == 0)
 | |
|     {
 | |
|       DBG (DBG_FUNC, "sane_read: scan finished -- exit\n");
 | |
|       sane_cancel (handle);
 | |
|       return SANE_STATUS_EOF;
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|   lines_read =
 | |
|     (maxbuffersize <
 | |
|      (SANE_Int) s->scan_buffer_len) ? maxbuffersize : (SANE_Int) s->scan_buffer_len;
 | |
|   DBG (DBG_DBG, "sane_read: after %d\n", lines_read);
 | |
| 
 | |
|   *len = (SANE_Int) lines_read;
 | |
| 
 | |
|   DBG (DBG_INFO, "sane_read : get lines_read = %d\n", lines_read);
 | |
|   DBG (DBG_INFO, "sane_read : get *len = %d\n", *len);
 | |
|   memcpy (buf, s->Scan_data_buf_start, lines_read);
 | |
| 
 | |
|   s->scan_buffer_len -= lines_read;
 | |
|   s->Scan_data_buf_start += lines_read;
 | |
|   DBG (DBG_FUNC, "sane_read: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| 
 | |
| }
 | |
| 
 | |
| void
 | |
| sane_cancel (SANE_Handle handle)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
|   int i;
 | |
|   DBG (DBG_FUNC, "sane_cancel: start\n");
 | |
|   if (s->bIsScanning)
 | |
|     {
 | |
|       s->bIsScanning = SANE_FALSE;
 | |
|       if (s->read_rows > 0)
 | |
| 	{
 | |
| 	  DBG (DBG_INFO, "sane_cancel: warning: is scanning\n");
 | |
| 
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  DBG (DBG_INFO, "sane_cancel: Scan finished\n");
 | |
| 	}
 | |
| 
 | |
|       StopScan ();
 | |
| 
 | |
|       CarriageHome ();
 | |
|       for (i = 0; i < 20; i++)
 | |
| 	{
 | |
| 	  if (s->bIsReading == SANE_FALSE)
 | |
| 	    {
 | |
| 	      if (s->gamma_table != NULL)
 | |
| 		{
 | |
| 		  free (s->gamma_table);
 | |
| 		  s->gamma_table = NULL;
 | |
| 		  break;
 | |
| 		}
 | |
| 	    }
 | |
| 	  else
 | |
| 	    sleep (1);
 | |
| 	}
 | |
|       if (s->Scan_data_buf != NULL)
 | |
| 	{
 | |
| 	  free (s->Scan_data_buf);
 | |
| 	  s->Scan_data_buf = NULL;
 | |
| 	  s->Scan_data_buf_start = NULL;
 | |
| 	}
 | |
| 
 | |
|       s->read_rows = 0;
 | |
|       s->scan_buffer_len = 0;
 | |
|       memset (&s->setpara, 0, sizeof (s->setpara));
 | |
|       memset (&s->getpara, 0, sizeof (s->getpara));
 | |
| 
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       DBG (DBG_INFO, "sane_cancel: do nothing\n");
 | |
|     }
 | |
| 
 | |
| 
 | |
|   DBG (DBG_FUNC, "sane_cancel: exit\n");
 | |
| 
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
|   DBG (DBG_FUNC, "sane_set_io_mode: handle = %p, non_blocking = %s\n",
 | |
|        handle, non_blocking == SANE_TRUE ? "true" : "false");
 | |
|   if (!s->bIsScanning)
 | |
|     {
 | |
|       DBG (DBG_WARN, "sane_set_io_mode: not scanning\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   if (non_blocking)
 | |
|     return SANE_STATUS_UNSUPPORTED;
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
 | |
| {
 | |
|   Mustek_Scanner *s = handle;
 | |
|   DBG (DBG_FUNC, "sane_get_select_fd: handle = %p, fd = %p\n", handle,
 | |
|        (void *) fd);
 | |
|   if (!s->bIsScanning)
 | |
|     {
 | |
|       DBG (DBG_WARN, "%s", "sane_get_select_fd: not scanning\n");
 | |
|       return SANE_STATUS_INVAL;
 | |
|     }
 | |
|   return SANE_STATUS_UNSUPPORTED;
 | |
| }
 |