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() */ 73static 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); 74static void pieusb_print_inquiry (Pieusb_Device_Definition * dev); 75 76/* sub to sane_start() */ 77static void pieusb_calculate_shading(struct Pieusb_Scanner *scanner, SANE_Byte* buffer); 78 79/* MR */ 80/* sub to sanei_pieusb_post() */ 81static SANE_Status pieusb_write_pnm_file (char *filename, uint16_t *data, int depth, int channels, int pixels_per_line, int lines); 82 83/* Auxiliary */ 84static size_t max_string_size (SANE_String_Const const strings[]); 85static double getGain(int gain); 86static int getGainSetting(double gain); 87/* 88static void updateGain(Pieusb_Scanner *scanner, int color_index); 89*/ 90static 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 173static 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 */ 180static const SANE_Range gain_range = { 181 0, /* minimum */ 182 63, /* maximum */ 183 0 /* quantization */ 184}; 185 186/* From the firmware disassembly */ 187static const SANE_Range offset_range = { 188 0, /* minimum */ 189 255, /* maximum */ 190 0 /* quantization */ 191}; 192 193static const double gains[] = { 1941.000, 1.075, 1.154, 1.251, 1.362, 1.491, 1.653, /* 0, 5, 10, 15, 20, 25, 30 */ 1951.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 */ 206SANE_Status 207sanei_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 */ 309static SANE_Status 310pieusb_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 */ 502static void 503pieusb_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 */ 623SANE_Status 624sanei_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 */ 1008SANE_Status 1009sanei_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 */ 1085SANE_Bool 1086sanei_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 */ 1109SANE_Status 1110sanei_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 */ 1157SANE_Status 1158sanei_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 */ 1177static size_t 1178max_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 */ 1206void 1207sanei_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 */ 1252SANE_Status 1253sanei_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 ------------------------------- */ 1397static SANE_Status 1398pieusb_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 */ 1482int 1483sanei_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 */ 1626void 1627sanei_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 */ 1665static 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 1770SANE_Status 1771sanei_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 1791SANE_Status 1792sanei_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 */ 1868SANE_Status 1869sanei_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 2041SANE_Status 2042sanei_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 2101SANE_Status 2102sanei_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 */ 2128SANE_Status 2129sanei_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 2185SANE_Status 2186sanei_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 2315SANE_Status 2316sanei_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 2352SANE_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 */ 2407static 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 2424static 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/* 2489static 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 2512static 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