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 (¶meters, &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 (¶meters, 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 (¶meters, 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 (¶meters, norm_histo, &static_thresh);
1343 if (status != SANE_STATUS_GOOD)
1344 return status;
1345 /* generate traditional static threshold */
1346 status = sanei_ir_threshold_otsu (¶meters, 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 (¶meters, 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 (¶meters, 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 (¶meters, 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, ¶meters, &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 (¶ms, 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