1 /* sane - Scanner Access Now Easy.
2 
3    pieusb_specific.c
4 
5    Copyright (C) 2012-2015 Jan Vleeshouwers, Michael Rickmann, Klaus Kaempf
6 
7    This file is part of the SANE package.
8 
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2 of the
12    License, or (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <https://www.gnu.org/licenses/>.
21 
22    As a special exception, the authors of SANE give permission for
23    additional uses of the libraries contained in this release of SANE.
24 
25    The exception is that, if you link a SANE library with other files
26    to produce an executable, this does not by itself cause the
27    resulting executable to be covered by the GNU General Public
28    License.  Your use of that executable is in no way restricted on
29    account of linking the SANE library code into it.
30 
31    This exception does not, however, invalidate any other reasons why
32    the executable file might be covered by the GNU General Public
33    License.
34 
35    If you submit changes to SANE to the maintainers to be included in
36    a subsequent release, you agree by submitting the changes that
37    those changes may be distributed with this exception intact.
38 
39    If you write modifications of your own for SANE, it is your choice
40    whether to permit this exception to apply to your modifications.
41    If you do not wish that, delete this exception notice.  */
42 
43 /* =========================================================================
44  *
45  * Various Pieusb backend specific functions
46  *
47  * Option handling, configuration file handling, post-processing
48  *
49  * ========================================================================= */
50 
51 #define DEBUG_DECLARE_ONLY
52 #include "pieusb.h"
53 
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <string.h>
57 #include "../include/sane/sane.h"
58 #include "../include/sane/saneopts.h"
59 #include "../include/sane/sanei_config.h"
60 
61 #include <errno.h>
62 #include <math.h>
63 #include <time.h>
64 
65 #include "pieusb_usb.h"
66 #include "pieusb_scancmd.h"
67 #include "pieusb_buffer.h"
68 #include "pieusb_specific.h"
69 
70 /* Pieusb specific */
71 
72 /* sub to sanei_pieusb_find_device_callback() */
73 static SANE_Status pieusb_initialize_device_definition (Pieusb_Device_Definition* dev, Pieusb_Scanner_Properties* inq, const char* devicename, SANE_Word vendor_id, SANE_Word product_id);
74 static void pieusb_print_inquiry (Pieusb_Device_Definition * dev);
75 
76 /* sub to sane_start() */
77 static void pieusb_calculate_shading(struct Pieusb_Scanner *scanner, SANE_Byte* buffer);
78 
79 /* MR */
80 /* sub to sanei_pieusb_post() */
81 static SANE_Status pieusb_write_pnm_file (char *filename, uint16_t *data, int depth, int channels, int pixels_per_line, int lines);
82 
83 /* Auxiliary */
84 static size_t max_string_size (SANE_String_Const const strings[]);
85 static double getGain(int gain);
86 static int getGainSetting(double gain);
87 /*
88 static void updateGain(Pieusb_Scanner *scanner, int color_index);
89 */
90 static void updateGain2(Pieusb_Scanner *scanner, int color_index, double gain_increase);
91 
92 /* --------------------------------------------------------------------------
93  *
94  * SPECIFIC PIEUSB
95  *
96  * --------------------------------------------------------------------------*/
97 
98 /* Settings for byte order */
99 #define SCAN_IMG_FMT_OKLINE          0x08
100 #define SCAN_IMG_FMT_BLK_ONE         0x04
101 #define SCAN_IMG_FMT_MOTOROLA        0x02
102 #define SCAN_IMG_FMT_INTEL           0x01
103 
104 /* Settings for scanner capabilities */
105 #define SCAN_CAP_PWRSAV              0x80
106 #define SCAN_CAP_EXT_CAL             0x40
107 #define SCAN_CAP_FAST_PREVIEW        0x10
108 #define SCAN_CAP_DISABLE_CAL         0x08
109 #define SCAN_CAP_SPEEDS              0x07
110 
111 /* Available scanner options */
112 #define SCAN_OPT_DEV_MPCL            0x80
113 #define SCAN_OPT_DEV_TP1             0x04
114 #define SCAN_OPT_DEV_TP              0x02
115 #define SCAN_OPT_DEV_ADF             0x01
116 
117 /* Options */
118 #define SANE_NAME_EXPOSURE_R         "exposure-time-r"
119 #define SANE_TITLE_EXPOSURE_R        "Exposure time red"
120 #define SANE_DESC_EXPOSURE_R         "The time the red color filter of the CCD is exposed"
121 #define SANE_NAME_EXPOSURE_G         "exposure-time-g"
122 #define SANE_TITLE_EXPOSURE_G        "Exposure time green"
123 #define SANE_DESC_EXPOSURE_G         "The time the green color filter of the CCD is exposed"
124 #define SANE_NAME_EXPOSURE_B         "exposure-time-b"
125 #define SANE_TITLE_EXPOSURE_B        "Exposure time blue"
126 #define SANE_DESC_EXPOSURE_B         "The time the blue color filter of the CCD is exposed"
127 #define SANE_NAME_EXPOSURE_I         "exposure-time-i"
128 #define SANE_TITLE_EXPOSURE_I        "Exposure time infrared"
129 #define SANE_DESC_EXPOSURE_I         "The time the infrared color filter of the CCD is exposed"
130 #define SANE_EXPOSURE_DEFAULT        DEFAULT_EXPOSURE
131 #if 1
132 #define SANE_NAME_GAIN_R               "gain-r"
133 #define SANE_TITLE_GAIN_R              "Gain red"
134 #define SANE_DESC_GAIN_R               "The gain of the signal processor for red"
135 #define SANE_NAME_GAIN_G               "gain-g"
136 #define SANE_TITLE_GAIN_G              "Gain green"
137 #define SANE_DESC_GAIN_G               "The gain of the signal processor for green"
138 #define SANE_NAME_GAIN_B               "gain-b"
139 #define SANE_TITLE_GAIN_B              "Gain blue"
140 #define SANE_DESC_GAIN_B               "The gain of the signal processor for blue"
141 #define SANE_NAME_GAIN_I               "gain-i"
142 #define SANE_TITLE_GAIN_I              "Gain infrared"
143 #define SANE_DESC_GAIN_I               "The gain of the signal processor for infrared"
144 #define SANE_GAIN_DEFAULT            DEFAULT_GAIN
145 
146 #define SANE_NAME_OFFSET_R             "offset-r"
147 #define SANE_TITLE_OFFSET_R            "Offset red"
148 #define SANE_DESC_OFFSET_R             "The offset of the signal processor for red"
149 #define SANE_NAME_OFFSET_G             "offset-g"
150 #define SANE_TITLE_OFFSET_G            "Offset greed"
151 #define SANE_DESC_OFFSET_G             "The offset of the signal processor for green"
152 #define SANE_NAME_OFFSET_B             "offset-b"
153 #define SANE_TITLE_OFFSET_B            "Offset blue"
154 #define SANE_DESC_OFFSET_B             "The offset of the signal processor for blue"
155 #define SANE_NAME_OFFSET_I             "offset-i"
156 #define SANE_TITLE_OFFSET_I            "Offset infrared"
157 #define SANE_DESC_OFFSET_I             "The offset of the signal processor for infrared"
158 #define SANE_OFFSET_DEFAULT          DEFAULT_OFFSET
159 #else
160 #define SANE_NAME_GAIN               "gain"
161 #define SANE_TITLE_GAIN              "Gain"
162 #define SANE_DESC_GAIN               "The gain of the signal processor for the 4 CCD color filters (R,G,B,I)"
163 #define SANE_GAIN_DEFAULT            0x13
164 
165 #define SANE_NAME_OFFSET             "offset"
166 #define SANE_TITLE_OFFSET            "Offset"
167 #define SANE_DESC_OFFSET             "The offset of the signal processor for the 4 CCD color filters (R,G,B,I)"
168 #define SANE_OFFSET_DEFAULT          0
169 #endif
170 #define min(a,b) (((a)<(b))?(a):(b))
171 #define max(a,b) (((a)>(b))?(a):(b))
172 
173 static const SANE_Range percentage_range_100 = {
174   0 << SANE_FIXED_SCALE_SHIFT,	  /* minimum */
175   100 << SANE_FIXED_SCALE_SHIFT,  /* maximum */
176   0 << SANE_FIXED_SCALE_SHIFT	  /* quantization */
177 };
178 
179 /* From the firmware disassembly */
180 static const SANE_Range gain_range = {
181   0,	  /* minimum */
182   63,     /* maximum */
183   0	  /* quantization */
184 };
185 
186 /* From the firmware disassembly */
187 static const SANE_Range offset_range = {
188   0,      /* minimum */
189   255,    /* maximum */
190   0	  /* quantization */
191 };
192 
193 static const double gains[] = {
194 1.000, 1.075, 1.154, 1.251, 1.362, 1.491, 1.653, /*  0,  5, 10, 15, 20, 25, 30 */
195 1.858, 2.115, 2.458, 2.935, 3.638, 4.627         /* 35, 40, 45, 50, 55, 60 */
196 };
197 
198 /**
199  * Callback called whenever a connected USB device reports a supported vendor
200  * and product id combination.
201  * Used by sane_init() and by sane_open().
202  *
203  * @param name Device name which has required vendor and product id
204  * @return SANE_STATUS_GOOD
205  */
206 SANE_Status
sanei_pieusb_find_device_callback(const char *devicename)207 sanei_pieusb_find_device_callback (const char *devicename)
208 {
209     struct Pieusb_Command_Status status;
210     SANE_Status r;
211     Pieusb_Device_Definition *dev;
212     int device_number; /* index in usb devices list maintained by sani_usb */
213     Pieusb_Scanner_Properties inq;
214     int retry;
215 
216     DBG (DBG_info_proc, "sanei_pieusb_find_device_callback: %s\n", devicename);
217 
218     /* Check if device is present in the Pieusb device list */
219     for (dev = pieusb_definition_list_head; dev; dev = dev->next) {
220         if (strcmp (dev->sane.name, devicename) == 0) {
221 	    return SANE_STATUS_GOOD;
222         }
223     }
224 
225     /* If not, create a new device struct */
226     dev = malloc (sizeof (*dev));
227     if (!dev) {
228         return SANE_STATUS_NO_MEM;
229     }
230 
231     /* Get device number: index of the device in the sanei_usb devices list */
232     r = sanei_usb_open (devicename, &device_number);
233     if (r != SANE_STATUS_GOOD) {
234         free (dev);
235         DBG (DBG_error, "sanei_pieusb_find_device_callback: sanei_usb_open failed for device %s: %s\n",devicename,sane_strstatus(r));
236         return r;
237     }
238 
239     /* Get device properties */
240 
241     retry = 2;
242     while (retry > 0) {
243       retry--;
244       /* get inquiry data length */
245       sanei_pieusb_cmd_inquiry (device_number, &inq, 5, &status);
246       if (status.pieusb_status == PIEUSB_STATUS_GOOD) {
247 	break;
248       }
249       else if (status.pieusb_status == PIEUSB_STATUS_IO_ERROR) {
250 	if (retry > 0) {
251 	  DBG (DBG_info_proc, "inquiry failed, resetting usb\n");
252 	  if (sanei_pieusb_usb_reset(device_number) == SANE_STATUS_GOOD) {
253 	    continue; /* retry after IEEE1284 reset */
254 	  }
255 	  if (sanei_usb_reset(device_number) == SANE_STATUS_GOOD) {
256 	    continue; /* retry after USB reset */
257 	  }
258 	}
259       }
260       free (dev);
261       DBG (DBG_error, "sanei_pieusb_find_device_callback: get scanner properties (5 bytes) failed with %d\n", status.pieusb_status);
262       sanei_usb_close (device_number);
263       return sanei_pieusb_convert_status (status.pieusb_status);
264     }
265     /* get full inquiry data */
266     sanei_pieusb_cmd_inquiry(device_number, &inq, inq.additionalLength+4, &status);
267     if (status.pieusb_status != PIEUSB_STATUS_GOOD) {
268         free (dev);
269         DBG (DBG_error, "sanei_pieusb_find_device_callback: get scanner properties failed\n");
270         sanei_usb_close (device_number);
271         return sanei_pieusb_convert_status (status.pieusb_status);
272     }
273 
274     /* Close the device again */
275     sanei_usb_close(device_number);
276 
277     /* Initialize device definition */
278     r = pieusb_initialize_device_definition(dev, &inq, devicename, pieusb_supported_usb_device.vendor, pieusb_supported_usb_device.product);
279     if (r != SANE_STATUS_GOOD) {
280       return r;
281     }
282 
283     /* Output */
284     pieusb_print_inquiry (dev);
285 
286     /* Check model number */
287     if (inq.model != pieusb_supported_usb_device.model) {
288         free (dev);
289         DBG (DBG_error, "sanei_pieusb_find_device_callback: wrong model number %d\n", inq.model);
290         return SANE_STATUS_INVAL;
291     }
292 
293     dev->flags = pieusb_supported_usb_device.flags;
294 
295     /* Found a supported scanner, put it in the definitions list*/
296     DBG (DBG_info_proc, "sanei_pieusb_find_device_callback: success\n");
297     dev->next = pieusb_definition_list_head;
298     pieusb_definition_list_head = dev;
299     return SANE_STATUS_GOOD;
300 }
301 
302 /**
303  * Full initialization of a Pieusb_Device structure from INQUIRY data.
304  * The function is used in find_device_callback(), so when sane_init() or
305  * sane_open() is called.
306  *
307  * @param dev
308  */
309 static SANE_Status
pieusb_initialize_device_definition(Pieusb_Device_Definition* dev, Pieusb_Scanner_Properties* inq, const char* devicename, SANE_Word vendor_id, SANE_Word product_id)310 pieusb_initialize_device_definition (Pieusb_Device_Definition* dev, Pieusb_Scanner_Properties* inq, const char* devicename,
311         SANE_Word vendor_id, SANE_Word product_id)
312 {
313     char *pp, *buf;
314 
315     /* Initialize device definition */
316     dev->next = NULL;
317     dev->sane.name = strdup(devicename);
318 
319     /* Create 0-terminated string without trailing spaces for vendor */
320     buf = malloc(9);
321     if (buf == NULL)
322       return SANE_STATUS_NO_MEM;
323     memcpy(buf, inq->vendor, 8);
324     pp = buf + 8;
325     *pp-- = '\0';
326     while (*pp == ' ') *pp-- = '\0';
327     dev->sane.vendor = buf;
328 
329     /* Create 0-terminated string without trailing spaces for model */
330     buf = malloc(17);
331     if (buf == NULL)
332       return SANE_STATUS_NO_MEM;
333     memcpy(buf, inq->product, 16);
334     pp = buf + 16;
335     *pp-- = '\0';
336     while (*pp == ' ') *pp-- = '\0';
337     dev->sane.model = buf;
338 
339     dev->sane.type = "film scanner";
340     dev->vendorId = vendor_id;
341     dev->productId = product_id;
342 
343     /* Create 0-terminated strings without trailing spaces for revision */
344     buf = malloc(5);
345     if (buf == NULL)
346       return SANE_STATUS_NO_MEM;
347     memcpy(buf, inq->productRevision, 4);
348     pp = buf + 4;
349     *pp-- = '\0';
350     while (*pp == ' ') *pp-- = '\0';
351     dev->version = buf;
352 
353     dev->model = inq->model;
354 
355     /* Maximum resolution values */
356     dev->maximum_resolution_x = inq->maxResolutionX;
357     dev->maximum_resolution_y = inq->maxResolutionY;
358     if (dev->maximum_resolution_y < 256) {
359         /* y res is a multiplier */
360         dev->maximum_resolution = dev->maximum_resolution_x;
361         dev->maximum_resolution_x *= dev->maximum_resolution_y;
362         dev->maximum_resolution_y = dev->maximum_resolution_x;
363     } else {
364       /* y res really is resolution */
365       dev->maximum_resolution = min (dev->maximum_resolution_x, dev->maximum_resolution_y);
366     }
367 
368     /* Geometry */
369     dev->scan_bed_width = (double) inq->maxScanWidth / dev->maximum_resolution;
370     dev->scan_bed_height = (double) inq->maxScanHeight / dev->maximum_resolution;
371     dev->slide_top_left_x = inq->x0;
372     dev->slide_top_left_y = inq->y0;
373     dev->slide_width = (double) (inq->x1 - inq->x0) / dev->maximum_resolution;
374     dev->slide_height = (double) (inq->y1 - inq->y0) / dev->maximum_resolution;
375 
376     /* Integer and bit-encoded properties */
377     dev->halftone_patterns = inq->halftones & 0x0f;
378     dev->color_filters = inq->filters;
379     dev->color_depths = inq->colorDepths;
380     dev->color_formats = inq->colorFormat;
381     dev->image_formats = inq->imageFormat;
382     dev->scan_capabilities = inq->scanCapability;
383     dev->optional_devices = inq->optionalDevices;
384     dev->enhancements = inq->enhancements;
385     dev->gamma_bits = inq->gammaBits;
386     dev->fast_preview_resolution = inq->previewScanResolution;
387     dev->minimum_highlight = inq->minumumHighlight;
388     dev->maximum_shadow = inq->maximumShadow;
389     dev->calibration_equation = inq->calibrationEquation;
390     dev->minimum_exposure = inq->minimumExposure;
391     dev->maximum_exposure = inq->maximumExposure*4; /* *4 to solve the strange situation that the default value is out of range */
392 
393     dev->x0 = inq->x0;
394     dev->y0 = inq->y0;
395     dev->x1 = inq->x1;
396     dev->y1 = inq->y1;
397     dev->production = strndup(inq->production, 4);
398     dev->timestamp = strndup(inq->timestamp, 20);
399     dev->signature = (char *)strndup((char *)inq->signature, 40);
400 
401     /* Ranges for various quantities */
402     dev->x_range.min = SANE_FIX (0);
403     dev->x_range.quant = SANE_FIX (0);
404     dev->x_range.max = SANE_FIX (dev->scan_bed_width * MM_PER_INCH);
405 
406     dev->y_range.min = SANE_FIX (0);
407     dev->y_range.quant = SANE_FIX (0);
408     dev->y_range.max = SANE_FIX (dev->scan_bed_height * MM_PER_INCH);
409 
410     dev->dpi_range.min = SANE_FIX (25);
411     dev->dpi_range.quant = SANE_FIX (1);
412     dev->dpi_range.max = SANE_FIX (max (dev->maximum_resolution_x, dev->maximum_resolution_y));
413 
414     dev->shadow_range.min = SANE_FIX (0);
415     dev->shadow_range.quant = SANE_FIX (1);
416     dev->shadow_range.max = SANE_FIX (dev->maximum_shadow);
417 
418     dev->highlight_range.min = SANE_FIX (dev->minimum_highlight);
419     dev->highlight_range.quant = SANE_FIX (1);
420     dev->highlight_range.max = SANE_FIX (100);
421 
422     dev->exposure_range.min = dev->minimum_exposure;
423     dev->exposure_range.quant = 1;
424     dev->exposure_range.max = dev->maximum_exposure;
425 
426     dev->dust_range.min = 0;
427     dev->dust_range.quant = 1;
428     dev->dust_range.max = 100;
429 
430     /* Enumerated ranges vor various quantities */
431     /*TODO: create from inq->filters */
432     dev->scan_mode_list[0] = SANE_VALUE_SCAN_MODE_LINEART;
433     dev->scan_mode_list[1] = SANE_VALUE_SCAN_MODE_HALFTONE;
434     dev->scan_mode_list[2] = SANE_VALUE_SCAN_MODE_GRAY;
435     dev->scan_mode_list[3] = SANE_VALUE_SCAN_MODE_COLOR;
436     dev->scan_mode_list[4] = SANE_VALUE_SCAN_MODE_RGBI;
437     dev->scan_mode_list[5] = 0;
438 
439     dev->calibration_mode_list[0] = SCAN_CALIBRATION_DEFAULT;
440     dev->calibration_mode_list[1] = SCAN_CALIBRATION_AUTO;
441     dev->calibration_mode_list[2] = SCAN_CALIBRATION_PREVIEW;
442     dev->calibration_mode_list[3] = SCAN_CALIBRATION_OPTIONS;
443     dev->calibration_mode_list[4] = 0;
444 
445     dev->gain_adjust_list[0] = SCAN_GAIN_ADJUST_03;
446     dev->gain_adjust_list[1] = SCAN_GAIN_ADJUST_05;
447     dev->gain_adjust_list[2] = SCAN_GAIN_ADJUST_08;
448     dev->gain_adjust_list[3] = SCAN_GAIN_ADJUST_10;
449     dev->gain_adjust_list[4] = SCAN_GAIN_ADJUST_12;
450     dev->gain_adjust_list[5] = SCAN_GAIN_ADJUST_16;
451     dev->gain_adjust_list[6] = SCAN_GAIN_ADJUST_19;
452     dev->gain_adjust_list[7] = SCAN_GAIN_ADJUST_24;
453     dev->gain_adjust_list[8] = SCAN_GAIN_ADJUST_30;
454     dev->gain_adjust_list[9] = 0;
455 
456     /*TODO: create from inq->colorDepths? Maybe not: didn't experiment with
457      * 4 and 12 bit depths. Don;t know how they behave. */
458     dev->bpp_list[0] = 3; /* count */
459     dev->bpp_list[1] = 1;
460     dev->bpp_list[2] = 8;
461     dev->bpp_list[3] = 16;
462 
463     /* Infrared */
464     dev->ir_sw_list[0] = "None";
465     dev->ir_sw_list[1] = "Reduce red overlap";
466     dev->ir_sw_list[2] = "Remove dirt";
467     dev->ir_sw_list[3] = 0;
468 
469     dev->grain_sw_list[0] = 4;
470     dev->grain_sw_list[1] = 0;
471     dev->grain_sw_list[2] = 1;
472     dev->grain_sw_list[3] = 2;
473     dev->grain_sw_list[4] = 3;
474     dev->grain_sw_list[5] = 0;
475 
476     dev->crop_sw_list[0] = "None";
477     dev->crop_sw_list[1] = "Outside";
478     dev->crop_sw_list[2] = "Inside";
479     dev->crop_sw_list[3] = 0;
480 
481     /* halftone_list */
482     dev->halftone_list[0] = "53lpi 45d ROUND"; /* 8x8 pattern */
483     dev->halftone_list[1] = "70lpi 45d ROUND"; /* 6x6 pattern */
484     dev->halftone_list[2] = "75lpi Hori. Line"; /* 4x4 pattern */
485     dev->halftone_list[3] = "4X4 BAYER"; /* 4x4 pattern */
486     dev->halftone_list[4] = "4X4 SCROLL"; /* 4x4 pattern */
487     dev->halftone_list[5] = "5x5 26 Levels"; /* 5x5 pattern */
488     dev->halftone_list[6] = "4x4 SQUARE"; /* 4x4 pattern */
489     dev->halftone_list[7] = "5x5 TILE"; /* 5x5 pattern */
490     dev->halftone_list[8] = 0;
491 
492     return SANE_STATUS_GOOD;
493 }
494 
495 /**
496  * Output device definition.
497  * The function is used in find_device_callback(), so when sane_init() or
498  * sane_open() is called.
499  *
500  * @param dev Device to output
501  */
502 static void
pieusb_print_inquiry(Pieusb_Device_Definition * dev)503 pieusb_print_inquiry (Pieusb_Device_Definition * dev)
504 {
505   DBG (DBG_inquiry, "INQUIRY:\n");
506   DBG (DBG_inquiry, "========\n");
507   DBG (DBG_inquiry, "\n");
508   DBG (DBG_inquiry, "vendor........................: '%s'\n", dev->sane.vendor);
509   DBG (DBG_inquiry, "product.......................: '%s'\n", dev->sane.model);
510   DBG (DBG_inquiry, "model  .......................: 0x%04x\n", dev->model);
511   DBG (DBG_inquiry, "version.......................: '%s'\n", dev->version);
512 
513   DBG (DBG_inquiry, "X resolution..................: %d dpi\n",
514        dev->maximum_resolution_x);
515   DBG (DBG_inquiry, "Y resolution..................: %d dpi\n",
516        dev->maximum_resolution_y);
517   DBG (DBG_inquiry, "pixel resolution..............: %d dpi\n",
518        dev->maximum_resolution);
519   DBG (DBG_inquiry, "fb width......................: %f in\n",
520        dev->scan_bed_width);
521   DBG (DBG_inquiry, "fb length.....................: %f in\n",
522        dev->scan_bed_height);
523 
524   DBG (DBG_inquiry, "transparency width............: %f in\n",
525        dev->slide_width);
526   DBG (DBG_inquiry, "transparency length...........: %f in\n",
527        dev->slide_height);
528   DBG (DBG_inquiry, "transparency offset...........: %d,%d\n",
529        dev->slide_top_left_x, dev->slide_top_left_y);
530 
531   DBG (DBG_inquiry, "# of halftones................: %d\n",
532        dev->halftone_patterns);
533 
534   DBG (DBG_inquiry, "One pass color................: %s\n",
535        dev->color_filters & SCAN_ONE_PASS_COLOR ? "yes" : "no");
536 
537   DBG (DBG_inquiry, "Filters.......................: %s%s%s%s%s (%02x)\n",
538        dev->color_filters & SCAN_FILTER_INFRARED ? "Infrared " : "",
539        dev->color_filters & SCAN_FILTER_RED ? "Red " : "",
540        dev->color_filters & SCAN_FILTER_GREEN ? "Green " : "",
541        dev->color_filters & SCAN_FILTER_BLUE ? "Blue " : "",
542        dev->color_filters & SCAN_FILTER_NEUTRAL ? "Neutral " : "",
543        dev->color_filters);
544 
545   DBG (DBG_inquiry, "Color depths..................: %s%s%s%s%s%s (%02x)\n",
546        dev->color_depths & SCAN_COLOR_DEPTH_16 ? "16 bit " : "",
547        dev->color_depths & SCAN_COLOR_DEPTH_12 ? "12 bit " : "",
548        dev->color_depths & SCAN_COLOR_DEPTH_10 ? "10 bit " : "",
549        dev->color_depths & SCAN_COLOR_DEPTH_8 ? "8 bit " : "",
550        dev->color_depths & SCAN_COLOR_DEPTH_4 ? "4 bit " : "",
551        dev->color_depths & SCAN_COLOR_DEPTH_1 ? "1 bit " : "",
552        dev->color_depths);
553 
554   DBG (DBG_inquiry, "Color Format..................: %s%s%s (%02x)\n",
555        dev->color_formats & SCAN_COLOR_FORMAT_INDEX ? "Indexed " : "",
556        dev->color_formats & SCAN_COLOR_FORMAT_LINE ? "Line " : "",
557        dev->color_formats & SCAN_COLOR_FORMAT_PIXEL ? "Pixel " : "",
558        dev->color_formats);
559 
560   DBG (DBG_inquiry, "Image Format..................: %s%s%s%s (%02x)\n",
561        dev->image_formats & SCAN_IMG_FMT_OKLINE ? "OKLine " : "",
562        dev->image_formats & SCAN_IMG_FMT_BLK_ONE ? "BlackOne " : "",
563        dev->image_formats & SCAN_IMG_FMT_MOTOROLA ? "Motorola " : "",
564        dev->image_formats & SCAN_IMG_FMT_INTEL ? "Intel" : "",
565        dev->image_formats);
566 
567   DBG (DBG_inquiry,
568        "Scan Capability...............: %s%s%s%s%d speeds (%02x)\n",
569        dev->scan_capabilities & SCAN_CAP_PWRSAV ? "PowerSave " : "",
570        dev->scan_capabilities & SCAN_CAP_EXT_CAL ? "ExtCal " : "",
571        dev->scan_capabilities & SCAN_CAP_FAST_PREVIEW ? "FastPreview" :
572        "",
573        dev->scan_capabilities & SCAN_CAP_DISABLE_CAL ? "DisCal " : "",
574        dev->scan_capabilities & SCAN_CAP_SPEEDS,
575        dev->scan_capabilities);
576 
577   DBG (DBG_inquiry, "Optional Devices..............: %s%s%s%s (%02x)\n",
578        dev->optional_devices & SCAN_OPT_DEV_MPCL ? "MultiPageLoad " :
579        "",
580        dev->optional_devices & SCAN_OPT_DEV_TP1 ? "TransModule1 " : "",
581        dev->optional_devices & SCAN_OPT_DEV_TP ? "TransModule " : "",
582        dev->optional_devices & SCAN_OPT_DEV_ADF ? "ADF " : "",
583        dev->optional_devices);
584 
585   DBG (DBG_inquiry, "Enhancement...................: %02x\n",
586        dev->enhancements);
587   DBG (DBG_inquiry, "Gamma bits....................: %d\n",
588        dev->gamma_bits);
589 
590   DBG (DBG_inquiry, "Fast Preview Resolution.......: %d\n",
591        dev->fast_preview_resolution);
592   DBG (DBG_inquiry, "Min Highlight.................: %d\n",
593        dev->minimum_highlight);
594   DBG (DBG_inquiry, "Max Shadow....................: %d\n",
595        dev->maximum_shadow);
596   DBG (DBG_inquiry, "Cal Eqn.......................: %d\n",
597        dev->calibration_equation);
598   DBG (DBG_inquiry, "Min Exposure..................: %d\n",
599        dev->minimum_exposure);
600   DBG (DBG_inquiry, "Max Exposure..................: %d\n",
601        dev->maximum_exposure);
602 
603   DBG (DBG_inquiry, "x0,y0 x1,y1...................: %d,%d %d,%d\n",
604        dev->x0, dev->y0, dev->x1, dev->y1);
605   DBG (DBG_inquiry, "production....................: '%s'\n",
606        dev->production);
607   DBG (DBG_inquiry, "timestamp.....................: '%s'\n",
608        dev->timestamp);
609   DBG (DBG_inquiry, "signature.....................: '%s'\n",
610        dev->signature);
611 
612 }
613 
614 /**
615  * Initiaize scanner options from the device definition and from exposure,
616  * gain and offset defaults. The function is called by sane_open(), when no
617  * optimized settings are available yet. The scanner object is fully
618  * initialized in sane_start().
619  *
620  * @param scanner Scanner to initialize
621  * @return SANE_STATUS_GOOD
622  */
623 SANE_Status
sanei_pieusb_init_options(Pieusb_Scanner* scanner)624 sanei_pieusb_init_options (Pieusb_Scanner* scanner)
625 {
626     int i;
627 
628     DBG (DBG_info_proc, "sanei_pieusb_init_options\n");
629 
630     memset (scanner->opt, 0, sizeof (scanner->opt));
631     memset (scanner->val, 0, sizeof (scanner->val));
632 
633     for (i = 0; i < NUM_OPTIONS; ++i) {
634         scanner->opt[i].size = sizeof (SANE_Word);
635         scanner->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
636     }
637 
638     /* Number of options (a pseudo-option) */
639     scanner->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
640     scanner->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
641     scanner->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
642     scanner->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
643     scanner->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
644     scanner->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
645 
646     /* "Mode" group: */
647     scanner->opt[OPT_MODE_GROUP].title = "Scan Mode";
648     scanner->opt[OPT_MODE_GROUP].desc = "";
649     scanner->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
650     scanner->opt[OPT_MODE_GROUP].cap = 0;
651     scanner->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
652 
653     /* scan mode */
654     scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
655     scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
656     scanner->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
657     scanner->opt[OPT_MODE].type = SANE_TYPE_STRING;
658     scanner->opt[OPT_MODE].size = max_string_size ((SANE_String_Const const *) scanner->device->scan_mode_list);
659     scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
660     scanner->opt[OPT_MODE].constraint.string_list = (SANE_String_Const const *) scanner->device->scan_mode_list;
661     scanner->val[OPT_MODE].s = (SANE_Char *) strdup (scanner->device->scan_mode_list[3]); /* default RGB */
662 
663     /* bit depth */
664     scanner->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
665     scanner->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
666     scanner->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
667     scanner->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
668     scanner->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
669     scanner->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word);
670     scanner->opt[OPT_BIT_DEPTH].constraint.word_list = scanner->device->bpp_list;
671     scanner->val[OPT_BIT_DEPTH].w = scanner->device->bpp_list[2];
672 
673     /* resolution */
674     scanner->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
675     scanner->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
676     scanner->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
677     scanner->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
678     scanner->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
679     scanner->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
680     scanner->opt[OPT_RESOLUTION].constraint.range = &scanner->device->dpi_range;
681     scanner->val[OPT_RESOLUTION].w = scanner->device->fast_preview_resolution << SANE_FIXED_SCALE_SHIFT;
682 
683     /* halftone pattern */
684     scanner->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
685     scanner->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
686     scanner->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
687     scanner->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
688     scanner->opt[OPT_HALFTONE_PATTERN].size = max_string_size ((SANE_String_Const const *) scanner->device->halftone_list);
689     scanner->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST;
690     scanner->opt[OPT_HALFTONE_PATTERN].constraint.string_list = (SANE_String_Const const *) scanner->device->halftone_list;
691     scanner->val[OPT_HALFTONE_PATTERN].s = (SANE_Char *) strdup (scanner->device->halftone_list[6]);
692     scanner->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; /* Not implemented, and only meaningful at depth 1 */
693 
694     /* lineart threshold */
695     scanner->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
696     scanner->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
697     scanner->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
698     scanner->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
699     scanner->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
700     scanner->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
701     scanner->opt[OPT_THRESHOLD].constraint.range = &percentage_range_100;
702     scanner->val[OPT_THRESHOLD].w = SANE_FIX (50);
703     /* scanner->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; Not implemented, and only meaningful at depth 1 */
704 
705     /* create a sharper scan at the cost of scan time */
706     scanner->opt[OPT_SHARPEN].name = "sharpen";
707     scanner->opt[OPT_SHARPEN].title = "Sharpen scan";
708     scanner->opt[OPT_SHARPEN].desc = "Sharpen scan by taking more time to discharge the CCD.";
709     scanner->opt[OPT_SHARPEN].type = SANE_TYPE_BOOL;
710     scanner->opt[OPT_SHARPEN].unit = SANE_UNIT_NONE;
711     scanner->opt[OPT_SHARPEN].constraint_type = SANE_CONSTRAINT_NONE;
712     scanner->val[OPT_SHARPEN].b = SANE_FALSE;
713     scanner->opt[OPT_SHARPEN].cap |= SANE_CAP_SOFT_SELECT;
714 
715     /* skip the auto-calibration phase before the scan */
716     scanner->opt[OPT_SHADING_ANALYSIS].name = "shading-analysis";
717     scanner->opt[OPT_SHADING_ANALYSIS].title = "Perform shading analysis";
718     scanner->opt[OPT_SHADING_ANALYSIS].desc = "Collect shading reference data before scanning the image. If set to 'no', this option may be overridden by the scanner.";
719     scanner->opt[OPT_SHADING_ANALYSIS].type = SANE_TYPE_BOOL;
720     scanner->opt[OPT_SHADING_ANALYSIS].unit = SANE_UNIT_NONE;
721     scanner->opt[OPT_SHADING_ANALYSIS].constraint_type = SANE_CONSTRAINT_NONE;
722     scanner->val[OPT_SHADING_ANALYSIS].b = SANE_FALSE;
723     scanner->opt[OPT_SHADING_ANALYSIS].cap |= SANE_CAP_SOFT_SELECT;
724 
725     /* use auto-calibration settings for scan */
726     scanner->opt[OPT_CALIBRATION_MODE].name = "calibration";
727     scanner->opt[OPT_CALIBRATION_MODE].title = "Calibration mode";
728     scanner->opt[OPT_CALIBRATION_MODE].desc = "How to calibrate the scanner.";
729     scanner->opt[OPT_CALIBRATION_MODE].type = SANE_TYPE_STRING;
730     scanner->opt[OPT_CALIBRATION_MODE].size = max_string_size ((SANE_String_Const const *) scanner->device->calibration_mode_list);
731     scanner->opt[OPT_CALIBRATION_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
732     scanner->opt[OPT_CALIBRATION_MODE].constraint.string_list = (SANE_String_Const const *) scanner->device->calibration_mode_list;
733     scanner->val[OPT_CALIBRATION_MODE].s = (SANE_Char *) strdup (scanner->device->calibration_mode_list[1]); /* default auto */
734 
735     /* OPT_GAIN_ADJUST */
736     scanner->opt[OPT_GAIN_ADJUST].name = "gain-adjust";
737     scanner->opt[OPT_GAIN_ADJUST].title = "Adjust gain";
738     scanner->opt[OPT_GAIN_ADJUST].desc = "Adjust gain determined by calibration procedure.";
739     scanner->opt[OPT_GAIN_ADJUST].type = SANE_TYPE_STRING;
740     scanner->opt[OPT_GAIN_ADJUST].size = max_string_size ((SANE_String_Const const *) scanner->device->gain_adjust_list);
741     scanner->opt[OPT_GAIN_ADJUST].constraint_type = SANE_CONSTRAINT_STRING_LIST;
742     scanner->opt[OPT_GAIN_ADJUST].constraint.string_list = (SANE_String_Const const *) scanner->device->gain_adjust_list;
743     scanner->val[OPT_GAIN_ADJUST].s = (SANE_Char *) strdup (scanner->device->gain_adjust_list[2]); /* x 1.0 (no change) */
744 
745     /* scan infrared channel faster but less accurate */
746     scanner->opt[OPT_FAST_INFRARED].name = "fast-infrared";
747     scanner->opt[OPT_FAST_INFRARED].title = "Fast infrared scan";
748     scanner->opt[OPT_FAST_INFRARED].desc = "Do not reposition scan head before scanning infrared line. Results in an infrared offset which may deteriorate IR dust and scratch removal.";
749     scanner->opt[OPT_FAST_INFRARED].type = SANE_TYPE_BOOL;
750     scanner->opt[OPT_FAST_INFRARED].unit = SANE_UNIT_NONE;
751     scanner->opt[OPT_FAST_INFRARED].constraint_type = SANE_CONSTRAINT_NONE;
752     scanner->val[OPT_FAST_INFRARED].b = SANE_FALSE;
753     scanner->opt[OPT_FAST_INFRARED].cap |= SANE_CAP_SOFT_SELECT;
754 
755     /* automatically advance to next slide after scan */
756     scanner->opt[OPT_ADVANCE_SLIDE].name = "advance";
757     scanner->opt[OPT_ADVANCE_SLIDE].title = "Advance slide";
758     scanner->opt[OPT_ADVANCE_SLIDE].desc = "Automatically advance to next slide after scan";
759     scanner->opt[OPT_ADVANCE_SLIDE].type = SANE_TYPE_BOOL;
760     scanner->opt[OPT_ADVANCE_SLIDE].unit = SANE_UNIT_NONE;
761     scanner->opt[OPT_ADVANCE_SLIDE].constraint_type = SANE_CONSTRAINT_NONE;
762     scanner->val[OPT_ADVANCE_SLIDE].w = SANE_TRUE;
763     scanner->opt[OPT_ADVANCE_SLIDE].cap |= SANE_CAP_SOFT_SELECT;
764 
765     /* "Geometry" group: */
766     scanner->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
767     scanner->opt[OPT_GEOMETRY_GROUP].desc = "";
768     scanner->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
769     scanner->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
770     scanner->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
771 
772     /* top-left x */
773     scanner->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
774     scanner->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
775     scanner->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
776     scanner->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
777     scanner->opt[OPT_TL_X].unit = SANE_UNIT_MM;
778     scanner->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
779     scanner->opt[OPT_TL_X].constraint.range = &(scanner->device->x_range);
780     scanner->val[OPT_TL_X].w = 0;
781 
782     /* top-left y */
783     scanner->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
784     scanner->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
785     scanner->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
786     scanner->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
787     scanner->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
788     scanner->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
789     scanner->opt[OPT_TL_Y].constraint.range = &(scanner->device->y_range);
790     scanner->val[OPT_TL_Y].w = 0;
791 
792     /* bottom-right x */
793     scanner->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
794     scanner->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
795     scanner->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
796     scanner->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
797     scanner->opt[OPT_BR_X].unit = SANE_UNIT_MM;
798     scanner->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
799     scanner->opt[OPT_BR_X].constraint.range = &(scanner->device->x_range);
800     scanner->val[OPT_BR_X].w = scanner->device->x_range.max;
801 
802     /* bottom-right y */
803     scanner->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
804     scanner->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
805     scanner->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
806     scanner->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
807     scanner->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
808     scanner->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
809     scanner->opt[OPT_BR_Y].constraint.range = &(scanner->device->y_range);
810     scanner->val[OPT_BR_Y].w = scanner->device->y_range.max;
811 
812     /* "Enhancement" group: */
813     scanner->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
814     scanner->opt[OPT_ENHANCEMENT_GROUP].desc = "";
815     scanner->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
816     scanner->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
817     scanner->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
818 
819     /* correct data for lamp variations (shading) */
820     scanner->opt[OPT_CORRECT_SHADING].name = "correct-shading";
821     scanner->opt[OPT_CORRECT_SHADING].title = "Correct shading";
822     scanner->opt[OPT_CORRECT_SHADING].desc = "Correct data for lamp variations (shading)";
823     scanner->opt[OPT_CORRECT_SHADING].type = SANE_TYPE_BOOL;
824     scanner->opt[OPT_CORRECT_SHADING].unit = SANE_UNIT_NONE;
825     scanner->val[OPT_CORRECT_SHADING].w = SANE_TRUE;
826 
827     /* correct infrared for red crosstalk */
828     scanner->opt[OPT_CORRECT_INFRARED].name = "correct-infrared";
829     scanner->opt[OPT_CORRECT_INFRARED].title = "Correct infrared";
830     scanner->opt[OPT_CORRECT_INFRARED].desc = "Correct infrared for red crosstalk";
831     scanner->opt[OPT_CORRECT_INFRARED].type = SANE_TYPE_BOOL;
832     scanner->opt[OPT_CORRECT_INFRARED].unit = SANE_UNIT_NONE;
833     scanner->val[OPT_CORRECT_INFRARED].w = SANE_FALSE;
834 
835     /* detect and remove dust and scratch artifacts */
836     scanner->opt[OPT_CLEAN_IMAGE].name = "clean-image";
837     scanner->opt[OPT_CLEAN_IMAGE].title = "Clean image";
838     scanner->opt[OPT_CLEAN_IMAGE].desc = "Detect and remove dust and scratch artifacts";
839     scanner->opt[OPT_CLEAN_IMAGE].type = SANE_TYPE_BOOL;
840     scanner->opt[OPT_CLEAN_IMAGE].unit = SANE_UNIT_NONE;
841     scanner->val[OPT_CLEAN_IMAGE].w = SANE_FALSE;
842 
843     /* strength of grain filtering */
844     scanner->opt[OPT_SMOOTH_IMAGE].name = "smooth";
845     scanner->opt[OPT_SMOOTH_IMAGE].title = "Attenuate film grain";
846     scanner->opt[OPT_SMOOTH_IMAGE].desc = "Amount of smoothening";
847     scanner->opt[OPT_SMOOTH_IMAGE].type = SANE_TYPE_INT;
848     scanner->opt[OPT_SMOOTH_IMAGE].constraint_type = SANE_CONSTRAINT_WORD_LIST;
849     scanner->opt[OPT_SMOOTH_IMAGE].size = sizeof (SANE_Word);
850     scanner->opt[OPT_SMOOTH_IMAGE].constraint.word_list = scanner->device->grain_sw_list;
851     scanner->val[OPT_SMOOTH_IMAGE].w = scanner->device->grain_sw_list[1];
852     if (scanner->opt[OPT_SMOOTH_IMAGE].constraint.word_list[0] < 2) {
853         scanner->opt[OPT_SMOOTH_IMAGE].cap |= SANE_CAP_INACTIVE;
854     }
855 
856     /* gamma correction, to make image sRGB like */
857     scanner->opt[OPT_TRANSFORM_TO_SRGB].name = "srgb";
858     scanner->opt[OPT_TRANSFORM_TO_SRGB].title = "sRGB colors";
859     scanner->opt[OPT_TRANSFORM_TO_SRGB].desc = "Transform image to approximate sRGB color space";
860     scanner->opt[OPT_TRANSFORM_TO_SRGB].type = SANE_TYPE_BOOL;
861     scanner->opt[OPT_TRANSFORM_TO_SRGB].unit = SANE_UNIT_NONE;
862     scanner->val[OPT_TRANSFORM_TO_SRGB].w = SANE_FALSE;
863     scanner->opt[OPT_TRANSFORM_TO_SRGB].cap |= SANE_CAP_INACTIVE;
864 
865     /* color correction for generic negative film */
866     scanner->opt[OPT_INVERT_IMAGE].name = "invert";
867     scanner->opt[OPT_INVERT_IMAGE].title = "Invert colors";
868     scanner->opt[OPT_INVERT_IMAGE].desc = "Correct for generic negative film";
869     scanner->opt[OPT_INVERT_IMAGE].type = SANE_TYPE_BOOL;
870     scanner->opt[OPT_INVERT_IMAGE].unit = SANE_UNIT_NONE;
871     scanner->val[OPT_INVERT_IMAGE].w = SANE_FALSE;
872     scanner->opt[OPT_INVERT_IMAGE].cap |= SANE_CAP_INACTIVE;
873 
874     /* crop image */
875     scanner->opt[OPT_CROP_IMAGE].name = "crop";
876     scanner->opt[OPT_CROP_IMAGE].title = "Cropping";
877     scanner->opt[OPT_CROP_IMAGE].desc = "How to crop the image";
878     scanner->opt[OPT_CROP_IMAGE].type = SANE_TYPE_STRING;
879     scanner->opt[OPT_CROP_IMAGE].size = max_string_size ((SANE_String_Const const *)(void*) scanner->device->crop_sw_list);
880     scanner->opt[OPT_CROP_IMAGE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
881     scanner->opt[OPT_CROP_IMAGE].constraint.string_list = (SANE_String_Const const *)(void*) scanner->device->crop_sw_list;
882     scanner->val[OPT_CROP_IMAGE].s = (SANE_Char *) strdup (scanner->device->crop_sw_list[2]);
883 
884     /* "Advanced" group: */
885     scanner->opt[OPT_ADVANCED_GROUP].title = "Advanced";
886     scanner->opt[OPT_ADVANCED_GROUP].desc = "";
887     scanner->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
888     scanner->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
889     scanner->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
890 
891     /* preview */
892     scanner->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
893     scanner->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
894     scanner->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
895     scanner->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
896     scanner->val[OPT_PREVIEW].w = SANE_FALSE;
897 
898     /* save shading data */
899     scanner->opt[OPT_SAVE_SHADINGDATA].name = "save-shading-data";
900     scanner->opt[OPT_SAVE_SHADINGDATA].title = "Save shading data";
901     scanner->opt[OPT_SAVE_SHADINGDATA].desc = "Save shading data in 'pieusb.shading'";
902     scanner->opt[OPT_SAVE_SHADINGDATA].type = SANE_TYPE_BOOL;
903     scanner->val[OPT_SAVE_SHADINGDATA].w = SANE_FALSE;
904 
905     /* save CCD mask */
906     scanner->opt[OPT_SAVE_CCDMASK].name = "save-ccdmask";
907     scanner->opt[OPT_SAVE_CCDMASK].title = "Save CCD mask";
908     scanner->opt[OPT_SAVE_CCDMASK].desc = "Save CCD mask 'pieusb.ccd'";
909     scanner->opt[OPT_SAVE_CCDMASK].type = SANE_TYPE_BOOL;
910     scanner->val[OPT_SAVE_CCDMASK].w = SANE_FALSE;
911 
912     scanner->opt[OPT_LIGHT].name = "light";
913     scanner->opt[OPT_LIGHT].title = "Light";
914     scanner->opt[OPT_LIGHT].desc = "Light";
915     scanner->opt[OPT_LIGHT].type = SANE_TYPE_INT;
916     scanner->opt[OPT_LIGHT].unit = SANE_UNIT_MICROSECOND;
917     scanner->opt[OPT_LIGHT].cap |= SANE_CAP_SOFT_SELECT;
918     scanner->opt[OPT_LIGHT].size = sizeof(SANE_Word);
919     scanner->val[OPT_LIGHT].w = DEFAULT_LIGHT;
920 
921     scanner->opt[OPT_DOUBLE_TIMES].name = "double-times";
922     scanner->opt[OPT_DOUBLE_TIMES].title = "Double times";
923     scanner->opt[OPT_DOUBLE_TIMES].desc = "Double times";
924     scanner->opt[OPT_DOUBLE_TIMES].type = SANE_TYPE_INT;
925     scanner->opt[OPT_DOUBLE_TIMES].unit = SANE_UNIT_MICROSECOND;
926     scanner->opt[OPT_DOUBLE_TIMES].cap |= SANE_CAP_SOFT_SELECT;
927     scanner->opt[OPT_DOUBLE_TIMES].size = sizeof(SANE_Word);
928     scanner->val[OPT_DOUBLE_TIMES].w = DEFAULT_DOUBLE_TIMES;
929 
930     /* exposure times for R, G, B and I */
931     scanner->opt[OPT_SET_EXPOSURE_R].name = SANE_NAME_EXPOSURE_R;
932     scanner->opt[OPT_SET_EXPOSURE_R].title = SANE_TITLE_EXPOSURE_R;
933     scanner->opt[OPT_SET_EXPOSURE_R].desc = SANE_DESC_EXPOSURE_R;
934     scanner->opt[OPT_SET_EXPOSURE_G].name = SANE_NAME_EXPOSURE_G;
935     scanner->opt[OPT_SET_EXPOSURE_G].title = SANE_TITLE_EXPOSURE_G;
936     scanner->opt[OPT_SET_EXPOSURE_G].desc = SANE_DESC_EXPOSURE_G;
937     scanner->opt[OPT_SET_EXPOSURE_B].name = SANE_NAME_EXPOSURE_B;
938     scanner->opt[OPT_SET_EXPOSURE_B].title = SANE_TITLE_EXPOSURE_B;
939     scanner->opt[OPT_SET_EXPOSURE_B].desc = SANE_DESC_EXPOSURE_B;
940     scanner->opt[OPT_SET_EXPOSURE_I].name = SANE_NAME_EXPOSURE_I;
941     scanner->opt[OPT_SET_EXPOSURE_I].title = SANE_TITLE_EXPOSURE_I;
942     scanner->opt[OPT_SET_EXPOSURE_I].desc = SANE_DESC_EXPOSURE_I;
943     for (i = OPT_SET_EXPOSURE_R; i <= OPT_SET_EXPOSURE_I; ++i) {
944     scanner->opt[i].type = SANE_TYPE_INT;
945     scanner->opt[i].unit = SANE_UNIT_MICROSECOND;
946     scanner->opt[i].cap |= SANE_CAP_SOFT_SELECT;
947     scanner->opt[i].constraint_type = SANE_CONSTRAINT_RANGE;
948     scanner->opt[i].constraint.range = &(scanner->device->exposure_range);
949     scanner->opt[i].size = sizeof(SANE_Word);
950     scanner->val[i].w = SANE_EXPOSURE_DEFAULT;
951     }
952 
953     /* gain for R, G, B and I */
954     scanner->opt[OPT_SET_GAIN_R].name = SANE_NAME_GAIN_R;
955     scanner->opt[OPT_SET_GAIN_R].title = SANE_TITLE_GAIN_R;
956     scanner->opt[OPT_SET_GAIN_R].desc = SANE_DESC_GAIN_R;
957     scanner->opt[OPT_SET_GAIN_G].name = SANE_NAME_GAIN_G;
958     scanner->opt[OPT_SET_GAIN_G].title = SANE_TITLE_GAIN_G;
959     scanner->opt[OPT_SET_GAIN_G].desc = SANE_DESC_GAIN_G;
960     scanner->opt[OPT_SET_GAIN_B].name = SANE_NAME_GAIN_B;
961     scanner->opt[OPT_SET_GAIN_B].title = SANE_TITLE_GAIN_B;
962     scanner->opt[OPT_SET_GAIN_B].desc = SANE_DESC_GAIN_B;
963     scanner->opt[OPT_SET_GAIN_I].name = SANE_NAME_GAIN_I;
964     scanner->opt[OPT_SET_GAIN_I].title = SANE_TITLE_GAIN_I;
965     scanner->opt[OPT_SET_GAIN_I].desc = SANE_DESC_GAIN_I;
966     for (i = OPT_SET_GAIN_R; i <= OPT_SET_GAIN_I; ++i) {
967       scanner->opt[i].type = SANE_TYPE_INT;
968       scanner->opt[i].unit = SANE_UNIT_NONE;
969       scanner->opt[i].constraint_type = SANE_CONSTRAINT_RANGE;
970       scanner->opt[i].constraint.range = &gain_range;
971       scanner->opt[i].size = sizeof(SANE_Word);
972       scanner->val[i].w = SANE_GAIN_DEFAULT;
973     }
974     /* offsets for R, G, B and I */
975     scanner->opt[OPT_SET_OFFSET_R].name = SANE_NAME_OFFSET_R;
976     scanner->opt[OPT_SET_OFFSET_R].title = SANE_TITLE_OFFSET_R;
977     scanner->opt[OPT_SET_OFFSET_R].desc = SANE_DESC_OFFSET_R;
978     scanner->opt[OPT_SET_OFFSET_G].name = SANE_NAME_OFFSET_G;
979     scanner->opt[OPT_SET_OFFSET_G].title = SANE_TITLE_OFFSET_G;
980     scanner->opt[OPT_SET_OFFSET_G].desc = SANE_DESC_OFFSET_G;
981     scanner->opt[OPT_SET_OFFSET_B].name = SANE_NAME_OFFSET_B;
982     scanner->opt[OPT_SET_OFFSET_B].title = SANE_TITLE_OFFSET_B;
983     scanner->opt[OPT_SET_OFFSET_B].desc = SANE_DESC_OFFSET_B;
984     scanner->opt[OPT_SET_OFFSET_I].name = SANE_NAME_OFFSET_I;
985     scanner->opt[OPT_SET_OFFSET_I].title = SANE_TITLE_OFFSET_I;
986     scanner->opt[OPT_SET_OFFSET_I].desc = SANE_DESC_OFFSET_I;
987     for (i = OPT_SET_OFFSET_R; i <= OPT_SET_OFFSET_I; ++i) {
988       scanner->opt[i].type = SANE_TYPE_INT;
989       scanner->opt[i].unit = SANE_UNIT_NONE;
990       scanner->opt[i].constraint_type = SANE_CONSTRAINT_RANGE;
991       scanner->opt[i].constraint.range = &offset_range;
992       scanner->opt[i].size = sizeof(SANE_Word);
993       scanner->val[i].w = SANE_OFFSET_DEFAULT;
994     }
995     return SANE_STATUS_GOOD;
996 }
997 
998 /**
999  * Parse line from config file into a vendor id, product id, model number, and flags
1000  *
1001  * @param config_line Text to parse
1002  * @param vendor_id
1003  * @param product_id
1004  * @param model_number
1005  * @param flags
1006  * @return SANE_STATUS_GOOD, or SANE_STATUS_INVAL in case of a parse error
1007  */
1008 SANE_Status
sanei_pieusb_parse_config_line(const char* config_line, SANE_Word* vendor_id, SANE_Word* product_id, SANE_Int* model_number, SANE_Int* flags)1009 sanei_pieusb_parse_config_line(const char* config_line,
1010                                SANE_Word* vendor_id,
1011                                SANE_Word* product_id,
1012                                SANE_Int* model_number,
1013                                SANE_Int* flags)
1014 {
1015     char *vendor_id_string, *product_id_string, *model_number_string, *flags_string;
1016 
1017     if (strncmp (config_line, "usb ", 4) != 0) {
1018         return SANE_STATUS_INVAL;
1019     }
1020     /* Detect vendor-id */
1021     config_line += 4;
1022     config_line = sanei_config_skip_whitespace (config_line);
1023     if (*config_line) {
1024         config_line = sanei_config_get_string (config_line, &vendor_id_string);
1025         if (vendor_id_string) {
1026             *vendor_id = strtol (vendor_id_string, 0, 0);
1027             free (vendor_id_string);
1028         } else {
1029             return SANE_STATUS_INVAL;
1030         }
1031         config_line = sanei_config_skip_whitespace (config_line);
1032     } else {
1033         return SANE_STATUS_INVAL;
1034     }
1035     /* Detect product-id */
1036     config_line = sanei_config_skip_whitespace (config_line);
1037     if (*config_line) {
1038         config_line = sanei_config_get_string (config_line, &product_id_string);
1039         if (product_id_string) {
1040             *product_id = strtol (product_id_string, 0, 0);
1041             free (product_id_string);
1042         } else {
1043             return SANE_STATUS_INVAL;
1044         }
1045         config_line = sanei_config_skip_whitespace (config_line);
1046     } else {
1047         return SANE_STATUS_INVAL;
1048     }
1049     /* Detect model number */
1050     config_line = sanei_config_skip_whitespace (config_line);
1051     if (*config_line) {
1052         config_line = sanei_config_get_string (config_line, &model_number_string);
1053         if (model_number_string) {
1054             *model_number = (SANE_Int) strtol (model_number_string, 0, 0);
1055             free (model_number_string);
1056         } else {
1057             return SANE_STATUS_INVAL;
1058         }
1059         config_line = sanei_config_skip_whitespace (config_line);
1060     } else {
1061         return SANE_STATUS_INVAL;
1062     }
1063     /* Detect (optional) flags */
1064     *flags = 0;
1065     config_line = sanei_config_skip_whitespace (config_line);
1066     if (*config_line) {
1067         config_line = sanei_config_get_string (config_line, &flags_string);
1068         if (flags_string) {
1069             *flags = (SANE_Int) strtol (flags_string, 0, 0);
1070             free (flags_string);
1071         }
1072     }
1073     return SANE_STATUS_GOOD;
1074 }
1075 
1076 /**
1077  * Check if current list of supported devices contains the given specifications.
1078  *
1079  * @param vendor_id
1080  * @param product_id
1081  * @param model_number
1082  * @param flags
1083  * @return
1084  */
1085 SANE_Bool
sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags)1086 sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags)
1087 {
1088     int i = 0;
1089     while (pieusb_supported_usb_device_list[i].vendor != 0) {
1090         if (pieusb_supported_usb_device_list[i].vendor == vendor_id
1091               && pieusb_supported_usb_device_list[i].product == product_id
1092               && pieusb_supported_usb_device_list[i].model == model_number
1093               && pieusb_supported_usb_device_list[i].flags == flags) {
1094             return SANE_TRUE;
1095         }
1096         i++;
1097     }
1098     return SANE_FALSE;
1099 }
1100 
1101 /**
1102  * Add the given specifications to the current list of supported devices
1103  * @param vendor_id
1104  * @param product_id
1105  * @param model_number
1106  * @param flags
1107  * @return
1108  */
1109 SANE_Status
sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags)1110 sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags)
1111 {
1112     int i = 0, k;
1113     struct Pieusb_USB_Device_Entry* dl;
1114 
1115     while (pieusb_supported_usb_device_list[i].vendor != 0) {
1116         i++;
1117     }
1118     /* i is index of last entry */
1119     for (k=0; k<=i; k++) {
1120         DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add(): current %03d: %04x %04x %02x %02x\n", i,
1121             pieusb_supported_usb_device_list[k].vendor,
1122             pieusb_supported_usb_device_list[k].product,
1123             pieusb_supported_usb_device_list[k].model,
1124             pieusb_supported_usb_device_list[k].flags);
1125     }
1126 
1127     dl = realloc(pieusb_supported_usb_device_list,(i+2)*sizeof(struct Pieusb_USB_Device_Entry)); /* Add one entry to list */
1128     if (dl == NULL) {
1129         return SANE_STATUS_INVAL;
1130     }
1131     /* Copy values */
1132     pieusb_supported_usb_device_list = dl;
1133     pieusb_supported_usb_device_list[i].vendor = vendor_id;
1134     pieusb_supported_usb_device_list[i].product = product_id;
1135     pieusb_supported_usb_device_list[i].model = model_number;
1136     pieusb_supported_usb_device_list[i].flags = flags;
1137     pieusb_supported_usb_device_list[i+1].vendor = 0;
1138     pieusb_supported_usb_device_list[i+1].product = 0;
1139     pieusb_supported_usb_device_list[i+1].model = 0;
1140     pieusb_supported_usb_device_list[i+1].flags = 0;
1141     for (k=0; k<=i+1; k++) {
1142         DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add() add: %03d: %04x %04x %02x %02x\n", i,
1143             pieusb_supported_usb_device_list[k].vendor,
1144             pieusb_supported_usb_device_list[k].product,
1145             pieusb_supported_usb_device_list[k].model,
1146             pieusb_supported_usb_device_list[k].flags);
1147     }
1148     return SANE_STATUS_GOOD;
1149 }
1150 
1151 /**
1152  * Actions to perform when a cancel request has been received.
1153  *
1154  * @param scanner scanner to stop scanning
1155  * @return SANE_STATUS_CANCELLED
1156  */
1157 SANE_Status
sanei_pieusb_on_cancel(Pieusb_Scanner * scanner)1158 sanei_pieusb_on_cancel (Pieusb_Scanner * scanner)
1159 {
1160     struct Pieusb_Command_Status status;
1161 
1162     DBG (DBG_info_proc, "sanei_pieusb_on_cancel()\n");
1163 
1164     sanei_pieusb_cmd_stop_scan (scanner->device_number, &status);
1165     sanei_pieusb_cmd_set_scan_head (scanner->device_number, 1, 0, &status);
1166     sanei_pieusb_buffer_delete (&scanner->buffer);
1167     scanner->scanning = SANE_FALSE;
1168     return SANE_STATUS_CANCELLED;
1169 }
1170 
1171 /**
1172  * Determine maximum length of a set of strings.
1173  *
1174  * @param strings Set of strings
1175  * @return maximum length
1176  */
1177 static size_t
max_string_size(SANE_String_Const const strings[])1178 max_string_size (SANE_String_Const const strings[])
1179 {
1180     size_t size, max_size = 0;
1181     int i;
1182 
1183     for (i = 0; strings[i]; ++i) {
1184         size = strlen (strings[i]) + 1;
1185         if (size > max_size) {
1186             max_size = size;
1187         }
1188     }
1189 
1190     return max_size;
1191 }
1192 
1193 /* From MR's pie.c */
1194 
1195 /* ------------------------- PIEUSB_CORRECT_SHADING -------------------------- */
1196 
1197 /**
1198  * Correct the given buffer for shading using shading data in scanner.
1199  * If the loop order is width->color->height, a 7200 dpi scan correction takes
1200  * 45 minutes. If the loop order is color->height->width, this is less than 3
1201  * minutes. So it is worthwhile to find the used pixels first (array width_to_loc).
1202  *
1203  * @param scanner Scanner
1204  * @param buffer Buffer to correct
1205  */
1206 void
sanei_pieusb_correct_shading(struct Pieusb_Scanner *scanner, struct Pieusb_Read_Buffer *buffer)1207 sanei_pieusb_correct_shading(struct Pieusb_Scanner *scanner, struct Pieusb_Read_Buffer *buffer)
1208 {
1209 
1210     int i, j, c, k;
1211     SANE_Uint val, val_org, *p;
1212     int *width_to_loc;
1213 
1214     DBG (DBG_info_proc, "sanei_pieusb_correct_shading()\n");
1215 
1216     /* Loop through CCD-mask to find used pixels */
1217     width_to_loc = calloc(buffer->width,sizeof(int));
1218     j = 0;
1219     for (i = 0; i < scanner->ccd_mask_size; i++) {
1220         if (scanner->ccd_mask[i] == 0) {
1221             width_to_loc[j++] = i;
1222         }
1223     }
1224     /* Correct complete image */
1225     for (c = 0; c < buffer->colors; c++) {
1226         DBG(DBG_info,"sanei_pieusb_correct_shading() correct color %d\n",c);
1227         for (k = 0; k < buffer->height; k++) {
1228             /* DBG(DBG_info,"Correct line %d\n",k); */
1229             p = buffer->data + c * buffer->width * buffer->height + k * buffer->width;
1230             for (j = 0; j < buffer->width; j++) {
1231                 val_org = *p;
1232                 val = lround((double)scanner->shading_mean[c] / scanner->shading_ref[c][width_to_loc[j]] * val_org);
1233                 /* DBG(DBG_info,"Correct [%d,%d,%d] %d -> %d\n",k,j,c,val_org,val); */
1234                 *p++ = val;
1235             }
1236         }
1237     }
1238     /* Free memory */
1239     free(width_to_loc);
1240 }
1241 
1242 /* === functions copied from MR's code === */
1243 
1244 /**
1245  *
1246  * @param scanner
1247  * @param in_img
1248  * @param planes
1249  * @param out_planes
1250  * @return
1251  */
1252 SANE_Status
sanei_pieusb_post(Pieusb_Scanner *scanner, uint16_t **in_img, int planes)1253 sanei_pieusb_post (Pieusb_Scanner *scanner, uint16_t **in_img, int planes)
1254 {
1255   uint16_t *cplane[PLANES];    /* R, G, B, I gray scale planes */
1256   SANE_Parameters parameters;   /* describes the image */
1257   int winsize_smooth;           /* for adapting replaced pixels */
1258   char filename[64];
1259   SANE_Status status;
1260   int smooth, i;
1261 
1262   memcpy (&parameters, &scanner->scan_parameters, sizeof (SANE_Parameters));
1263   parameters.format = SANE_FRAME_GRAY;
1264   parameters.bytes_per_line = parameters.pixels_per_line;
1265   if (parameters.depth > 8)
1266     parameters.bytes_per_line *= 2;
1267   parameters.last_frame = 0;
1268 
1269   DBG (DBG_info, "pie_usb_post: %d ppl, %d lines, %d bits, %d planes, %d dpi\n",
1270        parameters.pixels_per_line, parameters.lines,
1271        parameters.depth, planes, scanner->mode.resolution);
1272 
1273   if (planes > PLANES) {
1274     DBG (DBG_error, "pie_usb_post: too many planes: %d (max %d)\n", planes, PLANES);
1275     return SANE_STATUS_INVAL;
1276   }
1277 
1278   for (i = 0; i < planes; i++)
1279     cplane[i] = in_img[i];
1280 
1281   /* dirt is rather resolution invariant, so
1282    * setup resolution dependent parameters
1283    */
1284   /* film grain reduction */
1285   smooth = scanner->val[OPT_SMOOTH_IMAGE].w;
1286   winsize_smooth = (scanner->mode.resolution / 540) | 1;
1287   /* smoothen whole image or only replaced pixels */
1288   if (smooth)
1289     {
1290       winsize_smooth += 2 * (smooth - 3);       /* even */
1291       if (winsize_smooth < 3)
1292         smooth = 0;
1293     }
1294   if (winsize_smooth < 3)
1295     winsize_smooth = 3;
1296   DBG (DBG_info, "pie_usb_sw_post: winsize_smooth %d\n", winsize_smooth);
1297 
1298   /* RGBI post-processing if selected:
1299    * 1) remove spectral overlay from ired plane,
1300    * 2) remove dirt, smoothen if, crop if */
1301   if (scanner->val[OPT_CORRECT_INFRARED].b) /* (scanner->processing & POST_SW_IRED_MASK) */
1302     {
1303       /* remove spectral overlay from ired plane */
1304       status = sanei_ir_spectral_clean (&parameters, scanner->ln_lut, cplane[0], cplane[3]);
1305       if (status != SANE_STATUS_GOOD)
1306         return status;
1307       if (DBG_LEVEL >= 15)
1308         {
1309           snprintf (filename, 63, "/tmp/ir-spectral.pnm");
1310           pieusb_write_pnm_file (filename, cplane[3],
1311                                   parameters.depth, 1,
1312                                   parameters.pixels_per_line, parameters.lines);
1313         }
1314       if (scanner->cancel_request)          /* asynchronous cancel ? */
1315         return SANE_STATUS_CANCELLED;
1316   } /* scanner-> processing & POST_SW_IRED_MASK */
1317 
1318   /* remove dirt, smoothen if, crop if */
1319   if (scanner->val[OPT_CLEAN_IMAGE].b) /* (scanner->processing & POST_SW_DIRT) */
1320     {
1321       double *norm_histo;
1322       uint16_t *thresh_data;
1323       int static_thresh, too_thresh;    /* static thresholds */
1324       int winsize_filter;               /* primary size of filtering window */
1325       int size_dilate;                  /* the dirt mask */
1326 
1327       /* size of filter detecting dirt */
1328       winsize_filter = (int) (5.0 * (double) scanner->mode.resolution / 300.0) | 1;
1329       if (winsize_filter < 3)
1330         winsize_filter = 3;
1331       /* dirt usually has smooth edges which also need correction */
1332       size_dilate = scanner->mode.resolution / 1000 + 1;
1333 
1334       /* first detect large dirt by a static threshold */
1335       status = sanei_ir_create_norm_histogram (&parameters, cplane[3], &norm_histo);
1336       if (status != SANE_STATUS_GOOD)
1337         {
1338           DBG (DBG_error, "pie_usb_sw_post: no buffer\n");
1339           return SANE_STATUS_NO_MEM;
1340         }
1341       /* generate a "bimodal" static threshold */
1342       status = sanei_ir_threshold_yen (&parameters, norm_histo, &static_thresh);
1343       if (status != SANE_STATUS_GOOD)
1344         return status;
1345       /* generate traditional static threshold */
1346       status = sanei_ir_threshold_otsu (&parameters, norm_histo, &too_thresh);
1347       if (status != SANE_STATUS_GOOD)
1348         return status;
1349       /* choose lower one */
1350       if (too_thresh < static_thresh)
1351         static_thresh = too_thresh;
1352       free (norm_histo);
1353 
1354       /* then generate dirt mask with adaptive thresholding filter
1355        * and add the dirt from the static threshold */
1356       /* last two parameters: 10, 50 detects more, 20, 75 less */
1357       status = sanei_ir_filter_madmean (&parameters, cplane[3], &thresh_data, winsize_filter, 20, 100);
1358       if (status != SANE_STATUS_GOOD) {
1359         free (thresh_data);
1360         return status;
1361       }
1362       sanei_ir_add_threshold (&parameters, cplane[3], thresh_data, static_thresh);
1363       if (DBG_LEVEL >= 15)
1364         {
1365           snprintf (filename, 63, "/tmp/ir-threshold.pnm");
1366           pieusb_write_pnm_file (filename, thresh_data,
1367                                   8, 1, parameters.pixels_per_line,
1368                                   parameters.lines);
1369         }
1370       if (scanner->cancel_request) {         /* asynchronous cancel ? */
1371         free (thresh_data);
1372         return SANE_STATUS_CANCELLED;
1373       }
1374       /* replace the dirt and smoothen film grain and crop if possible */
1375       status = sanei_ir_dilate_mean (&parameters, cplane, thresh_data,
1376               500, size_dilate, winsize_smooth, smooth,
1377               0, NULL);
1378       if (status != SANE_STATUS_GOOD) {
1379         free (thresh_data);
1380         return status;
1381       }
1382       smooth = 0;
1383       free (thresh_data);
1384     }
1385 
1386   if (DBG_LEVEL >= 15)
1387     {
1388       pieusb_write_pnm_file ("/tmp/RGBi-img.pnm", scanner->buffer.data,
1389         scanner->scan_parameters.depth, 3, scanner->scan_parameters.pixels_per_line,
1390         scanner->scan_parameters.lines);
1391     }
1392 
1393   return status;
1394 }
1395 
1396 /* ------------------------------ PIE_USB_WRITE_PNM_FILE ------------------------------- */
1397 static SANE_Status
pieusb_write_pnm_file(char *filename, SANE_Uint *data, int depth, int channels, int pixels_per_line, int lines)1398 pieusb_write_pnm_file (char *filename, SANE_Uint *data, int depth,
1399                         int channels, int pixels_per_line, int lines)
1400 {
1401   FILE *out;
1402   int r, c, ch;
1403   SANE_Uint val;
1404   uint8_t b = 0;
1405 
1406   DBG (DBG_info_proc,
1407        "pie_usb_write_pnm_file: depth=%d, channels=%d, ppl=%d, lines=%d\n",
1408        depth, channels, pixels_per_line, lines);
1409 
1410   out = fopen (filename, "w");
1411   if (!out)
1412     {
1413       DBG (DBG_error,
1414            "pie_usb_write_pnm_file: could not open %s for writing: %s\n",
1415            filename, strerror (errno));
1416       return SANE_STATUS_INVAL;
1417     }
1418 
1419   switch (depth) {
1420       case 1:
1421           fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines);
1422           for (r = 0; r < lines; r++) {
1423               int i;
1424               i = 0;
1425               b = 0;
1426               for (c = 0; c < pixels_per_line; c++) {
1427                   val = *(data + r * pixels_per_line + c);
1428                   if (val > 0) b |= (0x80 >> i);
1429                   i++;
1430                   if (i == 7) {
1431                       fputc(b, out);
1432                       i = 0;
1433                       b = 0;
1434                   }
1435               }
1436               if (i != 0) {
1437                   fputc(b, out);
1438               }
1439           }
1440           break;
1441       case 8:
1442           fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', pixels_per_line, lines, 255);
1443           for (r = 0; r < lines; r++) {
1444               for (c = 0; c < pixels_per_line; c++) {
1445                   for (ch = 0; ch < channels; ch++) {
1446                       val = *(data + ch * lines * pixels_per_line + r * pixels_per_line + c);
1447                       b = val & 0xFF;
1448                       fputc(b, out);
1449                   }
1450               }
1451           }
1452           break;
1453       case 16:
1454           fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', pixels_per_line, lines, 65535);
1455           for (r = 0; r < lines; r++) {
1456               for (c = 0; c < pixels_per_line; c++) {
1457                   for (ch = 0; ch < channels; ch++) {
1458                       val = *(data + ch * lines * pixels_per_line + r * pixels_per_line + c);
1459                       b = (val >> 8) & 0xFF;
1460                       fputc(b, out);
1461                       b = val & 0xFF;
1462                       fputc(b, out);
1463                   }
1464               }
1465           }
1466           break;
1467       default:
1468           DBG (DBG_error, "pie_usb_write_pnm_file: depth %d not implemented\n", depth);
1469   }
1470   fclose (out);
1471 
1472   DBG (DBG_info, "pie_usb_write_pnm_file: finished\n");
1473   return SANE_STATUS_GOOD;
1474 }
1475 
1476 /**
1477  * Check option inconsistencies.
1478  * In most cases an inconsistency can be solved by ignoring an option setting.
1479  * Message these situations and return 1 to indicate we can work with the
1480  * current set op options. If the settings are really inconsistent, return 0.
1481  */
1482 int
sanei_pieusb_analyse_options(struct Pieusb_Scanner *scanner)1483 sanei_pieusb_analyse_options(struct Pieusb_Scanner *scanner)
1484 {
1485     /* Checks*/
1486     if (scanner->val[OPT_TL_X].w > scanner->val[OPT_BR_X].w) {
1487         DBG (DBG_error, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) -- aborting\n",
1488 	   scanner->opt[OPT_TL_X].title,
1489 	   SANE_UNFIX (scanner->val[OPT_TL_X].w),
1490 	   scanner->opt[OPT_BR_X].title,
1491 	   SANE_UNFIX (scanner->val[OPT_BR_X].w));
1492         return 0;
1493     }
1494     if (scanner->val[OPT_TL_Y].w > scanner->val[OPT_BR_Y].w) {
1495         DBG (DBG_error, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) -- aborting\n",
1496 	   scanner->opt[OPT_TL_Y].title,
1497 	   SANE_UNFIX (scanner->val[OPT_TL_Y].w),
1498 	   scanner->opt[OPT_BR_Y].title,
1499 	   SANE_UNFIX (scanner->val[OPT_BR_Y].w));
1500         return 0;
1501     }
1502     /* Modes sometimes limit other choices */
1503     if (scanner->val[OPT_PREVIEW].b) {
1504         /* Preview uses its own specific settings */
1505         if (scanner->val[OPT_RESOLUTION].w != (scanner->device->fast_preview_resolution << SANE_FIXED_SCALE_SHIFT)) {
1506             DBG (DBG_info_sane, "Option %s = %f ignored during preview\n", scanner->opt[OPT_RESOLUTION].name, SANE_UNFIX(scanner->val[OPT_RESOLUTION].w));
1507         }
1508         if (scanner->val[OPT_SHARPEN].b) {
1509             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_SHARPEN].name, scanner->val[OPT_SHARPEN].b);
1510         }
1511         if (!scanner->val[OPT_FAST_INFRARED].b) {
1512             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_FAST_INFRARED].name, scanner->val[OPT_FAST_INFRARED].b);
1513         }
1514         if (scanner->val[OPT_CORRECT_INFRARED].b) {
1515             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_CORRECT_INFRARED].name, scanner->val[OPT_CORRECT_INFRARED].b);
1516         }
1517         if (scanner->val[OPT_CLEAN_IMAGE].b) {
1518             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_CLEAN_IMAGE].name, scanner->val[OPT_CLEAN_IMAGE].b);
1519         }
1520         if (scanner->val[OPT_SMOOTH_IMAGE].w != 0) {
1521             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_SMOOTH_IMAGE].name, scanner->val[OPT_SMOOTH_IMAGE].w);
1522         }
1523         if (strcmp(scanner->val[OPT_CROP_IMAGE].s, scanner->device->crop_sw_list[0]) != 0) {
1524             DBG (DBG_info_sane, "Option %s = %s ignored during preview\n", scanner->opt[OPT_CROP_IMAGE].name, scanner->val[OPT_CROP_IMAGE].s);
1525         }
1526         if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) {
1527             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_TRANSFORM_TO_SRGB].name, scanner->val[OPT_TRANSFORM_TO_SRGB].w);
1528         }
1529         if (scanner->val[OPT_INVERT_IMAGE].w) {
1530             DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_INVERT_IMAGE].name, scanner->val[OPT_INVERT_IMAGE].w);
1531         }
1532     } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_LINEART)==0) {
1533         /* Can we do any post processing in lineart? Needs testing to see what's possible */
1534         if (scanner->val[OPT_BIT_DEPTH].w != 1) {
1535             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (will use 1)\n", scanner->opt[OPT_BIT_DEPTH].name, scanner->val[OPT_BIT_DEPTH].w);
1536         }
1537         if (!scanner->val[OPT_FAST_INFRARED].b) {
1538             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_FAST_INFRARED].name, scanner->val[OPT_FAST_INFRARED].b);
1539         }
1540         if (!scanner->val[OPT_CORRECT_SHADING].b) {
1541             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_CORRECT_SHADING].name, scanner->val[OPT_CORRECT_SHADING].b);
1542         }
1543         if (!scanner->val[OPT_CORRECT_INFRARED].b) {
1544             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_CORRECT_INFRARED].name, scanner->val[OPT_CORRECT_INFRARED].b);
1545         }
1546         if (scanner->val[OPT_CLEAN_IMAGE].b) {
1547             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_CLEAN_IMAGE].name, scanner->val[OPT_CLEAN_IMAGE].b);
1548         }
1549         if (scanner->val[OPT_SMOOTH_IMAGE].w != 0) {
1550             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_SMOOTH_IMAGE].name, scanner->val[OPT_SMOOTH_IMAGE].w);
1551         }
1552         if (strcmp(scanner->val[OPT_CROP_IMAGE].s, scanner->device->crop_sw_list[0]) != 0) {
1553             DBG (DBG_info_sane, "Option %s = %s ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_CROP_IMAGE].name, scanner->val[OPT_CROP_IMAGE].s);
1554         }
1555         if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) {
1556             DBG (DBG_info_sane, "Option %s = %d ignored in lineart mode (irrelevant)\n", scanner->opt[OPT_TRANSFORM_TO_SRGB].name, scanner->val[OPT_TRANSFORM_TO_SRGB].w);
1557         }
1558     } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_HALFTONE)==0) {
1559         /* Can we do any post processing in halftone? Needs testing to see what's possible */
1560         if (scanner->val[OPT_BIT_DEPTH].w != 1) {
1561             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (will use 1)\n", scanner->opt[OPT_BIT_DEPTH].name, scanner->val[OPT_BIT_DEPTH].w);
1562         }
1563         if (!scanner->val[OPT_FAST_INFRARED].b) {
1564             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_FAST_INFRARED].name, scanner->val[OPT_FAST_INFRARED].b);
1565         }
1566         if (!scanner->val[OPT_CORRECT_SHADING].b) {
1567             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_CORRECT_SHADING].name, scanner->val[OPT_CORRECT_SHADING].b);
1568         }
1569         if (!scanner->val[OPT_CORRECT_INFRARED].b) {
1570             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_CORRECT_INFRARED].name, scanner->val[OPT_CORRECT_INFRARED].b);
1571         }
1572         if (scanner->val[OPT_CLEAN_IMAGE].b) {
1573             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_CLEAN_IMAGE].name, scanner->val[OPT_CLEAN_IMAGE].b);
1574         }
1575         if (scanner->val[OPT_SMOOTH_IMAGE].w != 0) {
1576             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_SMOOTH_IMAGE].name, scanner->val[OPT_SMOOTH_IMAGE].w);
1577         }
1578         if (strcmp(scanner->val[OPT_CROP_IMAGE].s, scanner->device->crop_sw_list[0]) != 0) {
1579             DBG (DBG_info_sane, "Option %s = %s ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_CROP_IMAGE].name, scanner->val[OPT_CROP_IMAGE].s);
1580         }
1581         if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) {
1582             DBG (DBG_info_sane, "Option %s = %d ignored in halftone mode (irrelevant)\n", scanner->opt[OPT_TRANSFORM_TO_SRGB].name, scanner->val[OPT_TRANSFORM_TO_SRGB].w);
1583         }
1584     } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_GRAY)==0) {
1585         /* Can we do any post processing in gray mode? */
1586         /* Can we obtain a single color channel in this mode? How? */
1587         /* Is this just RGB with luminance trasformation? */
1588         /* Needs testing to see what's possible */
1589         /* Only do 8 or 16 bit scans */
1590         if (scanner->val[OPT_BIT_DEPTH].w == 1) {
1591             DBG (DBG_info_sane, "Option %s = %d ignored in gray mode (will use 8)\n", scanner->opt[OPT_BIT_DEPTH].name, scanner->val[OPT_BIT_DEPTH].w);
1592         }
1593         if (!scanner->val[OPT_FAST_INFRARED].b) {
1594             DBG (DBG_info_sane, "Option %s = %d ignored in gray mode (irrelevant)\n", scanner->opt[OPT_FAST_INFRARED].name, scanner->val[OPT_FAST_INFRARED].b);
1595         }
1596         if (!scanner->val[OPT_CORRECT_INFRARED].b) {
1597             DBG (DBG_info_sane, "Option %s = %d ignored in gray mode (irrelevant)\n", scanner->opt[OPT_CORRECT_INFRARED].name, scanner->val[OPT_CORRECT_INFRARED].b);
1598         }
1599         if (scanner->val[OPT_CLEAN_IMAGE].b) {
1600             DBG (DBG_info_sane, "Option %s = %d ignored in gray mode (irrelevant)\n", scanner->opt[OPT_CLEAN_IMAGE].name, scanner->val[OPT_CLEAN_IMAGE].b);
1601         }
1602         if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) {
1603             DBG (DBG_info_sane, "Option %s = %d ignored in gray mode (irrelevant)\n", scanner->opt[OPT_TRANSFORM_TO_SRGB].name, scanner->val[OPT_TRANSFORM_TO_SRGB].w);
1604         }
1605     } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_COLOR)==0) {
1606         /* Some options require infrared data to be obtained, so all infrared options are relevant */
1607         /* Only do 8 or 16 bit scans */
1608         if (scanner->val[OPT_BIT_DEPTH].w == 1) {
1609             DBG (DBG_info_sane, "Option %s = %d ignored in color mode (will use 8)\n", scanner->opt[OPT_BIT_DEPTH].name, scanner->val[OPT_BIT_DEPTH].w);
1610         }
1611     } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_RGBI)==0) {
1612         /* Only do 8 or 16 bit scans */
1613         if (scanner->val[OPT_BIT_DEPTH].w == 1) {
1614             DBG (DBG_info_sane, "Option %s = %d ignored in color mode (will use 8)\n", scanner->opt[OPT_BIT_DEPTH].name, scanner->val[OPT_BIT_DEPTH].w);
1615         }
1616     }
1617 
1618     return 1;
1619 }
1620 
1621 /**
1622  * Print options
1623  *
1624  * @param scanner
1625  */
1626 void
sanei_pieusb_print_options(struct Pieusb_Scanner *scanner)1627 sanei_pieusb_print_options(struct Pieusb_Scanner *scanner)
1628 {
1629     int k;
1630     /* List current options and values */
1631     DBG (DBG_info, "Num options = %d\n", scanner->val[OPT_NUM_OPTS].w);
1632     for (k = 1; k < scanner->val[OPT_NUM_OPTS].w; k++) {
1633         switch (scanner->opt[k].type) {
1634             case SANE_TYPE_BOOL:
1635                 DBG(DBG_info,"  Option %d: %s = %d\n", k, scanner->opt[k].name, scanner->val[k].b);
1636                 break;
1637             case SANE_TYPE_INT:
1638 	        DBG(DBG_info,"  Option %d: %s = %d\n", k, scanner->opt[k].name, scanner->val[k].w);
1639                 break;
1640             case SANE_TYPE_FIXED:
1641                 DBG(DBG_info,"  Option %d: %s = %f\n", k, scanner->opt[k].name, SANE_UNFIX (scanner->val[k].w));
1642                 break;
1643             case SANE_TYPE_STRING:
1644                 DBG(DBG_info,"  Option %d: %s = %s\n", k, scanner->opt[k].name, scanner->val[k].s);
1645                 break;
1646             case SANE_TYPE_GROUP:
1647                 DBG(DBG_info,"  Option %d: %s = %s\n", k, scanner->opt[k].title, scanner->val[k].s);
1648 	        break;
1649             default:
1650                 DBG(DBG_info,"  Option %d: %s unknown type %d\n", k, scanner->opt[k].name, scanner->opt[k].type);
1651                 break;
1652         }
1653     }
1654 }
1655 
1656 /**
1657  * Calculate reference values for each pixel, line means and line maxima.
1658  * We have got 45 lines for all four colors and for each CCD pixel.
1659  * The reference value for each pixel is the 45-line average for that
1660  * pixel, for each color separately.
1661  *
1662  * @param scanner
1663  * @param buffer
1664  */
pieusb_calculate_shading(struct Pieusb_Scanner *scanner, SANE_Byte* buffer)1665 static void pieusb_calculate_shading(struct Pieusb_Scanner *scanner, SANE_Byte* buffer)
1666 {
1667     int k, m;
1668     SANE_Byte* p;
1669     SANE_Int ci, val;
1670     SANE_Int shading_width = scanner->device->shading_parameters[0].pixelsPerLine;
1671     SANE_Int shading_height = scanner->device->shading_parameters[0].nLines;
1672 
1673     /* Initialize all to 0 */
1674     for (k = 0; k < SHADING_PARAMETERS_INFO_COUNT; k++) {
1675         scanner->shading_max[k] = 0;
1676         scanner->shading_mean[k] = 0;
1677         memset(scanner->shading_ref[k], 0, shading_width * sizeof (SANE_Int));
1678     }
1679     /* Process data from buffer */
1680     p = buffer;
1681     switch (scanner->mode.colorFormat) {
1682         case 0x01: /* Pixel */
1683             /* Process pixel by pixel */
1684             for (k = 0; k < shading_height; k++) {
1685                 for (m = 0; m < shading_width; m++) {
1686                     for (ci = 0; ci < SHADING_PARAMETERS_INFO_COUNT; ci++) {
1687                         val = *(p) + *(p+1) * 256;
1688                         scanner->shading_ref[ci][m] += val;
1689                         scanner->shading_max[ci] = scanner->shading_max[ci] < val ? val : scanner->shading_max[ci];
1690                         p += 2;
1691                     }
1692                 }
1693             }
1694             break;
1695         case 0x04: /* Indexed */
1696             /* Process each line in the sequence found in the buffer */
1697             for (k = 0; k < shading_height*4; k++) {
1698                 /* Save at right color */
1699                 switch (*p) {
1700                     case 'R': ci = 0; break;
1701                     case 'G': ci = 1; break;
1702                     case 'B': ci = 2; break;
1703                     case 'I': ci = 3; break;
1704                     default: ci = -1; break; /* ignore line */
1705                 }
1706                 /* Add scanned data to reference line and keep track of maximum */
1707                 if (ci != -1) {
1708                     for (m = 0; m < shading_width; m++) {
1709                         val = *(p+2+2*m) + *(p+2+2*m+1) * 256;
1710                         scanner->shading_ref[ci][m] += val;
1711                         scanner->shading_max[ci] = scanner->shading_max[ci] < val ? val : scanner->shading_max[ci];
1712                         /* DBG(DBG_error,"%02d Shading_ref[%d][%d] = %d\n",k,ci,m,scanner->shading_ref[ci][m]); */
1713                     }
1714                 }
1715                 /* Next line */
1716                 p += 2*shading_width+2;
1717             }
1718             break;
1719         default:
1720             DBG (DBG_error,"sane_start(): color format %d not implemented\n",scanner->mode.colorFormat);
1721             return;
1722     }
1723     /* Mean reference value needs division */
1724     for (k = 0; k < SHADING_PARAMETERS_INFO_COUNT; k++) {
1725         for (m = 0; m < shading_width; m++) {
1726             scanner->shading_ref[k][m] = lround((double)scanner->shading_ref[k][m]/shading_height);
1727             /* DBG(DBG_error,"Shading_ref[%d][%d] = %d\n",k,m,scanner->shading_ref[k][m]); */
1728         }
1729     }
1730     /* Overall means */
1731     for (k = 0; k < SHADING_PARAMETERS_INFO_COUNT; k++) {
1732         for (m=0; m<shading_width; m++) {
1733             scanner->shading_mean[k] += scanner->shading_ref[k][m];
1734         }
1735         scanner->shading_mean[k] = lround((double)scanner->shading_mean[k]/shading_width);
1736         DBG (DBG_error,"Shading_mean[%d] = %d\n",k,scanner->shading_mean[k]);
1737     }
1738 
1739     /* Set shading data present */
1740     scanner->shading_data_present = SANE_TRUE;
1741 
1742     /* Export shading data as TIFF */
1743 #ifdef CAN_DO_4_CHANNEL_TIFF
1744     if (scanner->val[OPT_SAVE_SHADINGDATA].b) {
1745         struct Pieusb_Read_Buffer shading;
1746         SANE_Byte* lboff = buffer;
1747         SANE_Int bpl = shading_width*2;
1748         SANE_Int n;
1749         buffer_create(&shading, shading_width, shading_height, 0x0F, 16);
1750         for (n=0; n<4*shading_height; n++) {
1751             if (buffer_put_single_color_line(&shading, *lboff, lboff+2, bpl) == 0) {
1752                 break;
1753             }
1754             lboff += (bpl + 2);
1755         }
1756         FILE* fs = fopen("pieusb.shading", "w");
1757         /* write_tiff_rgbi_header (fs, shading_width, shading_height, 16, 3600, NULL); */
1758         fwrite(shading.data, 1, shading.image_size_bytes, fs);
1759         fclose(fs);
1760         buffer_delete(&shading);
1761     }
1762 #endif
1763 
1764 }
1765 
1766 /*
1767  * Set frame (from scanner options)
1768  */
1769 
1770 SANE_Status
sanei_pieusb_set_frame_from_options(Pieusb_Scanner * scanner)1771 sanei_pieusb_set_frame_from_options(Pieusb_Scanner * scanner)
1772 {
1773     double dpmm;
1774     struct Pieusb_Command_Status status;
1775 
1776     dpmm = (double) scanner->device->maximum_resolution / MM_PER_INCH;
1777     scanner->frame.x0 = SANE_UNFIX(scanner->val[OPT_TL_X].w) * dpmm;
1778     scanner->frame.y0 = SANE_UNFIX(scanner->val[OPT_TL_Y].w) * dpmm;
1779     scanner->frame.x1 = SANE_UNFIX(scanner->val[OPT_BR_X].w) * dpmm;
1780     scanner->frame.y1 = SANE_UNFIX(scanner->val[OPT_BR_Y].w) * dpmm;
1781     scanner->frame.index = 0x80; /* 0x80: value from cyberview */
1782     sanei_pieusb_cmd_set_scan_frame (scanner->device_number, scanner->frame.index, &(scanner->frame), &status);
1783     DBG (DBG_info_sane, "sanei_pieusb_set_frame_from_options(): sanei_pieusb_cmd_set_scan_frame status %s\n", sane_strstatus (sanei_pieusb_convert_status (status.pieusb_status)));
1784     return sanei_pieusb_convert_status (status.pieusb_status);
1785 }
1786 
1787 /*
1788  * Set mode (from scanner options)
1789  */
1790 
1791 SANE_Status
sanei_pieusb_set_mode_from_options(Pieusb_Scanner * scanner)1792 sanei_pieusb_set_mode_from_options(Pieusb_Scanner * scanner)
1793 {
1794     struct Pieusb_Command_Status status;
1795     const char *mode;
1796     SANE_Status res;
1797 
1798     mode = scanner->val[OPT_MODE].s;
1799     if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) {
1800         scanner->mode.passes = SCAN_FILTER_GREEN; /* G */
1801         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_PIXEL;
1802     } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) {
1803         scanner->mode.passes = SCAN_FILTER_GREEN; /* G */
1804         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_PIXEL;
1805     } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) {
1806         scanner->mode.passes = SCAN_FILTER_GREEN; /* G=gray; unable to get R & B & I to work */
1807         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_PIXEL;
1808     } else if(scanner->val[OPT_PREVIEW].b) {
1809         /* Catch preview here, otherwise next ifs get complicated */
1810         scanner->mode.passes = SCAN_ONE_PASS_COLOR;
1811         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX; /* pixel format might be an alternative */
1812     } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_RGBI) == 0) {
1813         scanner->mode.passes = SCAN_ONE_PASS_RGBI;
1814         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX;
1815     } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0 && scanner->val[OPT_CLEAN_IMAGE].b) {
1816         scanner->mode.passes = SCAN_ONE_PASS_RGBI; /* Need infrared for cleaning */
1817         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX;
1818     } else { /* SANE_VALUE_SCAN_MODE_COLOR */
1819         scanner->mode.passes = SCAN_ONE_PASS_COLOR;
1820         scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX; /* pixel format might be an alternative */
1821     }
1822     /* Resolution */
1823     if (scanner->val[OPT_PREVIEW].b) {
1824         scanner->mode.resolution = scanner->device->fast_preview_resolution;
1825         DBG (DBG_info_sane, "sanei_pieusb_set_mode_from_options(): resolution fast preview (%d)\n", scanner->mode.resolution);
1826     } else {
1827         scanner->mode.resolution = SANE_UNFIX (scanner->val[OPT_RESOLUTION].w);
1828         DBG (DBG_info_sane, "sanei_pieusb_set_mode_from_options(): resolution from option setting (%d)\n", scanner->mode.resolution);
1829     }
1830     /* Bit depth: exit on untested values */
1831     switch (scanner->val[OPT_BIT_DEPTH].w) {
1832         case 1: scanner->mode.colorDepth = SCAN_COLOR_DEPTH_1; break;
1833         case 8: scanner->mode.colorDepth = SCAN_COLOR_DEPTH_8; break;
1834         case 16: scanner->mode.colorDepth = SCAN_COLOR_DEPTH_16; break;
1835         default: /* 4, 10 & 12 */
1836             DBG (DBG_error, "sanei_pieusb_set_mode_from_options(): sanei_pieusb_cmd_set_scan_frame untested bit depth %d\n", scanner->val[OPT_BIT_DEPTH].w);
1837             return SANE_STATUS_INVAL;
1838     }
1839     scanner->mode.byteOrder = 0x01; /* 0x01 = Intel; only bit 0 used */
1840     scanner->mode.sharpen = scanner->val[OPT_SHARPEN].b && !scanner->val[OPT_PREVIEW].b;
1841     scanner->mode.skipShadingAnalysis = !scanner->val[OPT_SHADING_ANALYSIS].b;
1842     scanner->mode.fastInfrared = scanner->val[OPT_FAST_INFRARED].b && !scanner->val[OPT_PREVIEW].b;
1843     if (strcmp (scanner->val[OPT_HALFTONE_PATTERN].s, "53lpi 45d ROUND") == 0) {
1844         scanner->mode.halftonePattern = 0;
1845     } else { /*TODO: the others */
1846         scanner->mode.halftonePattern = 0;
1847     }
1848     scanner->mode.lineThreshold = SANE_UNFIX (scanner->val[OPT_THRESHOLD].w) / 100 * 0xFF; /* 0xFF = 100% */
1849     sanei_pieusb_cmd_set_mode (scanner->device_number, &(scanner->mode), &status);
1850     res = sanei_pieusb_convert_status(status.pieusb_status);
1851     if (res == SANE_STATUS_GOOD) {
1852       res = sanei_pieusb_wait_ready (scanner, 0);
1853     }
1854     DBG (DBG_info_sane, "sanei_pieusb_set_mode_from_options(): sanei_pieusb_cmd_set_mode status %s\n", sane_strstatus(res));
1855     return res;
1856 }
1857 
1858 /**
1859  * Set gains, exposure and offset, to:
1860  * - values default (pieusb_set_default_gain_offset)
1861  * - values set by options
1862  * - values set by auto-calibration procedure
1863  * - values determined from preceding preview
1864  *
1865  * @param scanner
1866  * @return
1867  */
1868 SANE_Status
sanei_pieusb_set_gain_offset(Pieusb_Scanner * scanner, const char *calibration_mode)1869 sanei_pieusb_set_gain_offset(Pieusb_Scanner * scanner, const char *calibration_mode)
1870 {
1871     struct Pieusb_Command_Status status;
1872     SANE_Status ret;
1873     double gain;
1874 
1875     DBG (DBG_info,"sanei_pieusb_set_gain_offset(): mode = %s\n", calibration_mode);
1876 
1877     if (strcmp (calibration_mode, SCAN_CALIBRATION_DEFAULT) == 0) {
1878         /* Default values */
1879         DBG(DBG_info_sane,"sanei_pieusb_set_gain_offset(): get calibration data from defaults\n");
1880         scanner->settings.exposureTime[0] = DEFAULT_EXPOSURE;
1881         scanner->settings.exposureTime[1] = DEFAULT_EXPOSURE;
1882         scanner->settings.exposureTime[2] = DEFAULT_EXPOSURE;
1883         scanner->settings.exposureTime[3] = DEFAULT_EXPOSURE;
1884         scanner->settings.offset[0] = DEFAULT_OFFSET;
1885         scanner->settings.offset[1] = DEFAULT_OFFSET;
1886         scanner->settings.offset[2] = DEFAULT_OFFSET;
1887         scanner->settings.offset[3] = DEFAULT_OFFSET;
1888         scanner->settings.gain[0] = DEFAULT_GAIN;
1889         scanner->settings.gain[1] = DEFAULT_GAIN;
1890         scanner->settings.gain[2] = DEFAULT_GAIN;
1891         scanner->settings.gain[3] = DEFAULT_GAIN;
1892         scanner->settings.light = DEFAULT_LIGHT;
1893         scanner->settings.extraEntries = DEFAULT_ADDITIONAL_ENTRIES;
1894         scanner->settings.doubleTimes = DEFAULT_DOUBLE_TIMES;
1895         status.pieusb_status = PIEUSB_STATUS_GOOD;
1896     } else if ((strcmp(calibration_mode, SCAN_CALIBRATION_PREVIEW) == 0)
1897 	       && scanner->preview_done) {
1898         /* If no preview data available, do the auto-calibration. */
1899         double dg, dgi;
1900         DBG (DBG_info, "sanei_pieusb_set_gain_offset(): get calibration data from preview. scanner->mode.passes %d\n", scanner->mode.passes);
1901         switch (scanner->mode.passes) {
1902             case SCAN_ONE_PASS_RGBI:
1903                 dg = 3.00;
1904                 dgi = ((double)scanner->settings.saturationLevel[0] / 65536) / ((double)scanner->preview_upper_bound[0] / HISTOGRAM_SIZE);
1905                 if (dgi < dg) dg = dgi;
1906                 dgi = ((double)scanner->settings.saturationLevel[1] / 65536) / ((double)scanner->preview_upper_bound[1] / HISTOGRAM_SIZE);
1907                 if (dgi < dg) dg = dgi;
1908                 dgi = ((double)scanner->settings.saturationLevel[2] / 65536) / ((double)scanner->preview_upper_bound[2] / HISTOGRAM_SIZE);
1909                 if (dgi < dg) dg = dgi;
1910                 updateGain2(scanner, 0, dg);
1911                 updateGain2(scanner, 1, dg);
1912                 updateGain2(scanner, 2, dg);
1913 	    break;
1914             case SCAN_ONE_PASS_COLOR:
1915                 dg = 3.00;
1916                 dgi = ((double)scanner->settings.saturationLevel[0] / 65536) / ((double)scanner->preview_upper_bound[0] / HISTOGRAM_SIZE);
1917                 if (dgi < dg) dg = dgi;
1918                 dgi = ((double)scanner->settings.saturationLevel[1] / 65536) / ((double)scanner->preview_upper_bound[1] / HISTOGRAM_SIZE);
1919                 if (dgi < dg) dg = dgi;
1920                 dgi = ((double)scanner->settings.saturationLevel[2] / 65536) / ((double)scanner->preview_upper_bound[2] / HISTOGRAM_SIZE);
1921                 if (dgi < dg) dg = dgi;
1922                 updateGain2(scanner, 0, dg);
1923                 updateGain2(scanner, 1, dg);
1924                 updateGain2(scanner, 2, dg);
1925                 break;
1926             case SCAN_FILTER_BLUE:
1927                 dg = 3.00;
1928                 dgi = ((double)scanner->settings.saturationLevel[2] / 65536) / ((double)scanner->preview_upper_bound[2] / HISTOGRAM_SIZE);
1929                 if (dgi < dg) dg = dgi;
1930                 updateGain2(scanner, 2, dg);
1931                 break;
1932             case SCAN_FILTER_GREEN:
1933                 dg = 3.00;
1934                 dgi = ((double)scanner->settings.saturationLevel[1] / 65536) / ((double)scanner->preview_upper_bound[1] / HISTOGRAM_SIZE);
1935                 if (dgi < dg) dg = dgi;
1936                 updateGain2(scanner, 1, dg);
1937                 break;
1938             case SCAN_FILTER_RED:
1939                 dg = 3.00;
1940                 dgi = ((double)scanner->settings.saturationLevel[0] / 65536) / ((double)scanner->preview_upper_bound[0] / HISTOGRAM_SIZE);
1941                 if (dgi < dg) dg = dgi;
1942                 updateGain2(scanner, 0, dg);
1943                 break;
1944             case SCAN_FILTER_NEUTRAL:
1945                 break;
1946         }
1947         status.pieusb_status = PIEUSB_STATUS_GOOD;
1948     } else if (strcmp (calibration_mode, SCAN_CALIBRATION_OPTIONS) == 0) {
1949         DBG (DBG_info_sane, "sanei_pieusb_set_gain_offset(): get calibration data from options\n");
1950         /* Exposure times */
1951         scanner->settings.exposureTime[0] = scanner->val[OPT_SET_EXPOSURE_R].w;
1952         scanner->settings.exposureTime[1] = scanner->val[OPT_SET_EXPOSURE_G].w;
1953         scanner->settings.exposureTime[2] = scanner->val[OPT_SET_EXPOSURE_B].w;
1954         scanner->settings.exposureTime[3] = scanner->val[OPT_SET_EXPOSURE_I].w; /* Infrared */
1955         /* Offsets */
1956         scanner->settings.offset[0] = scanner->val[OPT_SET_OFFSET_R].w;
1957         scanner->settings.offset[1] = scanner->val[OPT_SET_OFFSET_G].w;
1958         scanner->settings.offset[2] = scanner->val[OPT_SET_OFFSET_B].w;
1959         scanner->settings.offset[3] = scanner->val[OPT_SET_OFFSET_I].w; /* Infrared */
1960         /* Gains */
1961         scanner->settings.gain[0] = scanner->val[OPT_SET_GAIN_R].w;
1962         scanner->settings.gain[1] = scanner->val[OPT_SET_GAIN_G].w;
1963         scanner->settings.gain[2] = scanner->val[OPT_SET_GAIN_B].w;
1964         scanner->settings.gain[3] = scanner->val[OPT_SET_GAIN_I].w; /* Infrared */
1965         /* Light, extra entries and doubling */
1966         scanner->settings.light = scanner->val[OPT_LIGHT].w;
1967         scanner->settings.extraEntries = DEFAULT_ADDITIONAL_ENTRIES;
1968         scanner->settings.doubleTimes = scanner->val[OPT_DOUBLE_TIMES].w;
1969         status.pieusb_status = PIEUSB_STATUS_GOOD;
1970     } else { /* SCAN_CALIBRATION_AUTO */
1971         DBG (DBG_info_sane, "sanei_pieusb_set_gain_offset(): get calibration data from scanner\n");
1972         sanei_pieusb_cmd_get_gain_offset (scanner->device_number, &scanner->settings, &status);
1973     }
1974     /* Check status */
1975     if (status.pieusb_status == PIEUSB_STATUS_DEVICE_BUSY) {
1976       ret = sanei_pieusb_wait_ready (scanner, 0);
1977       if (ret != SANE_STATUS_GOOD) {
1978 	DBG (DBG_error,"sanei_pieusb_set_gain_offset(): not ready after sanei_pieusb_cmd_get_gain_offset(): %d\n", ret);
1979 	return ret;
1980       }
1981     }
1982     else if (status.pieusb_status != PIEUSB_STATUS_GOOD) {
1983         return SANE_STATUS_INVAL;
1984     }
1985     /* Adjust gain */
1986     gain = 1.0;
1987     if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_03) == 0) {
1988         gain = 0.3;
1989     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_05) == 0) {
1990         gain = 0.5;
1991     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_08) == 0) {
1992         gain = 0.8;
1993     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_10) == 0) {
1994         gain = 1.0;
1995     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_12) == 0) {
1996         gain = 1.2;
1997     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_16) == 0) {
1998         gain = 1.6;
1999     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_19) == 0) {
2000         gain = 1.9;
2001     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_24) == 0) {
2002         gain = 2.4;
2003     } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_30) == 0) {
2004         gain = 3.0;
2005     }
2006     switch (scanner->mode.passes) {
2007         case SCAN_ONE_PASS_RGBI:
2008         case SCAN_ONE_PASS_COLOR:
2009             updateGain2 (scanner, 0, gain);
2010             updateGain2 (scanner, 1, gain);
2011             updateGain2 (scanner, 2, gain);
2012             /* Don't correct IR, hampers cleaning process... */
2013             break;
2014         case SCAN_FILTER_INFRARED:
2015             updateGain2 (scanner, 3, gain);
2016             break;
2017         case SCAN_FILTER_BLUE:
2018             updateGain2 (scanner, 2, gain);
2019             break;
2020         case SCAN_FILTER_GREEN:
2021             updateGain2 (scanner, 1, gain);
2022             break;
2023         case SCAN_FILTER_RED:
2024             updateGain2 (scanner, 0, gain);
2025             break;
2026         case SCAN_FILTER_NEUTRAL:
2027             break;
2028     }
2029     /* Now set values for gain, offset and exposure */
2030     sanei_pieusb_cmd_set_gain_offset (scanner->device_number, &(scanner->settings), &status);
2031     ret = sanei_pieusb_convert_status (status.pieusb_status);
2032     DBG (DBG_info_sane, "sanei_pieusb_set_gain_offset(): status %s\n", sane_strstatus (ret));
2033     return ret;
2034 }
2035 
2036 /*
2037  * get shading data
2038  * must be called immediately after sanei_pieusb_set_gain_offset
2039  */
2040 
2041 SANE_Status
sanei_pieusb_get_shading_data(Pieusb_Scanner * scanner)2042 sanei_pieusb_get_shading_data(Pieusb_Scanner * scanner)
2043 {
2044     struct Pieusb_Command_Status status;
2045     SANE_Int shading_width;
2046     SANE_Int shading_height;
2047     SANE_Byte* buffer;
2048     SANE_Int lines;
2049     SANE_Int cols;
2050     SANE_Int size;
2051     SANE_Status res = SANE_STATUS_GOOD;
2052 
2053     DBG (DBG_info_sane, "sanei_pieusb_get_shading_data()\n");
2054     shading_width = scanner->device->shading_parameters[0].pixelsPerLine;
2055     shading_height = scanner->device->shading_parameters[0].nLines;
2056     if (shading_height < 1) {
2057         DBG (DBG_error, "shading_height < 1\n");
2058 	return SANE_STATUS_INVAL;
2059     }
2060     switch (scanner->mode.colorFormat) {
2061         case SCAN_COLOR_FORMAT_PIXEL: /* Pixel */
2062             lines = shading_height * 4;
2063             cols = 2 * shading_width;
2064             break;
2065         case SCAN_COLOR_FORMAT_INDEX: /* Indexed */
2066             lines = shading_height * 4;
2067             cols = (2 * shading_width + 2);
2068             break;
2069         default:
2070             DBG (DBG_error, "sanei_pieusb_get_shading_data(): color format %d not implemented\n", scanner->mode.colorFormat);
2071             return SANE_STATUS_INVAL;
2072     }
2073 
2074     size = cols * lines;
2075     buffer = malloc (size);
2076     if (buffer == NULL) {
2077         return SANE_STATUS_NO_MEM;
2078     }
2079     sanei_pieusb_cmd_get_scanned_lines (scanner->device_number, buffer, 4, cols * 4, &status);
2080     if (status.pieusb_status == PIEUSB_STATUS_GOOD) {
2081         res = sanei_pieusb_wait_ready (scanner, 0);
2082         if (res == SANE_STATUS_GOOD) {
2083             sanei_pieusb_cmd_get_scanned_lines (scanner->device_number, buffer + cols*4, lines - 4, (lines - 4) * cols, &status);
2084 	    if (status.pieusb_status == PIEUSB_STATUS_GOOD) {
2085 	        pieusb_calculate_shading (scanner, buffer);
2086 	    }
2087 	    res = sanei_pieusb_convert_status (status.pieusb_status);
2088 	}
2089     }
2090     else {
2091         res = sanei_pieusb_convert_status (status.pieusb_status);
2092     }
2093     free (buffer);
2094     return res;
2095 }
2096 
2097 /*
2098  *
2099  */
2100 
2101 SANE_Status
sanei_pieusb_get_ccd_mask(Pieusb_Scanner * scanner)2102 sanei_pieusb_get_ccd_mask(Pieusb_Scanner * scanner)
2103 {
2104     struct Pieusb_Command_Status status;
2105 
2106     DBG(DBG_info_proc, "sanei_pieusb_get_ccd_mask()\n");
2107 
2108     sanei_pieusb_cmd_get_ccd_mask(scanner->device_number, scanner->ccd_mask, scanner->ccd_mask_size, &status);
2109     if (status.pieusb_status == PIEUSB_STATUS_GOOD) {
2110       /* Save CCD mask */
2111       if (scanner->val[OPT_SAVE_CCDMASK].b) {
2112         FILE* fs = fopen ("pieusb.ccd", "w");
2113         fwrite (scanner->ccd_mask, 1, scanner->ccd_mask_size, fs);
2114         fclose (fs);
2115       }
2116     }
2117   return sanei_pieusb_convert_status(status.pieusb_status);
2118 
2119 }
2120 
2121 /**
2122  * Read parameters from scanner
2123  * and initialize SANE parameters
2124  *
2125  * @param scanner
2126  * @return parameter_bytes for use in get_scan_data()
2127  */
2128 SANE_Status
sanei_pieusb_get_parameters(Pieusb_Scanner * scanner, SANE_Int *parameter_bytes)2129 sanei_pieusb_get_parameters(Pieusb_Scanner * scanner, SANE_Int *parameter_bytes)
2130 {
2131     struct Pieusb_Command_Status status;
2132     struct Pieusb_Scan_Parameters parameters;
2133     const char *mode;
2134 
2135     DBG (DBG_info_proc, "sanei_pieusb_get_parameters()\n");
2136 
2137     sanei_pieusb_cmd_get_parameters (scanner->device_number, &parameters, &status);
2138     if (status.pieusb_status != PIEUSB_STATUS_GOOD) {
2139         return sanei_pieusb_convert_status (status.pieusb_status);
2140     }
2141     *parameter_bytes = parameters.bytes;
2142     /* Use response from sanei_pieusb_cmd_get_parameters() for initialization of SANE parameters.
2143      * Note the weird values of the bytes-field: this is because of the colorFormat
2144      * setting in sanei_pieusb_cmd_set_mode(). The single-color modes all use the pixel format,
2145      * which makes sanei_pieusb_cmd_get_parameters() return a full color line although just
2146      * one color actually contains data. For the index format, the bytes field
2147      * gives the size of a single color line. */
2148     mode = scanner->val[OPT_MODE].s;
2149     if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) {
2150         scanner->scan_parameters.format = SANE_FRAME_GRAY;
2151         scanner->scan_parameters.depth = 1;
2152         scanner->scan_parameters.bytes_per_line = parameters.bytes/3;
2153     } else if (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) {
2154         scanner->scan_parameters.format = SANE_FRAME_GRAY;
2155         scanner->scan_parameters.depth = 1;
2156         scanner->scan_parameters.bytes_per_line = parameters.bytes/3;
2157     } else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) {
2158         scanner->scan_parameters.format = SANE_FRAME_GRAY;
2159         scanner->scan_parameters.depth = scanner->val[OPT_BIT_DEPTH].w;
2160         scanner->scan_parameters.bytes_per_line = parameters.bytes/3;
2161     } else if (strcmp (mode, SANE_VALUE_SCAN_MODE_RGBI) == 0) {
2162         scanner->scan_parameters.format = SANE_FRAME_RGB; /* was: SANE_FRAME_RGBI */
2163         scanner->scan_parameters.depth = scanner->val[OPT_BIT_DEPTH].w;
2164         scanner->scan_parameters.bytes_per_line = 4*parameters.bytes;
2165     } else { /* SANE_VALUE_SCAN_MODE_COLOR, with and without option clean image set */
2166         scanner->scan_parameters.format = SANE_FRAME_RGB;
2167         scanner->scan_parameters.depth = scanner->val[OPT_BIT_DEPTH].w;
2168         scanner->scan_parameters.bytes_per_line = 3*parameters.bytes;
2169     }
2170     scanner->scan_parameters.lines = parameters.lines;
2171     scanner->scan_parameters.pixels_per_line = parameters.width;
2172     scanner->scan_parameters.last_frame = SANE_TRUE;
2173 
2174     DBG (DBG_info_sane,"sanei_pieusb_get_parameters(): mode '%s'\n", mode);
2175     DBG (DBG_info_sane," format = %d\n", scanner->scan_parameters.format);
2176     DBG (DBG_info_sane," depth = %d\n", scanner->scan_parameters.depth);
2177     DBG (DBG_info_sane," bytes_per_line = %d\n", scanner->scan_parameters.bytes_per_line);
2178     DBG (DBG_info_sane," lines = %d\n", scanner->scan_parameters.lines);
2179     DBG (DBG_info_sane," pixels_per_line = %d\n", scanner->scan_parameters.pixels_per_line);
2180     DBG (DBG_info_sane," last_frame = %d\n", scanner->scan_parameters.last_frame);
2181 
2182     return SANE_STATUS_GOOD;
2183 }
2184 
2185 SANE_Status
sanei_pieusb_get_scan_data(Pieusb_Scanner * scanner, SANE_Int parameter_bytes)2186 sanei_pieusb_get_scan_data(Pieusb_Scanner * scanner, SANE_Int parameter_bytes)
2187 {
2188     struct Pieusb_Command_Status status;
2189     SANE_Parameters *parameters = &scanner->scan_parameters;
2190     SANE_Int lines_to_read, lines_remaining;
2191     SANE_Int ppl, bpl;
2192     SANE_Byte *linebuf, *lboff;
2193     SANE_Bool compress;
2194     int n, k, i;
2195 
2196     switch (scanner->mode.colorFormat) {
2197         case SCAN_COLOR_FORMAT_PIXEL: /* Pixel */
2198             lines_to_read = scanner->buffer.height;
2199             break;
2200         case SCAN_COLOR_FORMAT_INDEX: /* Indexed */
2201             lines_to_read = scanner->buffer.colors * scanner->buffer.height;
2202             break;
2203         default:
2204             DBG(DBG_error, "sanei_pieusb_get_scan_data(): color format %d not implemented\n",scanner->mode.colorFormat);
2205             return SANE_STATUS_INVAL;
2206     }
2207     lines_remaining = lines_to_read;
2208     DBG (DBG_info_proc, "sanei_pieusb_get_scan_data(colorFormat %d), lines_to_read %d, bytes %d\n", scanner->mode.colorFormat, lines_to_read, parameter_bytes);
2209 
2210   /*
2211     fdraw = open("/tmp/pieusb.raw", O_WRONLY | O_CREAT | O_TRUNC, (mode_t)0600);
2212     if (fdraw == -1) {
2213          perror("error opening raw image buffer file");
2214     }
2215 */
2216     while (lines_remaining > 0) {
2217         SANE_Int lines;
2218         /* Read lines */
2219         /* The amount of bytes_per_line varies with color format setting; only 'pixel' and 'index' implemented */
2220         ppl = parameters->pixels_per_line;
2221         switch (scanner->mode.colorFormat) {
2222 	    case SCAN_COLOR_FORMAT_PIXEL: /* Pixel */
2223 	        bpl = parameter_bytes;
2224 	        break;
2225             case SCAN_COLOR_FORMAT_INDEX: /* Indexed */
2226 	        bpl = parameter_bytes + 2; /* Index bytes! */
2227 	        break;
2228             default:
2229 	        DBG(DBG_error, "sanei_pieusb_get_scan_data(): color format %d not implemented\n", scanner->mode.colorFormat);
2230 	        return SANE_STATUS_INVAL;
2231         }
2232         lines = (lines_remaining < 256) ? lines_remaining : 255;
2233         DBG(DBG_info_sane, "sanei_pieusb_get_scan_data(): reading lines: now %d, bytes per line = %d\n", lines, bpl);
2234         linebuf = malloc(lines * bpl);
2235         sanei_pieusb_cmd_get_scanned_lines(scanner->device_number, linebuf, lines, lines * bpl, &status);
2236         if (status.pieusb_status != PIEUSB_STATUS_GOOD ) {
2237 	    /* Error, return */
2238 	    free(linebuf);
2239 	    return SANE_STATUS_INVAL;
2240 	}
2241         /* Save raw data */
2242 /*
2243         if (fdraw != -1) {
2244             wcnt = write(fdraw,linebuf,parameters.lines*bpl);
2245             DBG(DBG_info_sane,"Raw written %d\n",wcnt);
2246         }
2247 */
2248         /* Copy into official buffer
2249 	 * Sometimes the scanner returns too many lines. Take care not to
2250 	 * overflow the buffer. */
2251         lboff = linebuf;
2252         switch (scanner->mode.colorFormat) {
2253 	    case SCAN_COLOR_FORMAT_PIXEL:
2254 	        /* The scanner may return lines with 3 colors even though only
2255 		 * one color is actually scanned. Detect this situation and
2256 		 * eliminate the excess samples from the line buffer before
2257 		 * handing it to buffer_put_full_color_line(). */
2258 	        compress = SANE_FALSE;
2259 	        if (scanner->buffer.colors == 1
2260 		    && (bpl * scanner->buffer.packing_density / ppl) == (3 * scanner->buffer.packet_size_bytes)) {
2261 		    compress = SANE_TRUE;
2262 	        }
2263 	        for (n = 0; n < lines; n++) {
2264 		     if (compress) {
2265 		         /* Move samples to fill up all unused locations */
2266 		         int ps = scanner->buffer.packet_size_bytes;
2267 		         for (k = 0; k < scanner->buffer.line_size_packets; k++) {
2268 			     for (i = 0; i < ps; i++) {
2269 			         lboff[ps*k+i] = lboff[3*ps*k+i];
2270 			     }
2271 			 }
2272 		     }
2273 		     if (sanei_pieusb_buffer_put_full_color_line(&scanner->buffer, lboff, bpl/3) == 0) {
2274 		         /* Error, return */
2275 		         return SANE_STATUS_INVAL;
2276 		     }
2277 		     lboff += bpl;
2278 	        }
2279 	        break;
2280 	    case SCAN_COLOR_FORMAT_INDEX:
2281 	        /* Indexed data */
2282 	        for (n = 0; n < lines; n++) {
2283 		    if (sanei_pieusb_buffer_put_single_color_line(&scanner->buffer, *lboff, lboff+2, bpl-2) == 0) {
2284 		        /* Error, return */
2285 		        return SANE_STATUS_INVAL;
2286 		    }
2287 		    lboff += bpl;
2288 	        }
2289 	        break;
2290 	    default:
2291 	        DBG(DBG_error, "sanei_pieusb_get_scan_data(): store color format %d not implemented\n", scanner->mode.colorFormat);
2292 	        free(linebuf);
2293 	        return SANE_STATUS_INVAL;
2294         }
2295         free(linebuf);
2296         lines_remaining -= lines; /* Note: excess discarded */
2297         DBG(DBG_info_sane, "sanei_pieusb_get_scan_data(): reading lines: remaining %d\n", lines_remaining);
2298     }
2299 /*
2300     if (fdraw != -1) close(fdraw);
2301 */
2302     return SANE_STATUS_GOOD;
2303 }
2304 
2305 /**
2306  * Wait for scanner to get ready
2307  *
2308  * loop of test_ready/read_state
2309  *
2310  * @param scanner
2311  * @param device_number, used if scanner == NULL
2312  * @return SANE_Status
2313  */
2314 
2315 SANE_Status
sanei_pieusb_wait_ready(Pieusb_Scanner * scanner, SANE_Int device_number)2316 sanei_pieusb_wait_ready(Pieusb_Scanner * scanner, SANE_Int device_number)
2317 {
2318   struct Pieusb_Command_Status status;
2319   struct Pieusb_Scanner_State state;
2320   time_t start, elapsed;
2321 
2322   DBG (DBG_info_proc, "sanei_pieusb_wait_ready()\n");
2323   start = time(NULL);
2324   if (scanner)
2325     device_number = scanner->device_number;
2326 
2327   for(;;) {
2328     sanei_pieusb_cmd_test_unit_ready(device_number, &status);
2329     DBG (DBG_info_proc, "-> sanei_pieusb_cmd_test_unit_ready: %d\n", status.pieusb_status);
2330     if (status.pieusb_status == PIEUSB_STATUS_GOOD)
2331       break;
2332     if (status.pieusb_status == PIEUSB_STATUS_IO_ERROR)
2333       break;
2334     sanei_pieusb_cmd_read_state(device_number, &state, &status);
2335     DBG (DBG_info_proc, "-> sanei_pieusb_cmd_read_state: %d\n", status.pieusb_status);
2336     if (status.pieusb_status != PIEUSB_STATUS_DEVICE_BUSY)
2337       break;
2338     sleep(2);
2339     elapsed = time(NULL) - start;
2340     if (elapsed > 120) { /* 2 minute overall timeout */
2341       DBG (DBG_error, "scanner not ready after 2 minutes\n");
2342       break;
2343     }
2344     if (elapsed % 2) {
2345       DBG (DBG_info, "still waiting for scanner to get ready\n");
2346     }
2347   }
2348   return sanei_pieusb_convert_status(status.pieusb_status);
2349 }
2350 
2351 
sanei_pieusb_analyze_preview(Pieusb_Scanner * scanner)2352 SANE_Status sanei_pieusb_analyze_preview(Pieusb_Scanner * scanner)
2353 {
2354     int k, n;
2355     SANE_Parameters params;
2356     SANE_Int N;
2357     double *norm_histo;
2358     double level;
2359 
2360     DBG(DBG_info, "sanei_pieusb_analyze_preview(): saving preview data\n");
2361 
2362     /* Settings */
2363     scanner->preview_done = SANE_TRUE;
2364     for (k = 0; k < 4; k++) {
2365         scanner->preview_exposure[k] = scanner->settings.exposureTime[k];
2366         scanner->preview_gain[k] = scanner->settings.gain[k];
2367         scanner->preview_offset[k] = scanner->settings.offset[k];
2368     }
2369     /* Analyze color planes */
2370     N = scanner->buffer.width * scanner->buffer.height;
2371     params.format = SANE_FRAME_GRAY;
2372     params.depth = scanner->buffer.depth;
2373     params.pixels_per_line = scanner->buffer.width;
2374     params.lines = scanner->buffer.height;
2375     for (k = 0; k < scanner->buffer.colors; k++) {
2376         /* Create histogram for color k */
2377         sanei_ir_create_norm_histogram (&params, scanner->buffer.data + k * N, &norm_histo);
2378         /* Find 1% and 99% limits */
2379         level = 0;
2380         for (n =0; n < HISTOGRAM_SIZE; n++) {
2381 
2382             level += norm_histo[n];
2383             if (level < 0.01) {
2384                 scanner->preview_lower_bound[k] = n;
2385             }
2386             if (level < 0.99) {
2387                 scanner->preview_upper_bound[k] = n;
2388             }
2389         }
2390         DBG(DBG_info,"sanei_pieusb_analyze_preview(): 1%%-99%% levels for color %d: %d - %d\n", k, scanner->preview_lower_bound[k], scanner->preview_upper_bound[k]);
2391     }
2392     /* Disable remaining color planes */
2393     for (k = scanner->buffer.colors; k < 4; k++) {
2394         scanner->preview_lower_bound[k] = 0;
2395         scanner->preview_upper_bound[k] = 0;
2396     }
2397     return SANE_STATUS_GOOD;
2398 }
2399 
2400 
2401 /**
2402  * Return actual gain at given gain setting
2403  *
2404  * @param gain Gain setting (0 - 63)
2405  * @return
2406  */
getGain(int gain)2407 static double getGain(int gain)
2408 {
2409     int k;
2410 
2411     /* Actually an error, but don't be picky */
2412     if (gain <= 0) {
2413         return gains[0];
2414     }
2415     /* A gain > 63 is also an error, but don't be picky */
2416     if (gain >= 60) {
2417         return (gain-55)*(gains[12]-gains[11])/5 + gains[11];
2418     }
2419     /* Interpolate other values */
2420     k = gain/5; /* index of array value just below given gain */
2421     return (gain-5*k)*(gains[k+1]-gains[k])/5 + gains[k];
2422 }
2423 
getGainSetting(double gain)2424 static int getGainSetting(double gain)
2425 {
2426     int k, m;
2427 
2428     /* Out of bounds */
2429     if (gain < 1.0) {
2430         return 0;
2431     }
2432     if (gain >= gains[12]) {
2433         m = 60 + lround((gain-gains[11])/(gains[12]-gains[11])*5);
2434         if (m > 63) m = 63;
2435         return m;
2436     }
2437     /* Interpolate the rest */
2438     m = 0;
2439     for (k = 0; k <= 11; k++) {
2440         if (gains[k] <= gain && gain < gains[k+1]) {
2441             m = 5*k + lround((gain-gains[k])/(gains[k+1]-gains[k])*5);
2442         }
2443     }
2444     return m;
2445 }
2446 
2447 /**
2448  * Modify gain and exposure times in order to make maximal use of the scan depth.
2449  * Each color treated separately, infrared excluded.
2450  *
2451  * This may be too aggressive => leads to a noisy whitish border instead of the orange.
2452  * In a couuple of tries, gain was set to values of 60 and above, which introduces
2453  * the noise?
2454  * The whitish border is logical since the brightest parts of the negative, the
2455  * unexposed borders, are amplified to values near CCD saturation, which is white.
2456  * Maybe a uniform gain increase for each color is more appropriate? Somewhere
2457  * between 2.5 and 3 seems worthwhile trying, see updateGain2().
2458  *
2459         switch (scanner->mode.passes) {
2460             case SCAN_ONE_PASS_RGBI:
2461                 updateGain(scanner,0);
2462                 updateGain(scanner,1);
2463                 updateGain(scanner,2);
2464                 updateGain(scanner,3);
2465                 break;
2466             case SCAN_ONE_PASS_COLOR:
2467                 updateGain(scanner,0);
2468                 updateGain(scanner,1);
2469                 updateGain(scanner,2);
2470                 break;
2471             case SCAN_FILTER_INFRARED:
2472                 updateGain(scanner,3);
2473                 break;
2474             case SCAN_FILTER_BLUE:
2475                 updateGain(scanner,2);
2476                 break;
2477             case SCAN_FILTER_GREEN:
2478                 updateGain(scanner,1);
2479                 break;
2480             case SCAN_FILTER_RED:
2481                 updateGain(scanner,0);
2482                 break;
2483             case SCAN_FILTER_NEUTRAL:
2484                 break;
2485         }
2486  * @param scanner
2487  */
2488 /*
2489 static void updateGain(Pieusb_Scanner *scanner, int color_index)
2490 {
2491     double g, dg;
2492 
2493     DBG(DBG_info_sane,"updateGain(): color %d preview used G=%d Exp=%d\n", color_index, scanner->preview_gain[color_index], scanner->preview_exposure[color_index]);
2494     // Additional gain to obtain
2495     dg = ((double)scanner->settings.saturationLevel[color_index] / 65536) / ((double)scanner->preview_upper_bound[color_index] / HISTOGRAM_SIZE);
2496     DBG(DBG_info_sane,"updateGain(): additional gain %f\n", dg);
2497     // Achieve this by modifying gain and exposure
2498     // Gain used for preview
2499     g = getGain(scanner->preview_gain[color_index]);
2500     DBG(DBG_info_sane,"updateGain(): preview had gain %d => %f\n",scanner->preview_gain[color_index],g);
2501     // Look up new gain setting g*sqrt(dg)
2502     DBG(DBG_info_sane,"updateGain(): optimized gain * %f = %f\n",sqrt(dg),sqrt(dg)*g);
2503     scanner->settings.gain[color_index] = getGainSetting(g*sqrt(dg));
2504     DBG(DBG_info_sane,"updateGain(): optimized gain setting %d => %f\n",scanner->settings.gain[color_index],getGain(scanner->settings.gain[color_index]));
2505     // Exposure change is straightforward
2506     DBG(DBG_info_sane,"updateGain(): remains for exposure %f\n",dg/(getGain(scanner->settings.gain[color_index])/g));
2507     scanner->settings.exposureTime[color_index] = lround( g / getGain(scanner->settings.gain[color_index]) * dg * scanner->preview_exposure[color_index] );
2508     DBG(DBG_info_sane,"updateGain(): new setting G=%d Exp=%d\n", scanner->settings.gain[color_index], scanner->settings.exposureTime[color_index]);
2509 }
2510 */
2511 
updateGain2(Pieusb_Scanner *scanner, int color_index, double gain_increase)2512 static void updateGain2(Pieusb_Scanner *scanner, int color_index, double gain_increase)
2513 {
2514     double g;
2515 
2516     DBG(DBG_info,"updateGain2(): color %d preview used G=%d Exp=%d\n", color_index, scanner->settings.gain[color_index], scanner->settings.exposureTime[color_index]);
2517     /* Additional gain to obtain */
2518     DBG(DBG_info,"updateGain2(): additional gain %f\n", gain_increase);
2519     /* Achieve this by modifying gain and exposure */
2520     /* Gain used for preview */
2521     g = getGain(scanner->settings.gain[color_index]);
2522     DBG(DBG_info,"updateGain2(): preview had gain %d => %f\n", scanner->settings.gain[color_index], g);
2523     /* Look up new gain setting g*sqrt(dg) */
2524     DBG(DBG_info,"updateGain2(): optimized gain * %f = %f\n", sqrt(gain_increase), sqrt(gain_increase) * g);
2525     scanner->settings.gain[color_index] = getGainSetting(g * sqrt(gain_increase));
2526     DBG(DBG_info,"updateGain2(): optimized gain setting %d => %f\n", scanner->settings.gain[color_index], getGain(scanner->settings.gain[color_index]));
2527     /* Exposure change is straightforward */
2528     DBG(DBG_info,"updateGain2(): remains for exposure %f\n", gain_increase / (getGain(scanner->settings.gain[color_index]) / g));
2529     scanner->settings.exposureTime[color_index] = lround( g / getGain(scanner->settings.gain[color_index]) * gain_increase * scanner->settings.exposureTime[color_index] );
2530     DBG(DBG_info,"updateGain2(): new setting G=%d Exp=%d\n", scanner->settings.gain[color_index], scanner->settings.exposureTime[color_index]);
2531 }
2532