1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci pieusb_specific.c 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci Copyright (C) 2012-2015 Jan Vleeshouwers, Michael Rickmann, Klaus Kaempf 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 10141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 11141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 12141cc406Sopenharmony_ci License, or (at your option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 15141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 16141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17141cc406Sopenharmony_ci General Public License for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 23141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 26141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 27141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 28141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 29141cc406Sopenharmony_ci account of linking the SANE library code into it. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 32141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 33141cc406Sopenharmony_ci License. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 36141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 37141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 40141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 41141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. */ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci/* ========================================================================= 44141cc406Sopenharmony_ci * 45141cc406Sopenharmony_ci * Various Pieusb backend specific functions 46141cc406Sopenharmony_ci * 47141cc406Sopenharmony_ci * Option handling, configuration file handling, post-processing 48141cc406Sopenharmony_ci * 49141cc406Sopenharmony_ci * ========================================================================= */ 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 52141cc406Sopenharmony_ci#include "pieusb.h" 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci#include <stdlib.h> 55141cc406Sopenharmony_ci#include <unistd.h> 56141cc406Sopenharmony_ci#include <string.h> 57141cc406Sopenharmony_ci#include "../include/sane/sane.h" 58141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 59141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 60141cc406Sopenharmony_ci 61141cc406Sopenharmony_ci#include <errno.h> 62141cc406Sopenharmony_ci#include <math.h> 63141cc406Sopenharmony_ci#include <time.h> 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci#include "pieusb_usb.h" 66141cc406Sopenharmony_ci#include "pieusb_scancmd.h" 67141cc406Sopenharmony_ci#include "pieusb_buffer.h" 68141cc406Sopenharmony_ci#include "pieusb_specific.h" 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci/* Pieusb specific */ 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci/* sub to sanei_pieusb_find_device_callback() */ 73141cc406Sopenharmony_cistatic 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); 74141cc406Sopenharmony_cistatic void pieusb_print_inquiry (Pieusb_Device_Definition * dev); 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci/* sub to sane_start() */ 77141cc406Sopenharmony_cistatic void pieusb_calculate_shading(struct Pieusb_Scanner *scanner, SANE_Byte* buffer); 78141cc406Sopenharmony_ci 79141cc406Sopenharmony_ci/* MR */ 80141cc406Sopenharmony_ci/* sub to sanei_pieusb_post() */ 81141cc406Sopenharmony_cistatic SANE_Status pieusb_write_pnm_file (char *filename, uint16_t *data, int depth, int channels, int pixels_per_line, int lines); 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ci/* Auxiliary */ 84141cc406Sopenharmony_cistatic size_t max_string_size (SANE_String_Const const strings[]); 85141cc406Sopenharmony_cistatic double getGain(int gain); 86141cc406Sopenharmony_cistatic int getGainSetting(double gain); 87141cc406Sopenharmony_ci/* 88141cc406Sopenharmony_cistatic void updateGain(Pieusb_Scanner *scanner, int color_index); 89141cc406Sopenharmony_ci*/ 90141cc406Sopenharmony_cistatic void updateGain2(Pieusb_Scanner *scanner, int color_index, double gain_increase); 91141cc406Sopenharmony_ci 92141cc406Sopenharmony_ci/* -------------------------------------------------------------------------- 93141cc406Sopenharmony_ci * 94141cc406Sopenharmony_ci * SPECIFIC PIEUSB 95141cc406Sopenharmony_ci * 96141cc406Sopenharmony_ci * --------------------------------------------------------------------------*/ 97141cc406Sopenharmony_ci 98141cc406Sopenharmony_ci/* Settings for byte order */ 99141cc406Sopenharmony_ci#define SCAN_IMG_FMT_OKLINE 0x08 100141cc406Sopenharmony_ci#define SCAN_IMG_FMT_BLK_ONE 0x04 101141cc406Sopenharmony_ci#define SCAN_IMG_FMT_MOTOROLA 0x02 102141cc406Sopenharmony_ci#define SCAN_IMG_FMT_INTEL 0x01 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci/* Settings for scanner capabilities */ 105141cc406Sopenharmony_ci#define SCAN_CAP_PWRSAV 0x80 106141cc406Sopenharmony_ci#define SCAN_CAP_EXT_CAL 0x40 107141cc406Sopenharmony_ci#define SCAN_CAP_FAST_PREVIEW 0x10 108141cc406Sopenharmony_ci#define SCAN_CAP_DISABLE_CAL 0x08 109141cc406Sopenharmony_ci#define SCAN_CAP_SPEEDS 0x07 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci/* Available scanner options */ 112141cc406Sopenharmony_ci#define SCAN_OPT_DEV_MPCL 0x80 113141cc406Sopenharmony_ci#define SCAN_OPT_DEV_TP1 0x04 114141cc406Sopenharmony_ci#define SCAN_OPT_DEV_TP 0x02 115141cc406Sopenharmony_ci#define SCAN_OPT_DEV_ADF 0x01 116141cc406Sopenharmony_ci 117141cc406Sopenharmony_ci/* Options */ 118141cc406Sopenharmony_ci#define SANE_NAME_EXPOSURE_R "exposure-time-r" 119141cc406Sopenharmony_ci#define SANE_TITLE_EXPOSURE_R "Exposure time red" 120141cc406Sopenharmony_ci#define SANE_DESC_EXPOSURE_R "The time the red color filter of the CCD is exposed" 121141cc406Sopenharmony_ci#define SANE_NAME_EXPOSURE_G "exposure-time-g" 122141cc406Sopenharmony_ci#define SANE_TITLE_EXPOSURE_G "Exposure time green" 123141cc406Sopenharmony_ci#define SANE_DESC_EXPOSURE_G "The time the green color filter of the CCD is exposed" 124141cc406Sopenharmony_ci#define SANE_NAME_EXPOSURE_B "exposure-time-b" 125141cc406Sopenharmony_ci#define SANE_TITLE_EXPOSURE_B "Exposure time blue" 126141cc406Sopenharmony_ci#define SANE_DESC_EXPOSURE_B "The time the blue color filter of the CCD is exposed" 127141cc406Sopenharmony_ci#define SANE_NAME_EXPOSURE_I "exposure-time-i" 128141cc406Sopenharmony_ci#define SANE_TITLE_EXPOSURE_I "Exposure time infrared" 129141cc406Sopenharmony_ci#define SANE_DESC_EXPOSURE_I "The time the infrared color filter of the CCD is exposed" 130141cc406Sopenharmony_ci#define SANE_EXPOSURE_DEFAULT DEFAULT_EXPOSURE 131141cc406Sopenharmony_ci#if 1 132141cc406Sopenharmony_ci#define SANE_NAME_GAIN_R "gain-r" 133141cc406Sopenharmony_ci#define SANE_TITLE_GAIN_R "Gain red" 134141cc406Sopenharmony_ci#define SANE_DESC_GAIN_R "The gain of the signal processor for red" 135141cc406Sopenharmony_ci#define SANE_NAME_GAIN_G "gain-g" 136141cc406Sopenharmony_ci#define SANE_TITLE_GAIN_G "Gain green" 137141cc406Sopenharmony_ci#define SANE_DESC_GAIN_G "The gain of the signal processor for green" 138141cc406Sopenharmony_ci#define SANE_NAME_GAIN_B "gain-b" 139141cc406Sopenharmony_ci#define SANE_TITLE_GAIN_B "Gain blue" 140141cc406Sopenharmony_ci#define SANE_DESC_GAIN_B "The gain of the signal processor for blue" 141141cc406Sopenharmony_ci#define SANE_NAME_GAIN_I "gain-i" 142141cc406Sopenharmony_ci#define SANE_TITLE_GAIN_I "Gain infrared" 143141cc406Sopenharmony_ci#define SANE_DESC_GAIN_I "The gain of the signal processor for infrared" 144141cc406Sopenharmony_ci#define SANE_GAIN_DEFAULT DEFAULT_GAIN 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci#define SANE_NAME_OFFSET_R "offset-r" 147141cc406Sopenharmony_ci#define SANE_TITLE_OFFSET_R "Offset red" 148141cc406Sopenharmony_ci#define SANE_DESC_OFFSET_R "The offset of the signal processor for red" 149141cc406Sopenharmony_ci#define SANE_NAME_OFFSET_G "offset-g" 150141cc406Sopenharmony_ci#define SANE_TITLE_OFFSET_G "Offset greed" 151141cc406Sopenharmony_ci#define SANE_DESC_OFFSET_G "The offset of the signal processor for green" 152141cc406Sopenharmony_ci#define SANE_NAME_OFFSET_B "offset-b" 153141cc406Sopenharmony_ci#define SANE_TITLE_OFFSET_B "Offset blue" 154141cc406Sopenharmony_ci#define SANE_DESC_OFFSET_B "The offset of the signal processor for blue" 155141cc406Sopenharmony_ci#define SANE_NAME_OFFSET_I "offset-i" 156141cc406Sopenharmony_ci#define SANE_TITLE_OFFSET_I "Offset infrared" 157141cc406Sopenharmony_ci#define SANE_DESC_OFFSET_I "The offset of the signal processor for infrared" 158141cc406Sopenharmony_ci#define SANE_OFFSET_DEFAULT DEFAULT_OFFSET 159141cc406Sopenharmony_ci#else 160141cc406Sopenharmony_ci#define SANE_NAME_GAIN "gain" 161141cc406Sopenharmony_ci#define SANE_TITLE_GAIN "Gain" 162141cc406Sopenharmony_ci#define SANE_DESC_GAIN "The gain of the signal processor for the 4 CCD color filters (R,G,B,I)" 163141cc406Sopenharmony_ci#define SANE_GAIN_DEFAULT 0x13 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci#define SANE_NAME_OFFSET "offset" 166141cc406Sopenharmony_ci#define SANE_TITLE_OFFSET "Offset" 167141cc406Sopenharmony_ci#define SANE_DESC_OFFSET "The offset of the signal processor for the 4 CCD color filters (R,G,B,I)" 168141cc406Sopenharmony_ci#define SANE_OFFSET_DEFAULT 0 169141cc406Sopenharmony_ci#endif 170141cc406Sopenharmony_ci#define min(a,b) (((a)<(b))?(a):(b)) 171141cc406Sopenharmony_ci#define max(a,b) (((a)>(b))?(a):(b)) 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_cistatic const SANE_Range percentage_range_100 = { 174141cc406Sopenharmony_ci 0 << SANE_FIXED_SCALE_SHIFT, /* minimum */ 175141cc406Sopenharmony_ci 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ 176141cc406Sopenharmony_ci 0 << SANE_FIXED_SCALE_SHIFT /* quantization */ 177141cc406Sopenharmony_ci}; 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci/* From the firmware disassembly */ 180141cc406Sopenharmony_cistatic const SANE_Range gain_range = { 181141cc406Sopenharmony_ci 0, /* minimum */ 182141cc406Sopenharmony_ci 63, /* maximum */ 183141cc406Sopenharmony_ci 0 /* quantization */ 184141cc406Sopenharmony_ci}; 185141cc406Sopenharmony_ci 186141cc406Sopenharmony_ci/* From the firmware disassembly */ 187141cc406Sopenharmony_cistatic const SANE_Range offset_range = { 188141cc406Sopenharmony_ci 0, /* minimum */ 189141cc406Sopenharmony_ci 255, /* maximum */ 190141cc406Sopenharmony_ci 0 /* quantization */ 191141cc406Sopenharmony_ci}; 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_cistatic const double gains[] = { 194141cc406Sopenharmony_ci1.000, 1.075, 1.154, 1.251, 1.362, 1.491, 1.653, /* 0, 5, 10, 15, 20, 25, 30 */ 195141cc406Sopenharmony_ci1.858, 2.115, 2.458, 2.935, 3.638, 4.627 /* 35, 40, 45, 50, 55, 60 */ 196141cc406Sopenharmony_ci}; 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_ci/** 199141cc406Sopenharmony_ci * Callback called whenever a connected USB device reports a supported vendor 200141cc406Sopenharmony_ci * and product id combination. 201141cc406Sopenharmony_ci * Used by sane_init() and by sane_open(). 202141cc406Sopenharmony_ci * 203141cc406Sopenharmony_ci * @param name Device name which has required vendor and product id 204141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD 205141cc406Sopenharmony_ci */ 206141cc406Sopenharmony_ciSANE_Status 207141cc406Sopenharmony_cisanei_pieusb_find_device_callback (const char *devicename) 208141cc406Sopenharmony_ci{ 209141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 210141cc406Sopenharmony_ci SANE_Status r; 211141cc406Sopenharmony_ci Pieusb_Device_Definition *dev; 212141cc406Sopenharmony_ci int device_number; /* index in usb devices list maintained by sani_usb */ 213141cc406Sopenharmony_ci Pieusb_Scanner_Properties inq; 214141cc406Sopenharmony_ci int retry; 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_find_device_callback: %s\n", devicename); 217141cc406Sopenharmony_ci 218141cc406Sopenharmony_ci /* Check if device is present in the Pieusb device list */ 219141cc406Sopenharmony_ci for (dev = pieusb_definition_list_head; dev; dev = dev->next) { 220141cc406Sopenharmony_ci if (strcmp (dev->sane.name, devicename) == 0) { 221141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 222141cc406Sopenharmony_ci } 223141cc406Sopenharmony_ci } 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci /* If not, create a new device struct */ 226141cc406Sopenharmony_ci dev = malloc (sizeof (*dev)); 227141cc406Sopenharmony_ci if (!dev) { 228141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 229141cc406Sopenharmony_ci } 230141cc406Sopenharmony_ci 231141cc406Sopenharmony_ci /* Get device number: index of the device in the sanei_usb devices list */ 232141cc406Sopenharmony_ci r = sanei_usb_open (devicename, &device_number); 233141cc406Sopenharmony_ci if (r != SANE_STATUS_GOOD) { 234141cc406Sopenharmony_ci free (dev); 235141cc406Sopenharmony_ci DBG (DBG_error, "sanei_pieusb_find_device_callback: sanei_usb_open failed for device %s: %s\n",devicename,sane_strstatus(r)); 236141cc406Sopenharmony_ci return r; 237141cc406Sopenharmony_ci } 238141cc406Sopenharmony_ci 239141cc406Sopenharmony_ci /* Get device properties */ 240141cc406Sopenharmony_ci 241141cc406Sopenharmony_ci retry = 2; 242141cc406Sopenharmony_ci while (retry > 0) { 243141cc406Sopenharmony_ci retry--; 244141cc406Sopenharmony_ci /* get inquiry data length */ 245141cc406Sopenharmony_ci sanei_pieusb_cmd_inquiry (device_number, &inq, 5, &status); 246141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_GOOD) { 247141cc406Sopenharmony_ci break; 248141cc406Sopenharmony_ci } 249141cc406Sopenharmony_ci else if (status.pieusb_status == PIEUSB_STATUS_IO_ERROR) { 250141cc406Sopenharmony_ci if (retry > 0) { 251141cc406Sopenharmony_ci DBG (DBG_info_proc, "inquiry failed, resetting usb\n"); 252141cc406Sopenharmony_ci if (sanei_pieusb_usb_reset(device_number) == SANE_STATUS_GOOD) { 253141cc406Sopenharmony_ci continue; /* retry after IEEE1284 reset */ 254141cc406Sopenharmony_ci } 255141cc406Sopenharmony_ci if (sanei_usb_reset(device_number) == SANE_STATUS_GOOD) { 256141cc406Sopenharmony_ci continue; /* retry after USB reset */ 257141cc406Sopenharmony_ci } 258141cc406Sopenharmony_ci } 259141cc406Sopenharmony_ci } 260141cc406Sopenharmony_ci free (dev); 261141cc406Sopenharmony_ci DBG (DBG_error, "sanei_pieusb_find_device_callback: get scanner properties (5 bytes) failed with %d\n", status.pieusb_status); 262141cc406Sopenharmony_ci sanei_usb_close (device_number); 263141cc406Sopenharmony_ci return sanei_pieusb_convert_status (status.pieusb_status); 264141cc406Sopenharmony_ci } 265141cc406Sopenharmony_ci /* get full inquiry data */ 266141cc406Sopenharmony_ci sanei_pieusb_cmd_inquiry(device_number, &inq, inq.additionalLength+4, &status); 267141cc406Sopenharmony_ci if (status.pieusb_status != PIEUSB_STATUS_GOOD) { 268141cc406Sopenharmony_ci free (dev); 269141cc406Sopenharmony_ci DBG (DBG_error, "sanei_pieusb_find_device_callback: get scanner properties failed\n"); 270141cc406Sopenharmony_ci sanei_usb_close (device_number); 271141cc406Sopenharmony_ci return sanei_pieusb_convert_status (status.pieusb_status); 272141cc406Sopenharmony_ci } 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci /* Close the device again */ 275141cc406Sopenharmony_ci sanei_usb_close(device_number); 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci /* Initialize device definition */ 278141cc406Sopenharmony_ci r = pieusb_initialize_device_definition(dev, &inq, devicename, pieusb_supported_usb_device.vendor, pieusb_supported_usb_device.product); 279141cc406Sopenharmony_ci if (r != SANE_STATUS_GOOD) { 280141cc406Sopenharmony_ci return r; 281141cc406Sopenharmony_ci } 282141cc406Sopenharmony_ci 283141cc406Sopenharmony_ci /* Output */ 284141cc406Sopenharmony_ci pieusb_print_inquiry (dev); 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci /* Check model number */ 287141cc406Sopenharmony_ci if (inq.model != pieusb_supported_usb_device.model) { 288141cc406Sopenharmony_ci free (dev); 289141cc406Sopenharmony_ci DBG (DBG_error, "sanei_pieusb_find_device_callback: wrong model number %d\n", inq.model); 290141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 291141cc406Sopenharmony_ci } 292141cc406Sopenharmony_ci 293141cc406Sopenharmony_ci dev->flags = pieusb_supported_usb_device.flags; 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_ci /* Found a supported scanner, put it in the definitions list*/ 296141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_find_device_callback: success\n"); 297141cc406Sopenharmony_ci dev->next = pieusb_definition_list_head; 298141cc406Sopenharmony_ci pieusb_definition_list_head = dev; 299141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 300141cc406Sopenharmony_ci} 301141cc406Sopenharmony_ci 302141cc406Sopenharmony_ci/** 303141cc406Sopenharmony_ci * Full initialization of a Pieusb_Device structure from INQUIRY data. 304141cc406Sopenharmony_ci * The function is used in find_device_callback(), so when sane_init() or 305141cc406Sopenharmony_ci * sane_open() is called. 306141cc406Sopenharmony_ci * 307141cc406Sopenharmony_ci * @param dev 308141cc406Sopenharmony_ci */ 309141cc406Sopenharmony_cistatic SANE_Status 310141cc406Sopenharmony_cipieusb_initialize_device_definition (Pieusb_Device_Definition* dev, Pieusb_Scanner_Properties* inq, const char* devicename, 311141cc406Sopenharmony_ci SANE_Word vendor_id, SANE_Word product_id) 312141cc406Sopenharmony_ci{ 313141cc406Sopenharmony_ci char *pp, *buf; 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_ci /* Initialize device definition */ 316141cc406Sopenharmony_ci dev->next = NULL; 317141cc406Sopenharmony_ci dev->sane.name = strdup(devicename); 318141cc406Sopenharmony_ci 319141cc406Sopenharmony_ci /* Create 0-terminated string without trailing spaces for vendor */ 320141cc406Sopenharmony_ci buf = malloc(9); 321141cc406Sopenharmony_ci if (buf == NULL) 322141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 323141cc406Sopenharmony_ci memcpy(buf, inq->vendor, 8); 324141cc406Sopenharmony_ci pp = buf + 8; 325141cc406Sopenharmony_ci *pp-- = '\0'; 326141cc406Sopenharmony_ci while (*pp == ' ') *pp-- = '\0'; 327141cc406Sopenharmony_ci dev->sane.vendor = buf; 328141cc406Sopenharmony_ci 329141cc406Sopenharmony_ci /* Create 0-terminated string without trailing spaces for model */ 330141cc406Sopenharmony_ci buf = malloc(17); 331141cc406Sopenharmony_ci if (buf == NULL) 332141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 333141cc406Sopenharmony_ci memcpy(buf, inq->product, 16); 334141cc406Sopenharmony_ci pp = buf + 16; 335141cc406Sopenharmony_ci *pp-- = '\0'; 336141cc406Sopenharmony_ci while (*pp == ' ') *pp-- = '\0'; 337141cc406Sopenharmony_ci dev->sane.model = buf; 338141cc406Sopenharmony_ci 339141cc406Sopenharmony_ci dev->sane.type = "film scanner"; 340141cc406Sopenharmony_ci dev->vendorId = vendor_id; 341141cc406Sopenharmony_ci dev->productId = product_id; 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ci /* Create 0-terminated strings without trailing spaces for revision */ 344141cc406Sopenharmony_ci buf = malloc(5); 345141cc406Sopenharmony_ci if (buf == NULL) 346141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 347141cc406Sopenharmony_ci memcpy(buf, inq->productRevision, 4); 348141cc406Sopenharmony_ci pp = buf + 4; 349141cc406Sopenharmony_ci *pp-- = '\0'; 350141cc406Sopenharmony_ci while (*pp == ' ') *pp-- = '\0'; 351141cc406Sopenharmony_ci dev->version = buf; 352141cc406Sopenharmony_ci 353141cc406Sopenharmony_ci dev->model = inq->model; 354141cc406Sopenharmony_ci 355141cc406Sopenharmony_ci /* Maximum resolution values */ 356141cc406Sopenharmony_ci dev->maximum_resolution_x = inq->maxResolutionX; 357141cc406Sopenharmony_ci dev->maximum_resolution_y = inq->maxResolutionY; 358141cc406Sopenharmony_ci if (dev->maximum_resolution_y < 256) { 359141cc406Sopenharmony_ci /* y res is a multiplier */ 360141cc406Sopenharmony_ci dev->maximum_resolution = dev->maximum_resolution_x; 361141cc406Sopenharmony_ci dev->maximum_resolution_x *= dev->maximum_resolution_y; 362141cc406Sopenharmony_ci dev->maximum_resolution_y = dev->maximum_resolution_x; 363141cc406Sopenharmony_ci } else { 364141cc406Sopenharmony_ci /* y res really is resolution */ 365141cc406Sopenharmony_ci dev->maximum_resolution = min (dev->maximum_resolution_x, dev->maximum_resolution_y); 366141cc406Sopenharmony_ci } 367141cc406Sopenharmony_ci 368141cc406Sopenharmony_ci /* Geometry */ 369141cc406Sopenharmony_ci dev->scan_bed_width = (double) inq->maxScanWidth / dev->maximum_resolution; 370141cc406Sopenharmony_ci dev->scan_bed_height = (double) inq->maxScanHeight / dev->maximum_resolution; 371141cc406Sopenharmony_ci dev->slide_top_left_x = inq->x0; 372141cc406Sopenharmony_ci dev->slide_top_left_y = inq->y0; 373141cc406Sopenharmony_ci dev->slide_width = (double) (inq->x1 - inq->x0) / dev->maximum_resolution; 374141cc406Sopenharmony_ci dev->slide_height = (double) (inq->y1 - inq->y0) / dev->maximum_resolution; 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci /* Integer and bit-encoded properties */ 377141cc406Sopenharmony_ci dev->halftone_patterns = inq->halftones & 0x0f; 378141cc406Sopenharmony_ci dev->color_filters = inq->filters; 379141cc406Sopenharmony_ci dev->color_depths = inq->colorDepths; 380141cc406Sopenharmony_ci dev->color_formats = inq->colorFormat; 381141cc406Sopenharmony_ci dev->image_formats = inq->imageFormat; 382141cc406Sopenharmony_ci dev->scan_capabilities = inq->scanCapability; 383141cc406Sopenharmony_ci dev->optional_devices = inq->optionalDevices; 384141cc406Sopenharmony_ci dev->enhancements = inq->enhancements; 385141cc406Sopenharmony_ci dev->gamma_bits = inq->gammaBits; 386141cc406Sopenharmony_ci dev->fast_preview_resolution = inq->previewScanResolution; 387141cc406Sopenharmony_ci dev->minimum_highlight = inq->minumumHighlight; 388141cc406Sopenharmony_ci dev->maximum_shadow = inq->maximumShadow; 389141cc406Sopenharmony_ci dev->calibration_equation = inq->calibrationEquation; 390141cc406Sopenharmony_ci dev->minimum_exposure = inq->minimumExposure; 391141cc406Sopenharmony_ci dev->maximum_exposure = inq->maximumExposure*4; /* *4 to solve the strange situation that the default value is out of range */ 392141cc406Sopenharmony_ci 393141cc406Sopenharmony_ci dev->x0 = inq->x0; 394141cc406Sopenharmony_ci dev->y0 = inq->y0; 395141cc406Sopenharmony_ci dev->x1 = inq->x1; 396141cc406Sopenharmony_ci dev->y1 = inq->y1; 397141cc406Sopenharmony_ci dev->production = strndup(inq->production, 4); 398141cc406Sopenharmony_ci dev->timestamp = strndup(inq->timestamp, 20); 399141cc406Sopenharmony_ci dev->signature = (char *)strndup((char *)inq->signature, 40); 400141cc406Sopenharmony_ci 401141cc406Sopenharmony_ci /* Ranges for various quantities */ 402141cc406Sopenharmony_ci dev->x_range.min = SANE_FIX (0); 403141cc406Sopenharmony_ci dev->x_range.quant = SANE_FIX (0); 404141cc406Sopenharmony_ci dev->x_range.max = SANE_FIX (dev->scan_bed_width * MM_PER_INCH); 405141cc406Sopenharmony_ci 406141cc406Sopenharmony_ci dev->y_range.min = SANE_FIX (0); 407141cc406Sopenharmony_ci dev->y_range.quant = SANE_FIX (0); 408141cc406Sopenharmony_ci dev->y_range.max = SANE_FIX (dev->scan_bed_height * MM_PER_INCH); 409141cc406Sopenharmony_ci 410141cc406Sopenharmony_ci dev->dpi_range.min = SANE_FIX (25); 411141cc406Sopenharmony_ci dev->dpi_range.quant = SANE_FIX (1); 412141cc406Sopenharmony_ci dev->dpi_range.max = SANE_FIX (max (dev->maximum_resolution_x, dev->maximum_resolution_y)); 413141cc406Sopenharmony_ci 414141cc406Sopenharmony_ci dev->shadow_range.min = SANE_FIX (0); 415141cc406Sopenharmony_ci dev->shadow_range.quant = SANE_FIX (1); 416141cc406Sopenharmony_ci dev->shadow_range.max = SANE_FIX (dev->maximum_shadow); 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci dev->highlight_range.min = SANE_FIX (dev->minimum_highlight); 419141cc406Sopenharmony_ci dev->highlight_range.quant = SANE_FIX (1); 420141cc406Sopenharmony_ci dev->highlight_range.max = SANE_FIX (100); 421141cc406Sopenharmony_ci 422141cc406Sopenharmony_ci dev->exposure_range.min = dev->minimum_exposure; 423141cc406Sopenharmony_ci dev->exposure_range.quant = 1; 424141cc406Sopenharmony_ci dev->exposure_range.max = dev->maximum_exposure; 425141cc406Sopenharmony_ci 426141cc406Sopenharmony_ci dev->dust_range.min = 0; 427141cc406Sopenharmony_ci dev->dust_range.quant = 1; 428141cc406Sopenharmony_ci dev->dust_range.max = 100; 429141cc406Sopenharmony_ci 430141cc406Sopenharmony_ci /* Enumerated ranges vor various quantities */ 431141cc406Sopenharmony_ci /*TODO: create from inq->filters */ 432141cc406Sopenharmony_ci dev->scan_mode_list[0] = SANE_VALUE_SCAN_MODE_LINEART; 433141cc406Sopenharmony_ci dev->scan_mode_list[1] = SANE_VALUE_SCAN_MODE_HALFTONE; 434141cc406Sopenharmony_ci dev->scan_mode_list[2] = SANE_VALUE_SCAN_MODE_GRAY; 435141cc406Sopenharmony_ci dev->scan_mode_list[3] = SANE_VALUE_SCAN_MODE_COLOR; 436141cc406Sopenharmony_ci dev->scan_mode_list[4] = SANE_VALUE_SCAN_MODE_RGBI; 437141cc406Sopenharmony_ci dev->scan_mode_list[5] = 0; 438141cc406Sopenharmony_ci 439141cc406Sopenharmony_ci dev->calibration_mode_list[0] = SCAN_CALIBRATION_DEFAULT; 440141cc406Sopenharmony_ci dev->calibration_mode_list[1] = SCAN_CALIBRATION_AUTO; 441141cc406Sopenharmony_ci dev->calibration_mode_list[2] = SCAN_CALIBRATION_PREVIEW; 442141cc406Sopenharmony_ci dev->calibration_mode_list[3] = SCAN_CALIBRATION_OPTIONS; 443141cc406Sopenharmony_ci dev->calibration_mode_list[4] = 0; 444141cc406Sopenharmony_ci 445141cc406Sopenharmony_ci dev->gain_adjust_list[0] = SCAN_GAIN_ADJUST_03; 446141cc406Sopenharmony_ci dev->gain_adjust_list[1] = SCAN_GAIN_ADJUST_05; 447141cc406Sopenharmony_ci dev->gain_adjust_list[2] = SCAN_GAIN_ADJUST_08; 448141cc406Sopenharmony_ci dev->gain_adjust_list[3] = SCAN_GAIN_ADJUST_10; 449141cc406Sopenharmony_ci dev->gain_adjust_list[4] = SCAN_GAIN_ADJUST_12; 450141cc406Sopenharmony_ci dev->gain_adjust_list[5] = SCAN_GAIN_ADJUST_16; 451141cc406Sopenharmony_ci dev->gain_adjust_list[6] = SCAN_GAIN_ADJUST_19; 452141cc406Sopenharmony_ci dev->gain_adjust_list[7] = SCAN_GAIN_ADJUST_24; 453141cc406Sopenharmony_ci dev->gain_adjust_list[8] = SCAN_GAIN_ADJUST_30; 454141cc406Sopenharmony_ci dev->gain_adjust_list[9] = 0; 455141cc406Sopenharmony_ci 456141cc406Sopenharmony_ci /*TODO: create from inq->colorDepths? Maybe not: didn't experiment with 457141cc406Sopenharmony_ci * 4 and 12 bit depths. Don;t know how they behave. */ 458141cc406Sopenharmony_ci dev->bpp_list[0] = 3; /* count */ 459141cc406Sopenharmony_ci dev->bpp_list[1] = 1; 460141cc406Sopenharmony_ci dev->bpp_list[2] = 8; 461141cc406Sopenharmony_ci dev->bpp_list[3] = 16; 462141cc406Sopenharmony_ci 463141cc406Sopenharmony_ci /* Infrared */ 464141cc406Sopenharmony_ci dev->ir_sw_list[0] = "None"; 465141cc406Sopenharmony_ci dev->ir_sw_list[1] = "Reduce red overlap"; 466141cc406Sopenharmony_ci dev->ir_sw_list[2] = "Remove dirt"; 467141cc406Sopenharmony_ci dev->ir_sw_list[3] = 0; 468141cc406Sopenharmony_ci 469141cc406Sopenharmony_ci dev->grain_sw_list[0] = 4; 470141cc406Sopenharmony_ci dev->grain_sw_list[1] = 0; 471141cc406Sopenharmony_ci dev->grain_sw_list[2] = 1; 472141cc406Sopenharmony_ci dev->grain_sw_list[3] = 2; 473141cc406Sopenharmony_ci dev->grain_sw_list[4] = 3; 474141cc406Sopenharmony_ci dev->grain_sw_list[5] = 0; 475141cc406Sopenharmony_ci 476141cc406Sopenharmony_ci dev->crop_sw_list[0] = "None"; 477141cc406Sopenharmony_ci dev->crop_sw_list[1] = "Outside"; 478141cc406Sopenharmony_ci dev->crop_sw_list[2] = "Inside"; 479141cc406Sopenharmony_ci dev->crop_sw_list[3] = 0; 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci /* halftone_list */ 482141cc406Sopenharmony_ci dev->halftone_list[0] = "53lpi 45d ROUND"; /* 8x8 pattern */ 483141cc406Sopenharmony_ci dev->halftone_list[1] = "70lpi 45d ROUND"; /* 6x6 pattern */ 484141cc406Sopenharmony_ci dev->halftone_list[2] = "75lpi Hori. Line"; /* 4x4 pattern */ 485141cc406Sopenharmony_ci dev->halftone_list[3] = "4X4 BAYER"; /* 4x4 pattern */ 486141cc406Sopenharmony_ci dev->halftone_list[4] = "4X4 SCROLL"; /* 4x4 pattern */ 487141cc406Sopenharmony_ci dev->halftone_list[5] = "5x5 26 Levels"; /* 5x5 pattern */ 488141cc406Sopenharmony_ci dev->halftone_list[6] = "4x4 SQUARE"; /* 4x4 pattern */ 489141cc406Sopenharmony_ci dev->halftone_list[7] = "5x5 TILE"; /* 5x5 pattern */ 490141cc406Sopenharmony_ci dev->halftone_list[8] = 0; 491141cc406Sopenharmony_ci 492141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 493141cc406Sopenharmony_ci} 494141cc406Sopenharmony_ci 495141cc406Sopenharmony_ci/** 496141cc406Sopenharmony_ci * Output device definition. 497141cc406Sopenharmony_ci * The function is used in find_device_callback(), so when sane_init() or 498141cc406Sopenharmony_ci * sane_open() is called. 499141cc406Sopenharmony_ci * 500141cc406Sopenharmony_ci * @param dev Device to output 501141cc406Sopenharmony_ci */ 502141cc406Sopenharmony_cistatic void 503141cc406Sopenharmony_cipieusb_print_inquiry (Pieusb_Device_Definition * dev) 504141cc406Sopenharmony_ci{ 505141cc406Sopenharmony_ci DBG (DBG_inquiry, "INQUIRY:\n"); 506141cc406Sopenharmony_ci DBG (DBG_inquiry, "========\n"); 507141cc406Sopenharmony_ci DBG (DBG_inquiry, "\n"); 508141cc406Sopenharmony_ci DBG (DBG_inquiry, "vendor........................: '%s'\n", dev->sane.vendor); 509141cc406Sopenharmony_ci DBG (DBG_inquiry, "product.......................: '%s'\n", dev->sane.model); 510141cc406Sopenharmony_ci DBG (DBG_inquiry, "model .......................: 0x%04x\n", dev->model); 511141cc406Sopenharmony_ci DBG (DBG_inquiry, "version.......................: '%s'\n", dev->version); 512141cc406Sopenharmony_ci 513141cc406Sopenharmony_ci DBG (DBG_inquiry, "X resolution..................: %d dpi\n", 514141cc406Sopenharmony_ci dev->maximum_resolution_x); 515141cc406Sopenharmony_ci DBG (DBG_inquiry, "Y resolution..................: %d dpi\n", 516141cc406Sopenharmony_ci dev->maximum_resolution_y); 517141cc406Sopenharmony_ci DBG (DBG_inquiry, "pixel resolution..............: %d dpi\n", 518141cc406Sopenharmony_ci dev->maximum_resolution); 519141cc406Sopenharmony_ci DBG (DBG_inquiry, "fb width......................: %f in\n", 520141cc406Sopenharmony_ci dev->scan_bed_width); 521141cc406Sopenharmony_ci DBG (DBG_inquiry, "fb length.....................: %f in\n", 522141cc406Sopenharmony_ci dev->scan_bed_height); 523141cc406Sopenharmony_ci 524141cc406Sopenharmony_ci DBG (DBG_inquiry, "transparency width............: %f in\n", 525141cc406Sopenharmony_ci dev->slide_width); 526141cc406Sopenharmony_ci DBG (DBG_inquiry, "transparency length...........: %f in\n", 527141cc406Sopenharmony_ci dev->slide_height); 528141cc406Sopenharmony_ci DBG (DBG_inquiry, "transparency offset...........: %d,%d\n", 529141cc406Sopenharmony_ci dev->slide_top_left_x, dev->slide_top_left_y); 530141cc406Sopenharmony_ci 531141cc406Sopenharmony_ci DBG (DBG_inquiry, "# of halftones................: %d\n", 532141cc406Sopenharmony_ci dev->halftone_patterns); 533141cc406Sopenharmony_ci 534141cc406Sopenharmony_ci DBG (DBG_inquiry, "One pass color................: %s\n", 535141cc406Sopenharmony_ci dev->color_filters & SCAN_ONE_PASS_COLOR ? "yes" : "no"); 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ci DBG (DBG_inquiry, "Filters.......................: %s%s%s%s%s (%02x)\n", 538141cc406Sopenharmony_ci dev->color_filters & SCAN_FILTER_INFRARED ? "Infrared " : "", 539141cc406Sopenharmony_ci dev->color_filters & SCAN_FILTER_RED ? "Red " : "", 540141cc406Sopenharmony_ci dev->color_filters & SCAN_FILTER_GREEN ? "Green " : "", 541141cc406Sopenharmony_ci dev->color_filters & SCAN_FILTER_BLUE ? "Blue " : "", 542141cc406Sopenharmony_ci dev->color_filters & SCAN_FILTER_NEUTRAL ? "Neutral " : "", 543141cc406Sopenharmony_ci dev->color_filters); 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci DBG (DBG_inquiry, "Color depths..................: %s%s%s%s%s%s (%02x)\n", 546141cc406Sopenharmony_ci dev->color_depths & SCAN_COLOR_DEPTH_16 ? "16 bit " : "", 547141cc406Sopenharmony_ci dev->color_depths & SCAN_COLOR_DEPTH_12 ? "12 bit " : "", 548141cc406Sopenharmony_ci dev->color_depths & SCAN_COLOR_DEPTH_10 ? "10 bit " : "", 549141cc406Sopenharmony_ci dev->color_depths & SCAN_COLOR_DEPTH_8 ? "8 bit " : "", 550141cc406Sopenharmony_ci dev->color_depths & SCAN_COLOR_DEPTH_4 ? "4 bit " : "", 551141cc406Sopenharmony_ci dev->color_depths & SCAN_COLOR_DEPTH_1 ? "1 bit " : "", 552141cc406Sopenharmony_ci dev->color_depths); 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci DBG (DBG_inquiry, "Color Format..................: %s%s%s (%02x)\n", 555141cc406Sopenharmony_ci dev->color_formats & SCAN_COLOR_FORMAT_INDEX ? "Indexed " : "", 556141cc406Sopenharmony_ci dev->color_formats & SCAN_COLOR_FORMAT_LINE ? "Line " : "", 557141cc406Sopenharmony_ci dev->color_formats & SCAN_COLOR_FORMAT_PIXEL ? "Pixel " : "", 558141cc406Sopenharmony_ci dev->color_formats); 559141cc406Sopenharmony_ci 560141cc406Sopenharmony_ci DBG (DBG_inquiry, "Image Format..................: %s%s%s%s (%02x)\n", 561141cc406Sopenharmony_ci dev->image_formats & SCAN_IMG_FMT_OKLINE ? "OKLine " : "", 562141cc406Sopenharmony_ci dev->image_formats & SCAN_IMG_FMT_BLK_ONE ? "BlackOne " : "", 563141cc406Sopenharmony_ci dev->image_formats & SCAN_IMG_FMT_MOTOROLA ? "Motorola " : "", 564141cc406Sopenharmony_ci dev->image_formats & SCAN_IMG_FMT_INTEL ? "Intel" : "", 565141cc406Sopenharmony_ci dev->image_formats); 566141cc406Sopenharmony_ci 567141cc406Sopenharmony_ci DBG (DBG_inquiry, 568141cc406Sopenharmony_ci "Scan Capability...............: %s%s%s%s%d speeds (%02x)\n", 569141cc406Sopenharmony_ci dev->scan_capabilities & SCAN_CAP_PWRSAV ? "PowerSave " : "", 570141cc406Sopenharmony_ci dev->scan_capabilities & SCAN_CAP_EXT_CAL ? "ExtCal " : "", 571141cc406Sopenharmony_ci dev->scan_capabilities & SCAN_CAP_FAST_PREVIEW ? "FastPreview" : 572141cc406Sopenharmony_ci "", 573141cc406Sopenharmony_ci dev->scan_capabilities & SCAN_CAP_DISABLE_CAL ? "DisCal " : "", 574141cc406Sopenharmony_ci dev->scan_capabilities & SCAN_CAP_SPEEDS, 575141cc406Sopenharmony_ci dev->scan_capabilities); 576141cc406Sopenharmony_ci 577141cc406Sopenharmony_ci DBG (DBG_inquiry, "Optional Devices..............: %s%s%s%s (%02x)\n", 578141cc406Sopenharmony_ci dev->optional_devices & SCAN_OPT_DEV_MPCL ? "MultiPageLoad " : 579141cc406Sopenharmony_ci "", 580141cc406Sopenharmony_ci dev->optional_devices & SCAN_OPT_DEV_TP1 ? "TransModule1 " : "", 581141cc406Sopenharmony_ci dev->optional_devices & SCAN_OPT_DEV_TP ? "TransModule " : "", 582141cc406Sopenharmony_ci dev->optional_devices & SCAN_OPT_DEV_ADF ? "ADF " : "", 583141cc406Sopenharmony_ci dev->optional_devices); 584141cc406Sopenharmony_ci 585141cc406Sopenharmony_ci DBG (DBG_inquiry, "Enhancement...................: %02x\n", 586141cc406Sopenharmony_ci dev->enhancements); 587141cc406Sopenharmony_ci DBG (DBG_inquiry, "Gamma bits....................: %d\n", 588141cc406Sopenharmony_ci dev->gamma_bits); 589141cc406Sopenharmony_ci 590141cc406Sopenharmony_ci DBG (DBG_inquiry, "Fast Preview Resolution.......: %d\n", 591141cc406Sopenharmony_ci dev->fast_preview_resolution); 592141cc406Sopenharmony_ci DBG (DBG_inquiry, "Min Highlight.................: %d\n", 593141cc406Sopenharmony_ci dev->minimum_highlight); 594141cc406Sopenharmony_ci DBG (DBG_inquiry, "Max Shadow....................: %d\n", 595141cc406Sopenharmony_ci dev->maximum_shadow); 596141cc406Sopenharmony_ci DBG (DBG_inquiry, "Cal Eqn.......................: %d\n", 597141cc406Sopenharmony_ci dev->calibration_equation); 598141cc406Sopenharmony_ci DBG (DBG_inquiry, "Min Exposure..................: %d\n", 599141cc406Sopenharmony_ci dev->minimum_exposure); 600141cc406Sopenharmony_ci DBG (DBG_inquiry, "Max Exposure..................: %d\n", 601141cc406Sopenharmony_ci dev->maximum_exposure); 602141cc406Sopenharmony_ci 603141cc406Sopenharmony_ci DBG (DBG_inquiry, "x0,y0 x1,y1...................: %d,%d %d,%d\n", 604141cc406Sopenharmony_ci dev->x0, dev->y0, dev->x1, dev->y1); 605141cc406Sopenharmony_ci DBG (DBG_inquiry, "production....................: '%s'\n", 606141cc406Sopenharmony_ci dev->production); 607141cc406Sopenharmony_ci DBG (DBG_inquiry, "timestamp.....................: '%s'\n", 608141cc406Sopenharmony_ci dev->timestamp); 609141cc406Sopenharmony_ci DBG (DBG_inquiry, "signature.....................: '%s'\n", 610141cc406Sopenharmony_ci dev->signature); 611141cc406Sopenharmony_ci 612141cc406Sopenharmony_ci} 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci/** 615141cc406Sopenharmony_ci * Initiaize scanner options from the device definition and from exposure, 616141cc406Sopenharmony_ci * gain and offset defaults. The function is called by sane_open(), when no 617141cc406Sopenharmony_ci * optimized settings are available yet. The scanner object is fully 618141cc406Sopenharmony_ci * initialized in sane_start(). 619141cc406Sopenharmony_ci * 620141cc406Sopenharmony_ci * @param scanner Scanner to initialize 621141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD 622141cc406Sopenharmony_ci */ 623141cc406Sopenharmony_ciSANE_Status 624141cc406Sopenharmony_cisanei_pieusb_init_options (Pieusb_Scanner* scanner) 625141cc406Sopenharmony_ci{ 626141cc406Sopenharmony_ci int i; 627141cc406Sopenharmony_ci 628141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_init_options\n"); 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ci memset (scanner->opt, 0, sizeof (scanner->opt)); 631141cc406Sopenharmony_ci memset (scanner->val, 0, sizeof (scanner->val)); 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci for (i = 0; i < NUM_OPTIONS; ++i) { 634141cc406Sopenharmony_ci scanner->opt[i].size = sizeof (SANE_Word); 635141cc406Sopenharmony_ci scanner->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; 636141cc406Sopenharmony_ci } 637141cc406Sopenharmony_ci 638141cc406Sopenharmony_ci /* Number of options (a pseudo-option) */ 639141cc406Sopenharmony_ci scanner->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; 640141cc406Sopenharmony_ci scanner->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; 641141cc406Sopenharmony_ci scanner->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; 642141cc406Sopenharmony_ci scanner->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; 643141cc406Sopenharmony_ci scanner->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; 644141cc406Sopenharmony_ci scanner->val[OPT_NUM_OPTS].w = NUM_OPTIONS; 645141cc406Sopenharmony_ci 646141cc406Sopenharmony_ci /* "Mode" group: */ 647141cc406Sopenharmony_ci scanner->opt[OPT_MODE_GROUP].title = "Scan Mode"; 648141cc406Sopenharmony_ci scanner->opt[OPT_MODE_GROUP].desc = ""; 649141cc406Sopenharmony_ci scanner->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; 650141cc406Sopenharmony_ci scanner->opt[OPT_MODE_GROUP].cap = 0; 651141cc406Sopenharmony_ci scanner->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci /* scan mode */ 654141cc406Sopenharmony_ci scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; 655141cc406Sopenharmony_ci scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; 656141cc406Sopenharmony_ci scanner->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; 657141cc406Sopenharmony_ci scanner->opt[OPT_MODE].type = SANE_TYPE_STRING; 658141cc406Sopenharmony_ci scanner->opt[OPT_MODE].size = max_string_size ((SANE_String_Const const *) scanner->device->scan_mode_list); 659141cc406Sopenharmony_ci scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 660141cc406Sopenharmony_ci scanner->opt[OPT_MODE].constraint.string_list = (SANE_String_Const const *) scanner->device->scan_mode_list; 661141cc406Sopenharmony_ci scanner->val[OPT_MODE].s = (SANE_Char *) strdup (scanner->device->scan_mode_list[3]); /* default RGB */ 662141cc406Sopenharmony_ci 663141cc406Sopenharmony_ci /* bit depth */ 664141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; 665141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; 666141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; 667141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; 668141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; 669141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word); 670141cc406Sopenharmony_ci scanner->opt[OPT_BIT_DEPTH].constraint.word_list = scanner->device->bpp_list; 671141cc406Sopenharmony_ci scanner->val[OPT_BIT_DEPTH].w = scanner->device->bpp_list[2]; 672141cc406Sopenharmony_ci 673141cc406Sopenharmony_ci /* resolution */ 674141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; 675141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; 676141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; 677141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED; 678141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; 679141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; 680141cc406Sopenharmony_ci scanner->opt[OPT_RESOLUTION].constraint.range = &scanner->device->dpi_range; 681141cc406Sopenharmony_ci scanner->val[OPT_RESOLUTION].w = scanner->device->fast_preview_resolution << SANE_FIXED_SCALE_SHIFT; 682141cc406Sopenharmony_ci 683141cc406Sopenharmony_ci /* halftone pattern */ 684141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN; 685141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN; 686141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN; 687141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING; 688141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].size = max_string_size ((SANE_String_Const const *) scanner->device->halftone_list); 689141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST; 690141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].constraint.string_list = (SANE_String_Const const *) scanner->device->halftone_list; 691141cc406Sopenharmony_ci scanner->val[OPT_HALFTONE_PATTERN].s = (SANE_Char *) strdup (scanner->device->halftone_list[6]); 692141cc406Sopenharmony_ci scanner->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; /* Not implemented, and only meaningful at depth 1 */ 693141cc406Sopenharmony_ci 694141cc406Sopenharmony_ci /* lineart threshold */ 695141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; 696141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; 697141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; 698141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; 699141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; 700141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; 701141cc406Sopenharmony_ci scanner->opt[OPT_THRESHOLD].constraint.range = &percentage_range_100; 702141cc406Sopenharmony_ci scanner->val[OPT_THRESHOLD].w = SANE_FIX (50); 703141cc406Sopenharmony_ci /* scanner->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; Not implemented, and only meaningful at depth 1 */ 704141cc406Sopenharmony_ci 705141cc406Sopenharmony_ci /* create a sharper scan at the cost of scan time */ 706141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].name = "sharpen"; 707141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].title = "Sharpen scan"; 708141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].desc = "Sharpen scan by taking more time to discharge the CCD."; 709141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].type = SANE_TYPE_BOOL; 710141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].unit = SANE_UNIT_NONE; 711141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].constraint_type = SANE_CONSTRAINT_NONE; 712141cc406Sopenharmony_ci scanner->val[OPT_SHARPEN].b = SANE_FALSE; 713141cc406Sopenharmony_ci scanner->opt[OPT_SHARPEN].cap |= SANE_CAP_SOFT_SELECT; 714141cc406Sopenharmony_ci 715141cc406Sopenharmony_ci /* skip the auto-calibration phase before the scan */ 716141cc406Sopenharmony_ci scanner->opt[OPT_SHADING_ANALYSIS].name = "shading-analysis"; 717141cc406Sopenharmony_ci scanner->opt[OPT_SHADING_ANALYSIS].title = "Perform shading analysis"; 718141cc406Sopenharmony_ci 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."; 719141cc406Sopenharmony_ci scanner->opt[OPT_SHADING_ANALYSIS].type = SANE_TYPE_BOOL; 720141cc406Sopenharmony_ci scanner->opt[OPT_SHADING_ANALYSIS].unit = SANE_UNIT_NONE; 721141cc406Sopenharmony_ci scanner->opt[OPT_SHADING_ANALYSIS].constraint_type = SANE_CONSTRAINT_NONE; 722141cc406Sopenharmony_ci scanner->val[OPT_SHADING_ANALYSIS].b = SANE_FALSE; 723141cc406Sopenharmony_ci scanner->opt[OPT_SHADING_ANALYSIS].cap |= SANE_CAP_SOFT_SELECT; 724141cc406Sopenharmony_ci 725141cc406Sopenharmony_ci /* use auto-calibration settings for scan */ 726141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].name = "calibration"; 727141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].title = "Calibration mode"; 728141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].desc = "How to calibrate the scanner."; 729141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].type = SANE_TYPE_STRING; 730141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].size = max_string_size ((SANE_String_Const const *) scanner->device->calibration_mode_list); 731141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 732141cc406Sopenharmony_ci scanner->opt[OPT_CALIBRATION_MODE].constraint.string_list = (SANE_String_Const const *) scanner->device->calibration_mode_list; 733141cc406Sopenharmony_ci scanner->val[OPT_CALIBRATION_MODE].s = (SANE_Char *) strdup (scanner->device->calibration_mode_list[1]); /* default auto */ 734141cc406Sopenharmony_ci 735141cc406Sopenharmony_ci /* OPT_GAIN_ADJUST */ 736141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].name = "gain-adjust"; 737141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].title = "Adjust gain"; 738141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].desc = "Adjust gain determined by calibration procedure."; 739141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].type = SANE_TYPE_STRING; 740141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].size = max_string_size ((SANE_String_Const const *) scanner->device->gain_adjust_list); 741141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].constraint_type = SANE_CONSTRAINT_STRING_LIST; 742141cc406Sopenharmony_ci scanner->opt[OPT_GAIN_ADJUST].constraint.string_list = (SANE_String_Const const *) scanner->device->gain_adjust_list; 743141cc406Sopenharmony_ci scanner->val[OPT_GAIN_ADJUST].s = (SANE_Char *) strdup (scanner->device->gain_adjust_list[2]); /* x 1.0 (no change) */ 744141cc406Sopenharmony_ci 745141cc406Sopenharmony_ci /* scan infrared channel faster but less accurate */ 746141cc406Sopenharmony_ci scanner->opt[OPT_FAST_INFRARED].name = "fast-infrared"; 747141cc406Sopenharmony_ci scanner->opt[OPT_FAST_INFRARED].title = "Fast infrared scan"; 748141cc406Sopenharmony_ci 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."; 749141cc406Sopenharmony_ci scanner->opt[OPT_FAST_INFRARED].type = SANE_TYPE_BOOL; 750141cc406Sopenharmony_ci scanner->opt[OPT_FAST_INFRARED].unit = SANE_UNIT_NONE; 751141cc406Sopenharmony_ci scanner->opt[OPT_FAST_INFRARED].constraint_type = SANE_CONSTRAINT_NONE; 752141cc406Sopenharmony_ci scanner->val[OPT_FAST_INFRARED].b = SANE_FALSE; 753141cc406Sopenharmony_ci scanner->opt[OPT_FAST_INFRARED].cap |= SANE_CAP_SOFT_SELECT; 754141cc406Sopenharmony_ci 755141cc406Sopenharmony_ci /* automatically advance to next slide after scan */ 756141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].name = "advance"; 757141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].title = "Advance slide"; 758141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].desc = "Automatically advance to next slide after scan"; 759141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].type = SANE_TYPE_BOOL; 760141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].unit = SANE_UNIT_NONE; 761141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].constraint_type = SANE_CONSTRAINT_NONE; 762141cc406Sopenharmony_ci scanner->val[OPT_ADVANCE_SLIDE].w = SANE_TRUE; 763141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCE_SLIDE].cap |= SANE_CAP_SOFT_SELECT; 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci /* "Geometry" group: */ 766141cc406Sopenharmony_ci scanner->opt[OPT_GEOMETRY_GROUP].title = "Geometry"; 767141cc406Sopenharmony_ci scanner->opt[OPT_GEOMETRY_GROUP].desc = ""; 768141cc406Sopenharmony_ci scanner->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; 769141cc406Sopenharmony_ci scanner->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; 770141cc406Sopenharmony_ci scanner->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 771141cc406Sopenharmony_ci 772141cc406Sopenharmony_ci /* top-left x */ 773141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; 774141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; 775141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; 776141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].type = SANE_TYPE_FIXED; 777141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].unit = SANE_UNIT_MM; 778141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; 779141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].constraint.range = &(scanner->device->x_range); 780141cc406Sopenharmony_ci scanner->val[OPT_TL_X].w = 0; 781141cc406Sopenharmony_ci 782141cc406Sopenharmony_ci /* top-left y */ 783141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; 784141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; 785141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; 786141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; 787141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].unit = SANE_UNIT_MM; 788141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; 789141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].constraint.range = &(scanner->device->y_range); 790141cc406Sopenharmony_ci scanner->val[OPT_TL_Y].w = 0; 791141cc406Sopenharmony_ci 792141cc406Sopenharmony_ci /* bottom-right x */ 793141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; 794141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; 795141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; 796141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].type = SANE_TYPE_FIXED; 797141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].unit = SANE_UNIT_MM; 798141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; 799141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].constraint.range = &(scanner->device->x_range); 800141cc406Sopenharmony_ci scanner->val[OPT_BR_X].w = scanner->device->x_range.max; 801141cc406Sopenharmony_ci 802141cc406Sopenharmony_ci /* bottom-right y */ 803141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; 804141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; 805141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; 806141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; 807141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].unit = SANE_UNIT_MM; 808141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; 809141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].constraint.range = &(scanner->device->y_range); 810141cc406Sopenharmony_ci scanner->val[OPT_BR_Y].w = scanner->device->y_range.max; 811141cc406Sopenharmony_ci 812141cc406Sopenharmony_ci /* "Enhancement" group: */ 813141cc406Sopenharmony_ci scanner->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; 814141cc406Sopenharmony_ci scanner->opt[OPT_ENHANCEMENT_GROUP].desc = ""; 815141cc406Sopenharmony_ci scanner->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; 816141cc406Sopenharmony_ci scanner->opt[OPT_ENHANCEMENT_GROUP].cap = 0; 817141cc406Sopenharmony_ci scanner->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 818141cc406Sopenharmony_ci 819141cc406Sopenharmony_ci /* correct data for lamp variations (shading) */ 820141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_SHADING].name = "correct-shading"; 821141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_SHADING].title = "Correct shading"; 822141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_SHADING].desc = "Correct data for lamp variations (shading)"; 823141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_SHADING].type = SANE_TYPE_BOOL; 824141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_SHADING].unit = SANE_UNIT_NONE; 825141cc406Sopenharmony_ci scanner->val[OPT_CORRECT_SHADING].w = SANE_TRUE; 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_ci /* correct infrared for red crosstalk */ 828141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_INFRARED].name = "correct-infrared"; 829141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_INFRARED].title = "Correct infrared"; 830141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_INFRARED].desc = "Correct infrared for red crosstalk"; 831141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_INFRARED].type = SANE_TYPE_BOOL; 832141cc406Sopenharmony_ci scanner->opt[OPT_CORRECT_INFRARED].unit = SANE_UNIT_NONE; 833141cc406Sopenharmony_ci scanner->val[OPT_CORRECT_INFRARED].w = SANE_FALSE; 834141cc406Sopenharmony_ci 835141cc406Sopenharmony_ci /* detect and remove dust and scratch artifacts */ 836141cc406Sopenharmony_ci scanner->opt[OPT_CLEAN_IMAGE].name = "clean-image"; 837141cc406Sopenharmony_ci scanner->opt[OPT_CLEAN_IMAGE].title = "Clean image"; 838141cc406Sopenharmony_ci scanner->opt[OPT_CLEAN_IMAGE].desc = "Detect and remove dust and scratch artifacts"; 839141cc406Sopenharmony_ci scanner->opt[OPT_CLEAN_IMAGE].type = SANE_TYPE_BOOL; 840141cc406Sopenharmony_ci scanner->opt[OPT_CLEAN_IMAGE].unit = SANE_UNIT_NONE; 841141cc406Sopenharmony_ci scanner->val[OPT_CLEAN_IMAGE].w = SANE_FALSE; 842141cc406Sopenharmony_ci 843141cc406Sopenharmony_ci /* strength of grain filtering */ 844141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].name = "smooth"; 845141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].title = "Attenuate film grain"; 846141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].desc = "Amount of smoothening"; 847141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].type = SANE_TYPE_INT; 848141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].constraint_type = SANE_CONSTRAINT_WORD_LIST; 849141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].size = sizeof (SANE_Word); 850141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].constraint.word_list = scanner->device->grain_sw_list; 851141cc406Sopenharmony_ci scanner->val[OPT_SMOOTH_IMAGE].w = scanner->device->grain_sw_list[1]; 852141cc406Sopenharmony_ci if (scanner->opt[OPT_SMOOTH_IMAGE].constraint.word_list[0] < 2) { 853141cc406Sopenharmony_ci scanner->opt[OPT_SMOOTH_IMAGE].cap |= SANE_CAP_INACTIVE; 854141cc406Sopenharmony_ci } 855141cc406Sopenharmony_ci 856141cc406Sopenharmony_ci /* gamma correction, to make image sRGB like */ 857141cc406Sopenharmony_ci scanner->opt[OPT_TRANSFORM_TO_SRGB].name = "srgb"; 858141cc406Sopenharmony_ci scanner->opt[OPT_TRANSFORM_TO_SRGB].title = "sRGB colors"; 859141cc406Sopenharmony_ci scanner->opt[OPT_TRANSFORM_TO_SRGB].desc = "Transform image to approximate sRGB color space"; 860141cc406Sopenharmony_ci scanner->opt[OPT_TRANSFORM_TO_SRGB].type = SANE_TYPE_BOOL; 861141cc406Sopenharmony_ci scanner->opt[OPT_TRANSFORM_TO_SRGB].unit = SANE_UNIT_NONE; 862141cc406Sopenharmony_ci scanner->val[OPT_TRANSFORM_TO_SRGB].w = SANE_FALSE; 863141cc406Sopenharmony_ci scanner->opt[OPT_TRANSFORM_TO_SRGB].cap |= SANE_CAP_INACTIVE; 864141cc406Sopenharmony_ci 865141cc406Sopenharmony_ci /* color correction for generic negative film */ 866141cc406Sopenharmony_ci scanner->opt[OPT_INVERT_IMAGE].name = "invert"; 867141cc406Sopenharmony_ci scanner->opt[OPT_INVERT_IMAGE].title = "Invert colors"; 868141cc406Sopenharmony_ci scanner->opt[OPT_INVERT_IMAGE].desc = "Correct for generic negative film"; 869141cc406Sopenharmony_ci scanner->opt[OPT_INVERT_IMAGE].type = SANE_TYPE_BOOL; 870141cc406Sopenharmony_ci scanner->opt[OPT_INVERT_IMAGE].unit = SANE_UNIT_NONE; 871141cc406Sopenharmony_ci scanner->val[OPT_INVERT_IMAGE].w = SANE_FALSE; 872141cc406Sopenharmony_ci scanner->opt[OPT_INVERT_IMAGE].cap |= SANE_CAP_INACTIVE; 873141cc406Sopenharmony_ci 874141cc406Sopenharmony_ci /* crop image */ 875141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].name = "crop"; 876141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].title = "Cropping"; 877141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].desc = "How to crop the image"; 878141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].type = SANE_TYPE_STRING; 879141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].size = max_string_size ((SANE_String_Const const *)(void*) scanner->device->crop_sw_list); 880141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].constraint_type = SANE_CONSTRAINT_STRING_LIST; 881141cc406Sopenharmony_ci scanner->opt[OPT_CROP_IMAGE].constraint.string_list = (SANE_String_Const const *)(void*) scanner->device->crop_sw_list; 882141cc406Sopenharmony_ci scanner->val[OPT_CROP_IMAGE].s = (SANE_Char *) strdup (scanner->device->crop_sw_list[2]); 883141cc406Sopenharmony_ci 884141cc406Sopenharmony_ci /* "Advanced" group: */ 885141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCED_GROUP].title = "Advanced"; 886141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCED_GROUP].desc = ""; 887141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP; 888141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED; 889141cc406Sopenharmony_ci scanner->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE; 890141cc406Sopenharmony_ci 891141cc406Sopenharmony_ci /* preview */ 892141cc406Sopenharmony_ci scanner->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; 893141cc406Sopenharmony_ci scanner->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; 894141cc406Sopenharmony_ci scanner->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; 895141cc406Sopenharmony_ci scanner->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; 896141cc406Sopenharmony_ci scanner->val[OPT_PREVIEW].w = SANE_FALSE; 897141cc406Sopenharmony_ci 898141cc406Sopenharmony_ci /* save shading data */ 899141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_SHADINGDATA].name = "save-shading-data"; 900141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_SHADINGDATA].title = "Save shading data"; 901141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_SHADINGDATA].desc = "Save shading data in 'pieusb.shading'"; 902141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_SHADINGDATA].type = SANE_TYPE_BOOL; 903141cc406Sopenharmony_ci scanner->val[OPT_SAVE_SHADINGDATA].w = SANE_FALSE; 904141cc406Sopenharmony_ci 905141cc406Sopenharmony_ci /* save CCD mask */ 906141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_CCDMASK].name = "save-ccdmask"; 907141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_CCDMASK].title = "Save CCD mask"; 908141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_CCDMASK].desc = "Save CCD mask 'pieusb.ccd'"; 909141cc406Sopenharmony_ci scanner->opt[OPT_SAVE_CCDMASK].type = SANE_TYPE_BOOL; 910141cc406Sopenharmony_ci scanner->val[OPT_SAVE_CCDMASK].w = SANE_FALSE; 911141cc406Sopenharmony_ci 912141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].name = "light"; 913141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].title = "Light"; 914141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].desc = "Light"; 915141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].type = SANE_TYPE_INT; 916141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].unit = SANE_UNIT_MICROSECOND; 917141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].cap |= SANE_CAP_SOFT_SELECT; 918141cc406Sopenharmony_ci scanner->opt[OPT_LIGHT].size = sizeof(SANE_Word); 919141cc406Sopenharmony_ci scanner->val[OPT_LIGHT].w = DEFAULT_LIGHT; 920141cc406Sopenharmony_ci 921141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].name = "double-times"; 922141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].title = "Double times"; 923141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].desc = "Double times"; 924141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].type = SANE_TYPE_INT; 925141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].unit = SANE_UNIT_MICROSECOND; 926141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].cap |= SANE_CAP_SOFT_SELECT; 927141cc406Sopenharmony_ci scanner->opt[OPT_DOUBLE_TIMES].size = sizeof(SANE_Word); 928141cc406Sopenharmony_ci scanner->val[OPT_DOUBLE_TIMES].w = DEFAULT_DOUBLE_TIMES; 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci /* exposure times for R, G, B and I */ 931141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_R].name = SANE_NAME_EXPOSURE_R; 932141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_R].title = SANE_TITLE_EXPOSURE_R; 933141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_R].desc = SANE_DESC_EXPOSURE_R; 934141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_G].name = SANE_NAME_EXPOSURE_G; 935141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_G].title = SANE_TITLE_EXPOSURE_G; 936141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_G].desc = SANE_DESC_EXPOSURE_G; 937141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_B].name = SANE_NAME_EXPOSURE_B; 938141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_B].title = SANE_TITLE_EXPOSURE_B; 939141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_B].desc = SANE_DESC_EXPOSURE_B; 940141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_I].name = SANE_NAME_EXPOSURE_I; 941141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_I].title = SANE_TITLE_EXPOSURE_I; 942141cc406Sopenharmony_ci scanner->opt[OPT_SET_EXPOSURE_I].desc = SANE_DESC_EXPOSURE_I; 943141cc406Sopenharmony_ci for (i = OPT_SET_EXPOSURE_R; i <= OPT_SET_EXPOSURE_I; ++i) { 944141cc406Sopenharmony_ci scanner->opt[i].type = SANE_TYPE_INT; 945141cc406Sopenharmony_ci scanner->opt[i].unit = SANE_UNIT_MICROSECOND; 946141cc406Sopenharmony_ci scanner->opt[i].cap |= SANE_CAP_SOFT_SELECT; 947141cc406Sopenharmony_ci scanner->opt[i].constraint_type = SANE_CONSTRAINT_RANGE; 948141cc406Sopenharmony_ci scanner->opt[i].constraint.range = &(scanner->device->exposure_range); 949141cc406Sopenharmony_ci scanner->opt[i].size = sizeof(SANE_Word); 950141cc406Sopenharmony_ci scanner->val[i].w = SANE_EXPOSURE_DEFAULT; 951141cc406Sopenharmony_ci } 952141cc406Sopenharmony_ci 953141cc406Sopenharmony_ci /* gain for R, G, B and I */ 954141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_R].name = SANE_NAME_GAIN_R; 955141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_R].title = SANE_TITLE_GAIN_R; 956141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_R].desc = SANE_DESC_GAIN_R; 957141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_G].name = SANE_NAME_GAIN_G; 958141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_G].title = SANE_TITLE_GAIN_G; 959141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_G].desc = SANE_DESC_GAIN_G; 960141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_B].name = SANE_NAME_GAIN_B; 961141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_B].title = SANE_TITLE_GAIN_B; 962141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_B].desc = SANE_DESC_GAIN_B; 963141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_I].name = SANE_NAME_GAIN_I; 964141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_I].title = SANE_TITLE_GAIN_I; 965141cc406Sopenharmony_ci scanner->opt[OPT_SET_GAIN_I].desc = SANE_DESC_GAIN_I; 966141cc406Sopenharmony_ci for (i = OPT_SET_GAIN_R; i <= OPT_SET_GAIN_I; ++i) { 967141cc406Sopenharmony_ci scanner->opt[i].type = SANE_TYPE_INT; 968141cc406Sopenharmony_ci scanner->opt[i].unit = SANE_UNIT_NONE; 969141cc406Sopenharmony_ci scanner->opt[i].constraint_type = SANE_CONSTRAINT_RANGE; 970141cc406Sopenharmony_ci scanner->opt[i].constraint.range = &gain_range; 971141cc406Sopenharmony_ci scanner->opt[i].size = sizeof(SANE_Word); 972141cc406Sopenharmony_ci scanner->val[i].w = SANE_GAIN_DEFAULT; 973141cc406Sopenharmony_ci } 974141cc406Sopenharmony_ci /* offsets for R, G, B and I */ 975141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_R].name = SANE_NAME_OFFSET_R; 976141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_R].title = SANE_TITLE_OFFSET_R; 977141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_R].desc = SANE_DESC_OFFSET_R; 978141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_G].name = SANE_NAME_OFFSET_G; 979141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_G].title = SANE_TITLE_OFFSET_G; 980141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_G].desc = SANE_DESC_OFFSET_G; 981141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_B].name = SANE_NAME_OFFSET_B; 982141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_B].title = SANE_TITLE_OFFSET_B; 983141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_B].desc = SANE_DESC_OFFSET_B; 984141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_I].name = SANE_NAME_OFFSET_I; 985141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_I].title = SANE_TITLE_OFFSET_I; 986141cc406Sopenharmony_ci scanner->opt[OPT_SET_OFFSET_I].desc = SANE_DESC_OFFSET_I; 987141cc406Sopenharmony_ci for (i = OPT_SET_OFFSET_R; i <= OPT_SET_OFFSET_I; ++i) { 988141cc406Sopenharmony_ci scanner->opt[i].type = SANE_TYPE_INT; 989141cc406Sopenharmony_ci scanner->opt[i].unit = SANE_UNIT_NONE; 990141cc406Sopenharmony_ci scanner->opt[i].constraint_type = SANE_CONSTRAINT_RANGE; 991141cc406Sopenharmony_ci scanner->opt[i].constraint.range = &offset_range; 992141cc406Sopenharmony_ci scanner->opt[i].size = sizeof(SANE_Word); 993141cc406Sopenharmony_ci scanner->val[i].w = SANE_OFFSET_DEFAULT; 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 996141cc406Sopenharmony_ci} 997141cc406Sopenharmony_ci 998141cc406Sopenharmony_ci/** 999141cc406Sopenharmony_ci * Parse line from config file into a vendor id, product id, model number, and flags 1000141cc406Sopenharmony_ci * 1001141cc406Sopenharmony_ci * @param config_line Text to parse 1002141cc406Sopenharmony_ci * @param vendor_id 1003141cc406Sopenharmony_ci * @param product_id 1004141cc406Sopenharmony_ci * @param model_number 1005141cc406Sopenharmony_ci * @param flags 1006141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD, or SANE_STATUS_INVAL in case of a parse error 1007141cc406Sopenharmony_ci */ 1008141cc406Sopenharmony_ciSANE_Status 1009141cc406Sopenharmony_cisanei_pieusb_parse_config_line(const char* config_line, 1010141cc406Sopenharmony_ci SANE_Word* vendor_id, 1011141cc406Sopenharmony_ci SANE_Word* product_id, 1012141cc406Sopenharmony_ci SANE_Int* model_number, 1013141cc406Sopenharmony_ci SANE_Int* flags) 1014141cc406Sopenharmony_ci{ 1015141cc406Sopenharmony_ci char *vendor_id_string, *product_id_string, *model_number_string, *flags_string; 1016141cc406Sopenharmony_ci 1017141cc406Sopenharmony_ci if (strncmp (config_line, "usb ", 4) != 0) { 1018141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1019141cc406Sopenharmony_ci } 1020141cc406Sopenharmony_ci /* Detect vendor-id */ 1021141cc406Sopenharmony_ci config_line += 4; 1022141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1023141cc406Sopenharmony_ci if (*config_line) { 1024141cc406Sopenharmony_ci config_line = sanei_config_get_string (config_line, &vendor_id_string); 1025141cc406Sopenharmony_ci if (vendor_id_string) { 1026141cc406Sopenharmony_ci *vendor_id = strtol (vendor_id_string, 0, 0); 1027141cc406Sopenharmony_ci free (vendor_id_string); 1028141cc406Sopenharmony_ci } else { 1029141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1030141cc406Sopenharmony_ci } 1031141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1032141cc406Sopenharmony_ci } else { 1033141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1034141cc406Sopenharmony_ci } 1035141cc406Sopenharmony_ci /* Detect product-id */ 1036141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1037141cc406Sopenharmony_ci if (*config_line) { 1038141cc406Sopenharmony_ci config_line = sanei_config_get_string (config_line, &product_id_string); 1039141cc406Sopenharmony_ci if (product_id_string) { 1040141cc406Sopenharmony_ci *product_id = strtol (product_id_string, 0, 0); 1041141cc406Sopenharmony_ci free (product_id_string); 1042141cc406Sopenharmony_ci } else { 1043141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1044141cc406Sopenharmony_ci } 1045141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1046141cc406Sopenharmony_ci } else { 1047141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1048141cc406Sopenharmony_ci } 1049141cc406Sopenharmony_ci /* Detect model number */ 1050141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1051141cc406Sopenharmony_ci if (*config_line) { 1052141cc406Sopenharmony_ci config_line = sanei_config_get_string (config_line, &model_number_string); 1053141cc406Sopenharmony_ci if (model_number_string) { 1054141cc406Sopenharmony_ci *model_number = (SANE_Int) strtol (model_number_string, 0, 0); 1055141cc406Sopenharmony_ci free (model_number_string); 1056141cc406Sopenharmony_ci } else { 1057141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1058141cc406Sopenharmony_ci } 1059141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1060141cc406Sopenharmony_ci } else { 1061141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1062141cc406Sopenharmony_ci } 1063141cc406Sopenharmony_ci /* Detect (optional) flags */ 1064141cc406Sopenharmony_ci *flags = 0; 1065141cc406Sopenharmony_ci config_line = sanei_config_skip_whitespace (config_line); 1066141cc406Sopenharmony_ci if (*config_line) { 1067141cc406Sopenharmony_ci config_line = sanei_config_get_string (config_line, &flags_string); 1068141cc406Sopenharmony_ci if (flags_string) { 1069141cc406Sopenharmony_ci *flags = (SANE_Int) strtol (flags_string, 0, 0); 1070141cc406Sopenharmony_ci free (flags_string); 1071141cc406Sopenharmony_ci } 1072141cc406Sopenharmony_ci } 1073141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1074141cc406Sopenharmony_ci} 1075141cc406Sopenharmony_ci 1076141cc406Sopenharmony_ci/** 1077141cc406Sopenharmony_ci * Check if current list of supported devices contains the given specifications. 1078141cc406Sopenharmony_ci * 1079141cc406Sopenharmony_ci * @param vendor_id 1080141cc406Sopenharmony_ci * @param product_id 1081141cc406Sopenharmony_ci * @param model_number 1082141cc406Sopenharmony_ci * @param flags 1083141cc406Sopenharmony_ci * @return 1084141cc406Sopenharmony_ci */ 1085141cc406Sopenharmony_ciSANE_Bool 1086141cc406Sopenharmony_cisanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags) 1087141cc406Sopenharmony_ci{ 1088141cc406Sopenharmony_ci int i = 0; 1089141cc406Sopenharmony_ci while (pieusb_supported_usb_device_list[i].vendor != 0) { 1090141cc406Sopenharmony_ci if (pieusb_supported_usb_device_list[i].vendor == vendor_id 1091141cc406Sopenharmony_ci && pieusb_supported_usb_device_list[i].product == product_id 1092141cc406Sopenharmony_ci && pieusb_supported_usb_device_list[i].model == model_number 1093141cc406Sopenharmony_ci && pieusb_supported_usb_device_list[i].flags == flags) { 1094141cc406Sopenharmony_ci return SANE_TRUE; 1095141cc406Sopenharmony_ci } 1096141cc406Sopenharmony_ci i++; 1097141cc406Sopenharmony_ci } 1098141cc406Sopenharmony_ci return SANE_FALSE; 1099141cc406Sopenharmony_ci} 1100141cc406Sopenharmony_ci 1101141cc406Sopenharmony_ci/** 1102141cc406Sopenharmony_ci * Add the given specifications to the current list of supported devices 1103141cc406Sopenharmony_ci * @param vendor_id 1104141cc406Sopenharmony_ci * @param product_id 1105141cc406Sopenharmony_ci * @param model_number 1106141cc406Sopenharmony_ci * @param flags 1107141cc406Sopenharmony_ci * @return 1108141cc406Sopenharmony_ci */ 1109141cc406Sopenharmony_ciSANE_Status 1110141cc406Sopenharmony_cisanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags) 1111141cc406Sopenharmony_ci{ 1112141cc406Sopenharmony_ci int i = 0, k; 1113141cc406Sopenharmony_ci struct Pieusb_USB_Device_Entry* dl; 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci while (pieusb_supported_usb_device_list[i].vendor != 0) { 1116141cc406Sopenharmony_ci i++; 1117141cc406Sopenharmony_ci } 1118141cc406Sopenharmony_ci /* i is index of last entry */ 1119141cc406Sopenharmony_ci for (k=0; k<=i; k++) { 1120141cc406Sopenharmony_ci DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add(): current %03d: %04x %04x %02x %02x\n", i, 1121141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].vendor, 1122141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].product, 1123141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].model, 1124141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].flags); 1125141cc406Sopenharmony_ci } 1126141cc406Sopenharmony_ci 1127141cc406Sopenharmony_ci dl = realloc(pieusb_supported_usb_device_list,(i+2)*sizeof(struct Pieusb_USB_Device_Entry)); /* Add one entry to list */ 1128141cc406Sopenharmony_ci if (dl == NULL) { 1129141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1130141cc406Sopenharmony_ci } 1131141cc406Sopenharmony_ci /* Copy values */ 1132141cc406Sopenharmony_ci pieusb_supported_usb_device_list = dl; 1133141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i].vendor = vendor_id; 1134141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i].product = product_id; 1135141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i].model = model_number; 1136141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i].flags = flags; 1137141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i+1].vendor = 0; 1138141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i+1].product = 0; 1139141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i+1].model = 0; 1140141cc406Sopenharmony_ci pieusb_supported_usb_device_list[i+1].flags = 0; 1141141cc406Sopenharmony_ci for (k=0; k<=i+1; k++) { 1142141cc406Sopenharmony_ci DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add() add: %03d: %04x %04x %02x %02x\n", i, 1143141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].vendor, 1144141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].product, 1145141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].model, 1146141cc406Sopenharmony_ci pieusb_supported_usb_device_list[k].flags); 1147141cc406Sopenharmony_ci } 1148141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1149141cc406Sopenharmony_ci} 1150141cc406Sopenharmony_ci 1151141cc406Sopenharmony_ci/** 1152141cc406Sopenharmony_ci * Actions to perform when a cancel request has been received. 1153141cc406Sopenharmony_ci * 1154141cc406Sopenharmony_ci * @param scanner scanner to stop scanning 1155141cc406Sopenharmony_ci * @return SANE_STATUS_CANCELLED 1156141cc406Sopenharmony_ci */ 1157141cc406Sopenharmony_ciSANE_Status 1158141cc406Sopenharmony_cisanei_pieusb_on_cancel (Pieusb_Scanner * scanner) 1159141cc406Sopenharmony_ci{ 1160141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 1161141cc406Sopenharmony_ci 1162141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_on_cancel()\n"); 1163141cc406Sopenharmony_ci 1164141cc406Sopenharmony_ci sanei_pieusb_cmd_stop_scan (scanner->device_number, &status); 1165141cc406Sopenharmony_ci sanei_pieusb_cmd_set_scan_head (scanner->device_number, 1, 0, &status); 1166141cc406Sopenharmony_ci sanei_pieusb_buffer_delete (&scanner->buffer); 1167141cc406Sopenharmony_ci scanner->scanning = SANE_FALSE; 1168141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1169141cc406Sopenharmony_ci} 1170141cc406Sopenharmony_ci 1171141cc406Sopenharmony_ci/** 1172141cc406Sopenharmony_ci * Determine maximum length of a set of strings. 1173141cc406Sopenharmony_ci * 1174141cc406Sopenharmony_ci * @param strings Set of strings 1175141cc406Sopenharmony_ci * @return maximum length 1176141cc406Sopenharmony_ci */ 1177141cc406Sopenharmony_cistatic size_t 1178141cc406Sopenharmony_cimax_string_size (SANE_String_Const const strings[]) 1179141cc406Sopenharmony_ci{ 1180141cc406Sopenharmony_ci size_t size, max_size = 0; 1181141cc406Sopenharmony_ci int i; 1182141cc406Sopenharmony_ci 1183141cc406Sopenharmony_ci for (i = 0; strings[i]; ++i) { 1184141cc406Sopenharmony_ci size = strlen (strings[i]) + 1; 1185141cc406Sopenharmony_ci if (size > max_size) { 1186141cc406Sopenharmony_ci max_size = size; 1187141cc406Sopenharmony_ci } 1188141cc406Sopenharmony_ci } 1189141cc406Sopenharmony_ci 1190141cc406Sopenharmony_ci return max_size; 1191141cc406Sopenharmony_ci} 1192141cc406Sopenharmony_ci 1193141cc406Sopenharmony_ci/* From MR's pie.c */ 1194141cc406Sopenharmony_ci 1195141cc406Sopenharmony_ci/* ------------------------- PIEUSB_CORRECT_SHADING -------------------------- */ 1196141cc406Sopenharmony_ci 1197141cc406Sopenharmony_ci/** 1198141cc406Sopenharmony_ci * Correct the given buffer for shading using shading data in scanner. 1199141cc406Sopenharmony_ci * If the loop order is width->color->height, a 7200 dpi scan correction takes 1200141cc406Sopenharmony_ci * 45 minutes. If the loop order is color->height->width, this is less than 3 1201141cc406Sopenharmony_ci * minutes. So it is worthwhile to find the used pixels first (array width_to_loc). 1202141cc406Sopenharmony_ci * 1203141cc406Sopenharmony_ci * @param scanner Scanner 1204141cc406Sopenharmony_ci * @param buffer Buffer to correct 1205141cc406Sopenharmony_ci */ 1206141cc406Sopenharmony_civoid 1207141cc406Sopenharmony_cisanei_pieusb_correct_shading(struct Pieusb_Scanner *scanner, struct Pieusb_Read_Buffer *buffer) 1208141cc406Sopenharmony_ci{ 1209141cc406Sopenharmony_ci 1210141cc406Sopenharmony_ci int i, j, c, k; 1211141cc406Sopenharmony_ci SANE_Uint val, val_org, *p; 1212141cc406Sopenharmony_ci int *width_to_loc; 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_correct_shading()\n"); 1215141cc406Sopenharmony_ci 1216141cc406Sopenharmony_ci /* Loop through CCD-mask to find used pixels */ 1217141cc406Sopenharmony_ci width_to_loc = calloc(buffer->width,sizeof(int)); 1218141cc406Sopenharmony_ci j = 0; 1219141cc406Sopenharmony_ci for (i = 0; i < scanner->ccd_mask_size; i++) { 1220141cc406Sopenharmony_ci if (scanner->ccd_mask[i] == 0) { 1221141cc406Sopenharmony_ci width_to_loc[j++] = i; 1222141cc406Sopenharmony_ci } 1223141cc406Sopenharmony_ci } 1224141cc406Sopenharmony_ci /* Correct complete image */ 1225141cc406Sopenharmony_ci for (c = 0; c < buffer->colors; c++) { 1226141cc406Sopenharmony_ci DBG(DBG_info,"sanei_pieusb_correct_shading() correct color %d\n",c); 1227141cc406Sopenharmony_ci for (k = 0; k < buffer->height; k++) { 1228141cc406Sopenharmony_ci /* DBG(DBG_info,"Correct line %d\n",k); */ 1229141cc406Sopenharmony_ci p = buffer->data + c * buffer->width * buffer->height + k * buffer->width; 1230141cc406Sopenharmony_ci for (j = 0; j < buffer->width; j++) { 1231141cc406Sopenharmony_ci val_org = *p; 1232141cc406Sopenharmony_ci val = lround((double)scanner->shading_mean[c] / scanner->shading_ref[c][width_to_loc[j]] * val_org); 1233141cc406Sopenharmony_ci /* DBG(DBG_info,"Correct [%d,%d,%d] %d -> %d\n",k,j,c,val_org,val); */ 1234141cc406Sopenharmony_ci *p++ = val; 1235141cc406Sopenharmony_ci } 1236141cc406Sopenharmony_ci } 1237141cc406Sopenharmony_ci } 1238141cc406Sopenharmony_ci /* Free memory */ 1239141cc406Sopenharmony_ci free(width_to_loc); 1240141cc406Sopenharmony_ci} 1241141cc406Sopenharmony_ci 1242141cc406Sopenharmony_ci/* === functions copied from MR's code === */ 1243141cc406Sopenharmony_ci 1244141cc406Sopenharmony_ci/** 1245141cc406Sopenharmony_ci * 1246141cc406Sopenharmony_ci * @param scanner 1247141cc406Sopenharmony_ci * @param in_img 1248141cc406Sopenharmony_ci * @param planes 1249141cc406Sopenharmony_ci * @param out_planes 1250141cc406Sopenharmony_ci * @return 1251141cc406Sopenharmony_ci */ 1252141cc406Sopenharmony_ciSANE_Status 1253141cc406Sopenharmony_cisanei_pieusb_post (Pieusb_Scanner *scanner, uint16_t **in_img, int planes) 1254141cc406Sopenharmony_ci{ 1255141cc406Sopenharmony_ci uint16_t *cplane[PLANES]; /* R, G, B, I gray scale planes */ 1256141cc406Sopenharmony_ci SANE_Parameters parameters; /* describes the image */ 1257141cc406Sopenharmony_ci int winsize_smooth; /* for adapting replaced pixels */ 1258141cc406Sopenharmony_ci char filename[64]; 1259141cc406Sopenharmony_ci SANE_Status status; 1260141cc406Sopenharmony_ci int smooth, i; 1261141cc406Sopenharmony_ci 1262141cc406Sopenharmony_ci memcpy (¶meters, &scanner->scan_parameters, sizeof (SANE_Parameters)); 1263141cc406Sopenharmony_ci parameters.format = SANE_FRAME_GRAY; 1264141cc406Sopenharmony_ci parameters.bytes_per_line = parameters.pixels_per_line; 1265141cc406Sopenharmony_ci if (parameters.depth > 8) 1266141cc406Sopenharmony_ci parameters.bytes_per_line *= 2; 1267141cc406Sopenharmony_ci parameters.last_frame = 0; 1268141cc406Sopenharmony_ci 1269141cc406Sopenharmony_ci DBG (DBG_info, "pie_usb_post: %d ppl, %d lines, %d bits, %d planes, %d dpi\n", 1270141cc406Sopenharmony_ci parameters.pixels_per_line, parameters.lines, 1271141cc406Sopenharmony_ci parameters.depth, planes, scanner->mode.resolution); 1272141cc406Sopenharmony_ci 1273141cc406Sopenharmony_ci if (planes > PLANES) { 1274141cc406Sopenharmony_ci DBG (DBG_error, "pie_usb_post: too many planes: %d (max %d)\n", planes, PLANES); 1275141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1276141cc406Sopenharmony_ci } 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci for (i = 0; i < planes; i++) 1279141cc406Sopenharmony_ci cplane[i] = in_img[i]; 1280141cc406Sopenharmony_ci 1281141cc406Sopenharmony_ci /* dirt is rather resolution invariant, so 1282141cc406Sopenharmony_ci * setup resolution dependent parameters 1283141cc406Sopenharmony_ci */ 1284141cc406Sopenharmony_ci /* film grain reduction */ 1285141cc406Sopenharmony_ci smooth = scanner->val[OPT_SMOOTH_IMAGE].w; 1286141cc406Sopenharmony_ci winsize_smooth = (scanner->mode.resolution / 540) | 1; 1287141cc406Sopenharmony_ci /* smoothen whole image or only replaced pixels */ 1288141cc406Sopenharmony_ci if (smooth) 1289141cc406Sopenharmony_ci { 1290141cc406Sopenharmony_ci winsize_smooth += 2 * (smooth - 3); /* even */ 1291141cc406Sopenharmony_ci if (winsize_smooth < 3) 1292141cc406Sopenharmony_ci smooth = 0; 1293141cc406Sopenharmony_ci } 1294141cc406Sopenharmony_ci if (winsize_smooth < 3) 1295141cc406Sopenharmony_ci winsize_smooth = 3; 1296141cc406Sopenharmony_ci DBG (DBG_info, "pie_usb_sw_post: winsize_smooth %d\n", winsize_smooth); 1297141cc406Sopenharmony_ci 1298141cc406Sopenharmony_ci /* RGBI post-processing if selected: 1299141cc406Sopenharmony_ci * 1) remove spectral overlay from ired plane, 1300141cc406Sopenharmony_ci * 2) remove dirt, smoothen if, crop if */ 1301141cc406Sopenharmony_ci if (scanner->val[OPT_CORRECT_INFRARED].b) /* (scanner->processing & POST_SW_IRED_MASK) */ 1302141cc406Sopenharmony_ci { 1303141cc406Sopenharmony_ci /* remove spectral overlay from ired plane */ 1304141cc406Sopenharmony_ci status = sanei_ir_spectral_clean (¶meters, scanner->ln_lut, cplane[0], cplane[3]); 1305141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1306141cc406Sopenharmony_ci return status; 1307141cc406Sopenharmony_ci if (DBG_LEVEL >= 15) 1308141cc406Sopenharmony_ci { 1309141cc406Sopenharmony_ci snprintf (filename, 63, "/tmp/ir-spectral.pnm"); 1310141cc406Sopenharmony_ci pieusb_write_pnm_file (filename, cplane[3], 1311141cc406Sopenharmony_ci parameters.depth, 1, 1312141cc406Sopenharmony_ci parameters.pixels_per_line, parameters.lines); 1313141cc406Sopenharmony_ci } 1314141cc406Sopenharmony_ci if (scanner->cancel_request) /* asynchronous cancel ? */ 1315141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1316141cc406Sopenharmony_ci } /* scanner-> processing & POST_SW_IRED_MASK */ 1317141cc406Sopenharmony_ci 1318141cc406Sopenharmony_ci /* remove dirt, smoothen if, crop if */ 1319141cc406Sopenharmony_ci if (scanner->val[OPT_CLEAN_IMAGE].b) /* (scanner->processing & POST_SW_DIRT) */ 1320141cc406Sopenharmony_ci { 1321141cc406Sopenharmony_ci double *norm_histo; 1322141cc406Sopenharmony_ci uint16_t *thresh_data; 1323141cc406Sopenharmony_ci int static_thresh, too_thresh; /* static thresholds */ 1324141cc406Sopenharmony_ci int winsize_filter; /* primary size of filtering window */ 1325141cc406Sopenharmony_ci int size_dilate; /* the dirt mask */ 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ci /* size of filter detecting dirt */ 1328141cc406Sopenharmony_ci winsize_filter = (int) (5.0 * (double) scanner->mode.resolution / 300.0) | 1; 1329141cc406Sopenharmony_ci if (winsize_filter < 3) 1330141cc406Sopenharmony_ci winsize_filter = 3; 1331141cc406Sopenharmony_ci /* dirt usually has smooth edges which also need correction */ 1332141cc406Sopenharmony_ci size_dilate = scanner->mode.resolution / 1000 + 1; 1333141cc406Sopenharmony_ci 1334141cc406Sopenharmony_ci /* first detect large dirt by a static threshold */ 1335141cc406Sopenharmony_ci status = sanei_ir_create_norm_histogram (¶meters, cplane[3], &norm_histo); 1336141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1337141cc406Sopenharmony_ci { 1338141cc406Sopenharmony_ci DBG (DBG_error, "pie_usb_sw_post: no buffer\n"); 1339141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1340141cc406Sopenharmony_ci } 1341141cc406Sopenharmony_ci /* generate a "bimodal" static threshold */ 1342141cc406Sopenharmony_ci status = sanei_ir_threshold_yen (¶meters, norm_histo, &static_thresh); 1343141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1344141cc406Sopenharmony_ci return status; 1345141cc406Sopenharmony_ci /* generate traditional static threshold */ 1346141cc406Sopenharmony_ci status = sanei_ir_threshold_otsu (¶meters, norm_histo, &too_thresh); 1347141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1348141cc406Sopenharmony_ci return status; 1349141cc406Sopenharmony_ci /* choose lower one */ 1350141cc406Sopenharmony_ci if (too_thresh < static_thresh) 1351141cc406Sopenharmony_ci static_thresh = too_thresh; 1352141cc406Sopenharmony_ci free (norm_histo); 1353141cc406Sopenharmony_ci 1354141cc406Sopenharmony_ci /* then generate dirt mask with adaptive thresholding filter 1355141cc406Sopenharmony_ci * and add the dirt from the static threshold */ 1356141cc406Sopenharmony_ci /* last two parameters: 10, 50 detects more, 20, 75 less */ 1357141cc406Sopenharmony_ci status = sanei_ir_filter_madmean (¶meters, cplane[3], &thresh_data, winsize_filter, 20, 100); 1358141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1359141cc406Sopenharmony_ci free (thresh_data); 1360141cc406Sopenharmony_ci return status; 1361141cc406Sopenharmony_ci } 1362141cc406Sopenharmony_ci sanei_ir_add_threshold (¶meters, cplane[3], thresh_data, static_thresh); 1363141cc406Sopenharmony_ci if (DBG_LEVEL >= 15) 1364141cc406Sopenharmony_ci { 1365141cc406Sopenharmony_ci snprintf (filename, 63, "/tmp/ir-threshold.pnm"); 1366141cc406Sopenharmony_ci pieusb_write_pnm_file (filename, thresh_data, 1367141cc406Sopenharmony_ci 8, 1, parameters.pixels_per_line, 1368141cc406Sopenharmony_ci parameters.lines); 1369141cc406Sopenharmony_ci } 1370141cc406Sopenharmony_ci if (scanner->cancel_request) { /* asynchronous cancel ? */ 1371141cc406Sopenharmony_ci free (thresh_data); 1372141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; 1373141cc406Sopenharmony_ci } 1374141cc406Sopenharmony_ci /* replace the dirt and smoothen film grain and crop if possible */ 1375141cc406Sopenharmony_ci status = sanei_ir_dilate_mean (¶meters, cplane, thresh_data, 1376141cc406Sopenharmony_ci 500, size_dilate, winsize_smooth, smooth, 1377141cc406Sopenharmony_ci 0, NULL); 1378141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) { 1379141cc406Sopenharmony_ci free (thresh_data); 1380141cc406Sopenharmony_ci return status; 1381141cc406Sopenharmony_ci } 1382141cc406Sopenharmony_ci smooth = 0; 1383141cc406Sopenharmony_ci free (thresh_data); 1384141cc406Sopenharmony_ci } 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ci if (DBG_LEVEL >= 15) 1387141cc406Sopenharmony_ci { 1388141cc406Sopenharmony_ci pieusb_write_pnm_file ("/tmp/RGBi-img.pnm", scanner->buffer.data, 1389141cc406Sopenharmony_ci scanner->scan_parameters.depth, 3, scanner->scan_parameters.pixels_per_line, 1390141cc406Sopenharmony_ci scanner->scan_parameters.lines); 1391141cc406Sopenharmony_ci } 1392141cc406Sopenharmony_ci 1393141cc406Sopenharmony_ci return status; 1394141cc406Sopenharmony_ci} 1395141cc406Sopenharmony_ci 1396141cc406Sopenharmony_ci/* ------------------------------ PIE_USB_WRITE_PNM_FILE ------------------------------- */ 1397141cc406Sopenharmony_cistatic SANE_Status 1398141cc406Sopenharmony_cipieusb_write_pnm_file (char *filename, SANE_Uint *data, int depth, 1399141cc406Sopenharmony_ci int channels, int pixels_per_line, int lines) 1400141cc406Sopenharmony_ci{ 1401141cc406Sopenharmony_ci FILE *out; 1402141cc406Sopenharmony_ci int r, c, ch; 1403141cc406Sopenharmony_ci SANE_Uint val; 1404141cc406Sopenharmony_ci uint8_t b = 0; 1405141cc406Sopenharmony_ci 1406141cc406Sopenharmony_ci DBG (DBG_info_proc, 1407141cc406Sopenharmony_ci "pie_usb_write_pnm_file: depth=%d, channels=%d, ppl=%d, lines=%d\n", 1408141cc406Sopenharmony_ci depth, channels, pixels_per_line, lines); 1409141cc406Sopenharmony_ci 1410141cc406Sopenharmony_ci out = fopen (filename, "w"); 1411141cc406Sopenharmony_ci if (!out) 1412141cc406Sopenharmony_ci { 1413141cc406Sopenharmony_ci DBG (DBG_error, 1414141cc406Sopenharmony_ci "pie_usb_write_pnm_file: could not open %s for writing: %s\n", 1415141cc406Sopenharmony_ci filename, strerror (errno)); 1416141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1417141cc406Sopenharmony_ci } 1418141cc406Sopenharmony_ci 1419141cc406Sopenharmony_ci switch (depth) { 1420141cc406Sopenharmony_ci case 1: 1421141cc406Sopenharmony_ci fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines); 1422141cc406Sopenharmony_ci for (r = 0; r < lines; r++) { 1423141cc406Sopenharmony_ci int i; 1424141cc406Sopenharmony_ci i = 0; 1425141cc406Sopenharmony_ci b = 0; 1426141cc406Sopenharmony_ci for (c = 0; c < pixels_per_line; c++) { 1427141cc406Sopenharmony_ci val = *(data + r * pixels_per_line + c); 1428141cc406Sopenharmony_ci if (val > 0) b |= (0x80 >> i); 1429141cc406Sopenharmony_ci i++; 1430141cc406Sopenharmony_ci if (i == 7) { 1431141cc406Sopenharmony_ci fputc(b, out); 1432141cc406Sopenharmony_ci i = 0; 1433141cc406Sopenharmony_ci b = 0; 1434141cc406Sopenharmony_ci } 1435141cc406Sopenharmony_ci } 1436141cc406Sopenharmony_ci if (i != 0) { 1437141cc406Sopenharmony_ci fputc(b, out); 1438141cc406Sopenharmony_ci } 1439141cc406Sopenharmony_ci } 1440141cc406Sopenharmony_ci break; 1441141cc406Sopenharmony_ci case 8: 1442141cc406Sopenharmony_ci fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', pixels_per_line, lines, 255); 1443141cc406Sopenharmony_ci for (r = 0; r < lines; r++) { 1444141cc406Sopenharmony_ci for (c = 0; c < pixels_per_line; c++) { 1445141cc406Sopenharmony_ci for (ch = 0; ch < channels; ch++) { 1446141cc406Sopenharmony_ci val = *(data + ch * lines * pixels_per_line + r * pixels_per_line + c); 1447141cc406Sopenharmony_ci b = val & 0xFF; 1448141cc406Sopenharmony_ci fputc(b, out); 1449141cc406Sopenharmony_ci } 1450141cc406Sopenharmony_ci } 1451141cc406Sopenharmony_ci } 1452141cc406Sopenharmony_ci break; 1453141cc406Sopenharmony_ci case 16: 1454141cc406Sopenharmony_ci fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', pixels_per_line, lines, 65535); 1455141cc406Sopenharmony_ci for (r = 0; r < lines; r++) { 1456141cc406Sopenharmony_ci for (c = 0; c < pixels_per_line; c++) { 1457141cc406Sopenharmony_ci for (ch = 0; ch < channels; ch++) { 1458141cc406Sopenharmony_ci val = *(data + ch * lines * pixels_per_line + r * pixels_per_line + c); 1459141cc406Sopenharmony_ci b = (val >> 8) & 0xFF; 1460141cc406Sopenharmony_ci fputc(b, out); 1461141cc406Sopenharmony_ci b = val & 0xFF; 1462141cc406Sopenharmony_ci fputc(b, out); 1463141cc406Sopenharmony_ci } 1464141cc406Sopenharmony_ci } 1465141cc406Sopenharmony_ci } 1466141cc406Sopenharmony_ci break; 1467141cc406Sopenharmony_ci default: 1468141cc406Sopenharmony_ci DBG (DBG_error, "pie_usb_write_pnm_file: depth %d not implemented\n", depth); 1469141cc406Sopenharmony_ci } 1470141cc406Sopenharmony_ci fclose (out); 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ci DBG (DBG_info, "pie_usb_write_pnm_file: finished\n"); 1473141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1474141cc406Sopenharmony_ci} 1475141cc406Sopenharmony_ci 1476141cc406Sopenharmony_ci/** 1477141cc406Sopenharmony_ci * Check option inconsistencies. 1478141cc406Sopenharmony_ci * In most cases an inconsistency can be solved by ignoring an option setting. 1479141cc406Sopenharmony_ci * Message these situations and return 1 to indicate we can work with the 1480141cc406Sopenharmony_ci * current set op options. If the settings are really inconsistent, return 0. 1481141cc406Sopenharmony_ci */ 1482141cc406Sopenharmony_ciint 1483141cc406Sopenharmony_cisanei_pieusb_analyse_options(struct Pieusb_Scanner *scanner) 1484141cc406Sopenharmony_ci{ 1485141cc406Sopenharmony_ci /* Checks*/ 1486141cc406Sopenharmony_ci if (scanner->val[OPT_TL_X].w > scanner->val[OPT_BR_X].w) { 1487141cc406Sopenharmony_ci DBG (DBG_error, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) -- aborting\n", 1488141cc406Sopenharmony_ci scanner->opt[OPT_TL_X].title, 1489141cc406Sopenharmony_ci SANE_UNFIX (scanner->val[OPT_TL_X].w), 1490141cc406Sopenharmony_ci scanner->opt[OPT_BR_X].title, 1491141cc406Sopenharmony_ci SANE_UNFIX (scanner->val[OPT_BR_X].w)); 1492141cc406Sopenharmony_ci return 0; 1493141cc406Sopenharmony_ci } 1494141cc406Sopenharmony_ci if (scanner->val[OPT_TL_Y].w > scanner->val[OPT_BR_Y].w) { 1495141cc406Sopenharmony_ci DBG (DBG_error, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) -- aborting\n", 1496141cc406Sopenharmony_ci scanner->opt[OPT_TL_Y].title, 1497141cc406Sopenharmony_ci SANE_UNFIX (scanner->val[OPT_TL_Y].w), 1498141cc406Sopenharmony_ci scanner->opt[OPT_BR_Y].title, 1499141cc406Sopenharmony_ci SANE_UNFIX (scanner->val[OPT_BR_Y].w)); 1500141cc406Sopenharmony_ci return 0; 1501141cc406Sopenharmony_ci } 1502141cc406Sopenharmony_ci /* Modes sometimes limit other choices */ 1503141cc406Sopenharmony_ci if (scanner->val[OPT_PREVIEW].b) { 1504141cc406Sopenharmony_ci /* Preview uses its own specific settings */ 1505141cc406Sopenharmony_ci if (scanner->val[OPT_RESOLUTION].w != (scanner->device->fast_preview_resolution << SANE_FIXED_SCALE_SHIFT)) { 1506141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %f ignored during preview\n", scanner->opt[OPT_RESOLUTION].name, SANE_UNFIX(scanner->val[OPT_RESOLUTION].w)); 1507141cc406Sopenharmony_ci } 1508141cc406Sopenharmony_ci if (scanner->val[OPT_SHARPEN].b) { 1509141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_SHARPEN].name, scanner->val[OPT_SHARPEN].b); 1510141cc406Sopenharmony_ci } 1511141cc406Sopenharmony_ci if (!scanner->val[OPT_FAST_INFRARED].b) { 1512141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_FAST_INFRARED].name, scanner->val[OPT_FAST_INFRARED].b); 1513141cc406Sopenharmony_ci } 1514141cc406Sopenharmony_ci if (scanner->val[OPT_CORRECT_INFRARED].b) { 1515141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_CORRECT_INFRARED].name, scanner->val[OPT_CORRECT_INFRARED].b); 1516141cc406Sopenharmony_ci } 1517141cc406Sopenharmony_ci if (scanner->val[OPT_CLEAN_IMAGE].b) { 1518141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_CLEAN_IMAGE].name, scanner->val[OPT_CLEAN_IMAGE].b); 1519141cc406Sopenharmony_ci } 1520141cc406Sopenharmony_ci if (scanner->val[OPT_SMOOTH_IMAGE].w != 0) { 1521141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_SMOOTH_IMAGE].name, scanner->val[OPT_SMOOTH_IMAGE].w); 1522141cc406Sopenharmony_ci } 1523141cc406Sopenharmony_ci if (strcmp(scanner->val[OPT_CROP_IMAGE].s, scanner->device->crop_sw_list[0]) != 0) { 1524141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %s ignored during preview\n", scanner->opt[OPT_CROP_IMAGE].name, scanner->val[OPT_CROP_IMAGE].s); 1525141cc406Sopenharmony_ci } 1526141cc406Sopenharmony_ci if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) { 1527141cc406Sopenharmony_ci 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); 1528141cc406Sopenharmony_ci } 1529141cc406Sopenharmony_ci if (scanner->val[OPT_INVERT_IMAGE].w) { 1530141cc406Sopenharmony_ci DBG (DBG_info_sane, "Option %s = %d ignored during preview\n", scanner->opt[OPT_INVERT_IMAGE].name, scanner->val[OPT_INVERT_IMAGE].w); 1531141cc406Sopenharmony_ci } 1532141cc406Sopenharmony_ci } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_LINEART)==0) { 1533141cc406Sopenharmony_ci /* Can we do any post processing in lineart? Needs testing to see what's possible */ 1534141cc406Sopenharmony_ci if (scanner->val[OPT_BIT_DEPTH].w != 1) { 1535141cc406Sopenharmony_ci 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); 1536141cc406Sopenharmony_ci } 1537141cc406Sopenharmony_ci if (!scanner->val[OPT_FAST_INFRARED].b) { 1538141cc406Sopenharmony_ci 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); 1539141cc406Sopenharmony_ci } 1540141cc406Sopenharmony_ci if (!scanner->val[OPT_CORRECT_SHADING].b) { 1541141cc406Sopenharmony_ci 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); 1542141cc406Sopenharmony_ci } 1543141cc406Sopenharmony_ci if (!scanner->val[OPT_CORRECT_INFRARED].b) { 1544141cc406Sopenharmony_ci 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); 1545141cc406Sopenharmony_ci } 1546141cc406Sopenharmony_ci if (scanner->val[OPT_CLEAN_IMAGE].b) { 1547141cc406Sopenharmony_ci 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); 1548141cc406Sopenharmony_ci } 1549141cc406Sopenharmony_ci if (scanner->val[OPT_SMOOTH_IMAGE].w != 0) { 1550141cc406Sopenharmony_ci 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); 1551141cc406Sopenharmony_ci } 1552141cc406Sopenharmony_ci if (strcmp(scanner->val[OPT_CROP_IMAGE].s, scanner->device->crop_sw_list[0]) != 0) { 1553141cc406Sopenharmony_ci 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); 1554141cc406Sopenharmony_ci } 1555141cc406Sopenharmony_ci if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) { 1556141cc406Sopenharmony_ci 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); 1557141cc406Sopenharmony_ci } 1558141cc406Sopenharmony_ci } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_HALFTONE)==0) { 1559141cc406Sopenharmony_ci /* Can we do any post processing in halftone? Needs testing to see what's possible */ 1560141cc406Sopenharmony_ci if (scanner->val[OPT_BIT_DEPTH].w != 1) { 1561141cc406Sopenharmony_ci 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); 1562141cc406Sopenharmony_ci } 1563141cc406Sopenharmony_ci if (!scanner->val[OPT_FAST_INFRARED].b) { 1564141cc406Sopenharmony_ci 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); 1565141cc406Sopenharmony_ci } 1566141cc406Sopenharmony_ci if (!scanner->val[OPT_CORRECT_SHADING].b) { 1567141cc406Sopenharmony_ci 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); 1568141cc406Sopenharmony_ci } 1569141cc406Sopenharmony_ci if (!scanner->val[OPT_CORRECT_INFRARED].b) { 1570141cc406Sopenharmony_ci 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); 1571141cc406Sopenharmony_ci } 1572141cc406Sopenharmony_ci if (scanner->val[OPT_CLEAN_IMAGE].b) { 1573141cc406Sopenharmony_ci 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); 1574141cc406Sopenharmony_ci } 1575141cc406Sopenharmony_ci if (scanner->val[OPT_SMOOTH_IMAGE].w != 0) { 1576141cc406Sopenharmony_ci 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); 1577141cc406Sopenharmony_ci } 1578141cc406Sopenharmony_ci if (strcmp(scanner->val[OPT_CROP_IMAGE].s, scanner->device->crop_sw_list[0]) != 0) { 1579141cc406Sopenharmony_ci 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); 1580141cc406Sopenharmony_ci } 1581141cc406Sopenharmony_ci if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) { 1582141cc406Sopenharmony_ci 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); 1583141cc406Sopenharmony_ci } 1584141cc406Sopenharmony_ci } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_GRAY)==0) { 1585141cc406Sopenharmony_ci /* Can we do any post processing in gray mode? */ 1586141cc406Sopenharmony_ci /* Can we obtain a single color channel in this mode? How? */ 1587141cc406Sopenharmony_ci /* Is this just RGB with luminance trasformation? */ 1588141cc406Sopenharmony_ci /* Needs testing to see what's possible */ 1589141cc406Sopenharmony_ci /* Only do 8 or 16 bit scans */ 1590141cc406Sopenharmony_ci if (scanner->val[OPT_BIT_DEPTH].w == 1) { 1591141cc406Sopenharmony_ci 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); 1592141cc406Sopenharmony_ci } 1593141cc406Sopenharmony_ci if (!scanner->val[OPT_FAST_INFRARED].b) { 1594141cc406Sopenharmony_ci 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); 1595141cc406Sopenharmony_ci } 1596141cc406Sopenharmony_ci if (!scanner->val[OPT_CORRECT_INFRARED].b) { 1597141cc406Sopenharmony_ci 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); 1598141cc406Sopenharmony_ci } 1599141cc406Sopenharmony_ci if (scanner->val[OPT_CLEAN_IMAGE].b) { 1600141cc406Sopenharmony_ci 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); 1601141cc406Sopenharmony_ci } 1602141cc406Sopenharmony_ci if (scanner->val[OPT_TRANSFORM_TO_SRGB].b) { 1603141cc406Sopenharmony_ci 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); 1604141cc406Sopenharmony_ci } 1605141cc406Sopenharmony_ci } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_COLOR)==0) { 1606141cc406Sopenharmony_ci /* Some options require infrared data to be obtained, so all infrared options are relevant */ 1607141cc406Sopenharmony_ci /* Only do 8 or 16 bit scans */ 1608141cc406Sopenharmony_ci if (scanner->val[OPT_BIT_DEPTH].w == 1) { 1609141cc406Sopenharmony_ci 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); 1610141cc406Sopenharmony_ci } 1611141cc406Sopenharmony_ci } else if (strcmp(scanner->val[OPT_MODE].s,SANE_VALUE_SCAN_MODE_RGBI)==0) { 1612141cc406Sopenharmony_ci /* Only do 8 or 16 bit scans */ 1613141cc406Sopenharmony_ci if (scanner->val[OPT_BIT_DEPTH].w == 1) { 1614141cc406Sopenharmony_ci 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); 1615141cc406Sopenharmony_ci } 1616141cc406Sopenharmony_ci } 1617141cc406Sopenharmony_ci 1618141cc406Sopenharmony_ci return 1; 1619141cc406Sopenharmony_ci} 1620141cc406Sopenharmony_ci 1621141cc406Sopenharmony_ci/** 1622141cc406Sopenharmony_ci * Print options 1623141cc406Sopenharmony_ci * 1624141cc406Sopenharmony_ci * @param scanner 1625141cc406Sopenharmony_ci */ 1626141cc406Sopenharmony_civoid 1627141cc406Sopenharmony_cisanei_pieusb_print_options(struct Pieusb_Scanner *scanner) 1628141cc406Sopenharmony_ci{ 1629141cc406Sopenharmony_ci int k; 1630141cc406Sopenharmony_ci /* List current options and values */ 1631141cc406Sopenharmony_ci DBG (DBG_info, "Num options = %d\n", scanner->val[OPT_NUM_OPTS].w); 1632141cc406Sopenharmony_ci for (k = 1; k < scanner->val[OPT_NUM_OPTS].w; k++) { 1633141cc406Sopenharmony_ci switch (scanner->opt[k].type) { 1634141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 1635141cc406Sopenharmony_ci DBG(DBG_info," Option %d: %s = %d\n", k, scanner->opt[k].name, scanner->val[k].b); 1636141cc406Sopenharmony_ci break; 1637141cc406Sopenharmony_ci case SANE_TYPE_INT: 1638141cc406Sopenharmony_ci DBG(DBG_info," Option %d: %s = %d\n", k, scanner->opt[k].name, scanner->val[k].w); 1639141cc406Sopenharmony_ci break; 1640141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 1641141cc406Sopenharmony_ci DBG(DBG_info," Option %d: %s = %f\n", k, scanner->opt[k].name, SANE_UNFIX (scanner->val[k].w)); 1642141cc406Sopenharmony_ci break; 1643141cc406Sopenharmony_ci case SANE_TYPE_STRING: 1644141cc406Sopenharmony_ci DBG(DBG_info," Option %d: %s = %s\n", k, scanner->opt[k].name, scanner->val[k].s); 1645141cc406Sopenharmony_ci break; 1646141cc406Sopenharmony_ci case SANE_TYPE_GROUP: 1647141cc406Sopenharmony_ci DBG(DBG_info," Option %d: %s = %s\n", k, scanner->opt[k].title, scanner->val[k].s); 1648141cc406Sopenharmony_ci break; 1649141cc406Sopenharmony_ci default: 1650141cc406Sopenharmony_ci DBG(DBG_info," Option %d: %s unknown type %d\n", k, scanner->opt[k].name, scanner->opt[k].type); 1651141cc406Sopenharmony_ci break; 1652141cc406Sopenharmony_ci } 1653141cc406Sopenharmony_ci } 1654141cc406Sopenharmony_ci} 1655141cc406Sopenharmony_ci 1656141cc406Sopenharmony_ci/** 1657141cc406Sopenharmony_ci * Calculate reference values for each pixel, line means and line maxima. 1658141cc406Sopenharmony_ci * We have got 45 lines for all four colors and for each CCD pixel. 1659141cc406Sopenharmony_ci * The reference value for each pixel is the 45-line average for that 1660141cc406Sopenharmony_ci * pixel, for each color separately. 1661141cc406Sopenharmony_ci * 1662141cc406Sopenharmony_ci * @param scanner 1663141cc406Sopenharmony_ci * @param buffer 1664141cc406Sopenharmony_ci */ 1665141cc406Sopenharmony_cistatic void pieusb_calculate_shading(struct Pieusb_Scanner *scanner, SANE_Byte* buffer) 1666141cc406Sopenharmony_ci{ 1667141cc406Sopenharmony_ci int k, m; 1668141cc406Sopenharmony_ci SANE_Byte* p; 1669141cc406Sopenharmony_ci SANE_Int ci, val; 1670141cc406Sopenharmony_ci SANE_Int shading_width = scanner->device->shading_parameters[0].pixelsPerLine; 1671141cc406Sopenharmony_ci SANE_Int shading_height = scanner->device->shading_parameters[0].nLines; 1672141cc406Sopenharmony_ci 1673141cc406Sopenharmony_ci /* Initialize all to 0 */ 1674141cc406Sopenharmony_ci for (k = 0; k < SHADING_PARAMETERS_INFO_COUNT; k++) { 1675141cc406Sopenharmony_ci scanner->shading_max[k] = 0; 1676141cc406Sopenharmony_ci scanner->shading_mean[k] = 0; 1677141cc406Sopenharmony_ci memset(scanner->shading_ref[k], 0, shading_width * sizeof (SANE_Int)); 1678141cc406Sopenharmony_ci } 1679141cc406Sopenharmony_ci /* Process data from buffer */ 1680141cc406Sopenharmony_ci p = buffer; 1681141cc406Sopenharmony_ci switch (scanner->mode.colorFormat) { 1682141cc406Sopenharmony_ci case 0x01: /* Pixel */ 1683141cc406Sopenharmony_ci /* Process pixel by pixel */ 1684141cc406Sopenharmony_ci for (k = 0; k < shading_height; k++) { 1685141cc406Sopenharmony_ci for (m = 0; m < shading_width; m++) { 1686141cc406Sopenharmony_ci for (ci = 0; ci < SHADING_PARAMETERS_INFO_COUNT; ci++) { 1687141cc406Sopenharmony_ci val = *(p) + *(p+1) * 256; 1688141cc406Sopenharmony_ci scanner->shading_ref[ci][m] += val; 1689141cc406Sopenharmony_ci scanner->shading_max[ci] = scanner->shading_max[ci] < val ? val : scanner->shading_max[ci]; 1690141cc406Sopenharmony_ci p += 2; 1691141cc406Sopenharmony_ci } 1692141cc406Sopenharmony_ci } 1693141cc406Sopenharmony_ci } 1694141cc406Sopenharmony_ci break; 1695141cc406Sopenharmony_ci case 0x04: /* Indexed */ 1696141cc406Sopenharmony_ci /* Process each line in the sequence found in the buffer */ 1697141cc406Sopenharmony_ci for (k = 0; k < shading_height*4; k++) { 1698141cc406Sopenharmony_ci /* Save at right color */ 1699141cc406Sopenharmony_ci switch (*p) { 1700141cc406Sopenharmony_ci case 'R': ci = 0; break; 1701141cc406Sopenharmony_ci case 'G': ci = 1; break; 1702141cc406Sopenharmony_ci case 'B': ci = 2; break; 1703141cc406Sopenharmony_ci case 'I': ci = 3; break; 1704141cc406Sopenharmony_ci default: ci = -1; break; /* ignore line */ 1705141cc406Sopenharmony_ci } 1706141cc406Sopenharmony_ci /* Add scanned data to reference line and keep track of maximum */ 1707141cc406Sopenharmony_ci if (ci != -1) { 1708141cc406Sopenharmony_ci for (m = 0; m < shading_width; m++) { 1709141cc406Sopenharmony_ci val = *(p+2+2*m) + *(p+2+2*m+1) * 256; 1710141cc406Sopenharmony_ci scanner->shading_ref[ci][m] += val; 1711141cc406Sopenharmony_ci scanner->shading_max[ci] = scanner->shading_max[ci] < val ? val : scanner->shading_max[ci]; 1712141cc406Sopenharmony_ci /* DBG(DBG_error,"%02d Shading_ref[%d][%d] = %d\n",k,ci,m,scanner->shading_ref[ci][m]); */ 1713141cc406Sopenharmony_ci } 1714141cc406Sopenharmony_ci } 1715141cc406Sopenharmony_ci /* Next line */ 1716141cc406Sopenharmony_ci p += 2*shading_width+2; 1717141cc406Sopenharmony_ci } 1718141cc406Sopenharmony_ci break; 1719141cc406Sopenharmony_ci default: 1720141cc406Sopenharmony_ci DBG (DBG_error,"sane_start(): color format %d not implemented\n",scanner->mode.colorFormat); 1721141cc406Sopenharmony_ci return; 1722141cc406Sopenharmony_ci } 1723141cc406Sopenharmony_ci /* Mean reference value needs division */ 1724141cc406Sopenharmony_ci for (k = 0; k < SHADING_PARAMETERS_INFO_COUNT; k++) { 1725141cc406Sopenharmony_ci for (m = 0; m < shading_width; m++) { 1726141cc406Sopenharmony_ci scanner->shading_ref[k][m] = lround((double)scanner->shading_ref[k][m]/shading_height); 1727141cc406Sopenharmony_ci /* DBG(DBG_error,"Shading_ref[%d][%d] = %d\n",k,m,scanner->shading_ref[k][m]); */ 1728141cc406Sopenharmony_ci } 1729141cc406Sopenharmony_ci } 1730141cc406Sopenharmony_ci /* Overall means */ 1731141cc406Sopenharmony_ci for (k = 0; k < SHADING_PARAMETERS_INFO_COUNT; k++) { 1732141cc406Sopenharmony_ci for (m=0; m<shading_width; m++) { 1733141cc406Sopenharmony_ci scanner->shading_mean[k] += scanner->shading_ref[k][m]; 1734141cc406Sopenharmony_ci } 1735141cc406Sopenharmony_ci scanner->shading_mean[k] = lround((double)scanner->shading_mean[k]/shading_width); 1736141cc406Sopenharmony_ci DBG (DBG_error,"Shading_mean[%d] = %d\n",k,scanner->shading_mean[k]); 1737141cc406Sopenharmony_ci } 1738141cc406Sopenharmony_ci 1739141cc406Sopenharmony_ci /* Set shading data present */ 1740141cc406Sopenharmony_ci scanner->shading_data_present = SANE_TRUE; 1741141cc406Sopenharmony_ci 1742141cc406Sopenharmony_ci /* Export shading data as TIFF */ 1743141cc406Sopenharmony_ci#ifdef CAN_DO_4_CHANNEL_TIFF 1744141cc406Sopenharmony_ci if (scanner->val[OPT_SAVE_SHADINGDATA].b) { 1745141cc406Sopenharmony_ci struct Pieusb_Read_Buffer shading; 1746141cc406Sopenharmony_ci SANE_Byte* lboff = buffer; 1747141cc406Sopenharmony_ci SANE_Int bpl = shading_width*2; 1748141cc406Sopenharmony_ci SANE_Int n; 1749141cc406Sopenharmony_ci buffer_create(&shading, shading_width, shading_height, 0x0F, 16); 1750141cc406Sopenharmony_ci for (n=0; n<4*shading_height; n++) { 1751141cc406Sopenharmony_ci if (buffer_put_single_color_line(&shading, *lboff, lboff+2, bpl) == 0) { 1752141cc406Sopenharmony_ci break; 1753141cc406Sopenharmony_ci } 1754141cc406Sopenharmony_ci lboff += (bpl + 2); 1755141cc406Sopenharmony_ci } 1756141cc406Sopenharmony_ci FILE* fs = fopen("pieusb.shading", "w"); 1757141cc406Sopenharmony_ci /* write_tiff_rgbi_header (fs, shading_width, shading_height, 16, 3600, NULL); */ 1758141cc406Sopenharmony_ci fwrite(shading.data, 1, shading.image_size_bytes, fs); 1759141cc406Sopenharmony_ci fclose(fs); 1760141cc406Sopenharmony_ci buffer_delete(&shading); 1761141cc406Sopenharmony_ci } 1762141cc406Sopenharmony_ci#endif 1763141cc406Sopenharmony_ci 1764141cc406Sopenharmony_ci} 1765141cc406Sopenharmony_ci 1766141cc406Sopenharmony_ci/* 1767141cc406Sopenharmony_ci * Set frame (from scanner options) 1768141cc406Sopenharmony_ci */ 1769141cc406Sopenharmony_ci 1770141cc406Sopenharmony_ciSANE_Status 1771141cc406Sopenharmony_cisanei_pieusb_set_frame_from_options(Pieusb_Scanner * scanner) 1772141cc406Sopenharmony_ci{ 1773141cc406Sopenharmony_ci double dpmm; 1774141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 1775141cc406Sopenharmony_ci 1776141cc406Sopenharmony_ci dpmm = (double) scanner->device->maximum_resolution / MM_PER_INCH; 1777141cc406Sopenharmony_ci scanner->frame.x0 = SANE_UNFIX(scanner->val[OPT_TL_X].w) * dpmm; 1778141cc406Sopenharmony_ci scanner->frame.y0 = SANE_UNFIX(scanner->val[OPT_TL_Y].w) * dpmm; 1779141cc406Sopenharmony_ci scanner->frame.x1 = SANE_UNFIX(scanner->val[OPT_BR_X].w) * dpmm; 1780141cc406Sopenharmony_ci scanner->frame.y1 = SANE_UNFIX(scanner->val[OPT_BR_Y].w) * dpmm; 1781141cc406Sopenharmony_ci scanner->frame.index = 0x80; /* 0x80: value from cyberview */ 1782141cc406Sopenharmony_ci sanei_pieusb_cmd_set_scan_frame (scanner->device_number, scanner->frame.index, &(scanner->frame), &status); 1783141cc406Sopenharmony_ci 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))); 1784141cc406Sopenharmony_ci return sanei_pieusb_convert_status (status.pieusb_status); 1785141cc406Sopenharmony_ci} 1786141cc406Sopenharmony_ci 1787141cc406Sopenharmony_ci/* 1788141cc406Sopenharmony_ci * Set mode (from scanner options) 1789141cc406Sopenharmony_ci */ 1790141cc406Sopenharmony_ci 1791141cc406Sopenharmony_ciSANE_Status 1792141cc406Sopenharmony_cisanei_pieusb_set_mode_from_options(Pieusb_Scanner * scanner) 1793141cc406Sopenharmony_ci{ 1794141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 1795141cc406Sopenharmony_ci const char *mode; 1796141cc406Sopenharmony_ci SANE_Status res; 1797141cc406Sopenharmony_ci 1798141cc406Sopenharmony_ci mode = scanner->val[OPT_MODE].s; 1799141cc406Sopenharmony_ci if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) { 1800141cc406Sopenharmony_ci scanner->mode.passes = SCAN_FILTER_GREEN; /* G */ 1801141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_PIXEL; 1802141cc406Sopenharmony_ci } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) { 1803141cc406Sopenharmony_ci scanner->mode.passes = SCAN_FILTER_GREEN; /* G */ 1804141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_PIXEL; 1805141cc406Sopenharmony_ci } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) { 1806141cc406Sopenharmony_ci scanner->mode.passes = SCAN_FILTER_GREEN; /* G=gray; unable to get R & B & I to work */ 1807141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_PIXEL; 1808141cc406Sopenharmony_ci } else if(scanner->val[OPT_PREVIEW].b) { 1809141cc406Sopenharmony_ci /* Catch preview here, otherwise next ifs get complicated */ 1810141cc406Sopenharmony_ci scanner->mode.passes = SCAN_ONE_PASS_COLOR; 1811141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX; /* pixel format might be an alternative */ 1812141cc406Sopenharmony_ci } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_RGBI) == 0) { 1813141cc406Sopenharmony_ci scanner->mode.passes = SCAN_ONE_PASS_RGBI; 1814141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX; 1815141cc406Sopenharmony_ci } else if(strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0 && scanner->val[OPT_CLEAN_IMAGE].b) { 1816141cc406Sopenharmony_ci scanner->mode.passes = SCAN_ONE_PASS_RGBI; /* Need infrared for cleaning */ 1817141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX; 1818141cc406Sopenharmony_ci } else { /* SANE_VALUE_SCAN_MODE_COLOR */ 1819141cc406Sopenharmony_ci scanner->mode.passes = SCAN_ONE_PASS_COLOR; 1820141cc406Sopenharmony_ci scanner->mode.colorFormat = SCAN_COLOR_FORMAT_INDEX; /* pixel format might be an alternative */ 1821141cc406Sopenharmony_ci } 1822141cc406Sopenharmony_ci /* Resolution */ 1823141cc406Sopenharmony_ci if (scanner->val[OPT_PREVIEW].b) { 1824141cc406Sopenharmony_ci scanner->mode.resolution = scanner->device->fast_preview_resolution; 1825141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_set_mode_from_options(): resolution fast preview (%d)\n", scanner->mode.resolution); 1826141cc406Sopenharmony_ci } else { 1827141cc406Sopenharmony_ci scanner->mode.resolution = SANE_UNFIX (scanner->val[OPT_RESOLUTION].w); 1828141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_set_mode_from_options(): resolution from option setting (%d)\n", scanner->mode.resolution); 1829141cc406Sopenharmony_ci } 1830141cc406Sopenharmony_ci /* Bit depth: exit on untested values */ 1831141cc406Sopenharmony_ci switch (scanner->val[OPT_BIT_DEPTH].w) { 1832141cc406Sopenharmony_ci case 1: scanner->mode.colorDepth = SCAN_COLOR_DEPTH_1; break; 1833141cc406Sopenharmony_ci case 8: scanner->mode.colorDepth = SCAN_COLOR_DEPTH_8; break; 1834141cc406Sopenharmony_ci case 16: scanner->mode.colorDepth = SCAN_COLOR_DEPTH_16; break; 1835141cc406Sopenharmony_ci default: /* 4, 10 & 12 */ 1836141cc406Sopenharmony_ci 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); 1837141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1838141cc406Sopenharmony_ci } 1839141cc406Sopenharmony_ci scanner->mode.byteOrder = 0x01; /* 0x01 = Intel; only bit 0 used */ 1840141cc406Sopenharmony_ci scanner->mode.sharpen = scanner->val[OPT_SHARPEN].b && !scanner->val[OPT_PREVIEW].b; 1841141cc406Sopenharmony_ci scanner->mode.skipShadingAnalysis = !scanner->val[OPT_SHADING_ANALYSIS].b; 1842141cc406Sopenharmony_ci scanner->mode.fastInfrared = scanner->val[OPT_FAST_INFRARED].b && !scanner->val[OPT_PREVIEW].b; 1843141cc406Sopenharmony_ci if (strcmp (scanner->val[OPT_HALFTONE_PATTERN].s, "53lpi 45d ROUND") == 0) { 1844141cc406Sopenharmony_ci scanner->mode.halftonePattern = 0; 1845141cc406Sopenharmony_ci } else { /*TODO: the others */ 1846141cc406Sopenharmony_ci scanner->mode.halftonePattern = 0; 1847141cc406Sopenharmony_ci } 1848141cc406Sopenharmony_ci scanner->mode.lineThreshold = SANE_UNFIX (scanner->val[OPT_THRESHOLD].w) / 100 * 0xFF; /* 0xFF = 100% */ 1849141cc406Sopenharmony_ci sanei_pieusb_cmd_set_mode (scanner->device_number, &(scanner->mode), &status); 1850141cc406Sopenharmony_ci res = sanei_pieusb_convert_status(status.pieusb_status); 1851141cc406Sopenharmony_ci if (res == SANE_STATUS_GOOD) { 1852141cc406Sopenharmony_ci res = sanei_pieusb_wait_ready (scanner, 0); 1853141cc406Sopenharmony_ci } 1854141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_set_mode_from_options(): sanei_pieusb_cmd_set_mode status %s\n", sane_strstatus(res)); 1855141cc406Sopenharmony_ci return res; 1856141cc406Sopenharmony_ci} 1857141cc406Sopenharmony_ci 1858141cc406Sopenharmony_ci/** 1859141cc406Sopenharmony_ci * Set gains, exposure and offset, to: 1860141cc406Sopenharmony_ci * - values default (pieusb_set_default_gain_offset) 1861141cc406Sopenharmony_ci * - values set by options 1862141cc406Sopenharmony_ci * - values set by auto-calibration procedure 1863141cc406Sopenharmony_ci * - values determined from preceding preview 1864141cc406Sopenharmony_ci * 1865141cc406Sopenharmony_ci * @param scanner 1866141cc406Sopenharmony_ci * @return 1867141cc406Sopenharmony_ci */ 1868141cc406Sopenharmony_ciSANE_Status 1869141cc406Sopenharmony_cisanei_pieusb_set_gain_offset(Pieusb_Scanner * scanner, const char *calibration_mode) 1870141cc406Sopenharmony_ci{ 1871141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 1872141cc406Sopenharmony_ci SANE_Status ret; 1873141cc406Sopenharmony_ci double gain; 1874141cc406Sopenharmony_ci 1875141cc406Sopenharmony_ci DBG (DBG_info,"sanei_pieusb_set_gain_offset(): mode = %s\n", calibration_mode); 1876141cc406Sopenharmony_ci 1877141cc406Sopenharmony_ci if (strcmp (calibration_mode, SCAN_CALIBRATION_DEFAULT) == 0) { 1878141cc406Sopenharmony_ci /* Default values */ 1879141cc406Sopenharmony_ci DBG(DBG_info_sane,"sanei_pieusb_set_gain_offset(): get calibration data from defaults\n"); 1880141cc406Sopenharmony_ci scanner->settings.exposureTime[0] = DEFAULT_EXPOSURE; 1881141cc406Sopenharmony_ci scanner->settings.exposureTime[1] = DEFAULT_EXPOSURE; 1882141cc406Sopenharmony_ci scanner->settings.exposureTime[2] = DEFAULT_EXPOSURE; 1883141cc406Sopenharmony_ci scanner->settings.exposureTime[3] = DEFAULT_EXPOSURE; 1884141cc406Sopenharmony_ci scanner->settings.offset[0] = DEFAULT_OFFSET; 1885141cc406Sopenharmony_ci scanner->settings.offset[1] = DEFAULT_OFFSET; 1886141cc406Sopenharmony_ci scanner->settings.offset[2] = DEFAULT_OFFSET; 1887141cc406Sopenharmony_ci scanner->settings.offset[3] = DEFAULT_OFFSET; 1888141cc406Sopenharmony_ci scanner->settings.gain[0] = DEFAULT_GAIN; 1889141cc406Sopenharmony_ci scanner->settings.gain[1] = DEFAULT_GAIN; 1890141cc406Sopenharmony_ci scanner->settings.gain[2] = DEFAULT_GAIN; 1891141cc406Sopenharmony_ci scanner->settings.gain[3] = DEFAULT_GAIN; 1892141cc406Sopenharmony_ci scanner->settings.light = DEFAULT_LIGHT; 1893141cc406Sopenharmony_ci scanner->settings.extraEntries = DEFAULT_ADDITIONAL_ENTRIES; 1894141cc406Sopenharmony_ci scanner->settings.doubleTimes = DEFAULT_DOUBLE_TIMES; 1895141cc406Sopenharmony_ci status.pieusb_status = PIEUSB_STATUS_GOOD; 1896141cc406Sopenharmony_ci } else if ((strcmp(calibration_mode, SCAN_CALIBRATION_PREVIEW) == 0) 1897141cc406Sopenharmony_ci && scanner->preview_done) { 1898141cc406Sopenharmony_ci /* If no preview data available, do the auto-calibration. */ 1899141cc406Sopenharmony_ci double dg, dgi; 1900141cc406Sopenharmony_ci DBG (DBG_info, "sanei_pieusb_set_gain_offset(): get calibration data from preview. scanner->mode.passes %d\n", scanner->mode.passes); 1901141cc406Sopenharmony_ci switch (scanner->mode.passes) { 1902141cc406Sopenharmony_ci case SCAN_ONE_PASS_RGBI: 1903141cc406Sopenharmony_ci dg = 3.00; 1904141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[0] / 65536) / ((double)scanner->preview_upper_bound[0] / HISTOGRAM_SIZE); 1905141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1906141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[1] / 65536) / ((double)scanner->preview_upper_bound[1] / HISTOGRAM_SIZE); 1907141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1908141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[2] / 65536) / ((double)scanner->preview_upper_bound[2] / HISTOGRAM_SIZE); 1909141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1910141cc406Sopenharmony_ci updateGain2(scanner, 0, dg); 1911141cc406Sopenharmony_ci updateGain2(scanner, 1, dg); 1912141cc406Sopenharmony_ci updateGain2(scanner, 2, dg); 1913141cc406Sopenharmony_ci break; 1914141cc406Sopenharmony_ci case SCAN_ONE_PASS_COLOR: 1915141cc406Sopenharmony_ci dg = 3.00; 1916141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[0] / 65536) / ((double)scanner->preview_upper_bound[0] / HISTOGRAM_SIZE); 1917141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1918141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[1] / 65536) / ((double)scanner->preview_upper_bound[1] / HISTOGRAM_SIZE); 1919141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1920141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[2] / 65536) / ((double)scanner->preview_upper_bound[2] / HISTOGRAM_SIZE); 1921141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1922141cc406Sopenharmony_ci updateGain2(scanner, 0, dg); 1923141cc406Sopenharmony_ci updateGain2(scanner, 1, dg); 1924141cc406Sopenharmony_ci updateGain2(scanner, 2, dg); 1925141cc406Sopenharmony_ci break; 1926141cc406Sopenharmony_ci case SCAN_FILTER_BLUE: 1927141cc406Sopenharmony_ci dg = 3.00; 1928141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[2] / 65536) / ((double)scanner->preview_upper_bound[2] / HISTOGRAM_SIZE); 1929141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1930141cc406Sopenharmony_ci updateGain2(scanner, 2, dg); 1931141cc406Sopenharmony_ci break; 1932141cc406Sopenharmony_ci case SCAN_FILTER_GREEN: 1933141cc406Sopenharmony_ci dg = 3.00; 1934141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[1] / 65536) / ((double)scanner->preview_upper_bound[1] / HISTOGRAM_SIZE); 1935141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1936141cc406Sopenharmony_ci updateGain2(scanner, 1, dg); 1937141cc406Sopenharmony_ci break; 1938141cc406Sopenharmony_ci case SCAN_FILTER_RED: 1939141cc406Sopenharmony_ci dg = 3.00; 1940141cc406Sopenharmony_ci dgi = ((double)scanner->settings.saturationLevel[0] / 65536) / ((double)scanner->preview_upper_bound[0] / HISTOGRAM_SIZE); 1941141cc406Sopenharmony_ci if (dgi < dg) dg = dgi; 1942141cc406Sopenharmony_ci updateGain2(scanner, 0, dg); 1943141cc406Sopenharmony_ci break; 1944141cc406Sopenharmony_ci case SCAN_FILTER_NEUTRAL: 1945141cc406Sopenharmony_ci break; 1946141cc406Sopenharmony_ci } 1947141cc406Sopenharmony_ci status.pieusb_status = PIEUSB_STATUS_GOOD; 1948141cc406Sopenharmony_ci } else if (strcmp (calibration_mode, SCAN_CALIBRATION_OPTIONS) == 0) { 1949141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_set_gain_offset(): get calibration data from options\n"); 1950141cc406Sopenharmony_ci /* Exposure times */ 1951141cc406Sopenharmony_ci scanner->settings.exposureTime[0] = scanner->val[OPT_SET_EXPOSURE_R].w; 1952141cc406Sopenharmony_ci scanner->settings.exposureTime[1] = scanner->val[OPT_SET_EXPOSURE_G].w; 1953141cc406Sopenharmony_ci scanner->settings.exposureTime[2] = scanner->val[OPT_SET_EXPOSURE_B].w; 1954141cc406Sopenharmony_ci scanner->settings.exposureTime[3] = scanner->val[OPT_SET_EXPOSURE_I].w; /* Infrared */ 1955141cc406Sopenharmony_ci /* Offsets */ 1956141cc406Sopenharmony_ci scanner->settings.offset[0] = scanner->val[OPT_SET_OFFSET_R].w; 1957141cc406Sopenharmony_ci scanner->settings.offset[1] = scanner->val[OPT_SET_OFFSET_G].w; 1958141cc406Sopenharmony_ci scanner->settings.offset[2] = scanner->val[OPT_SET_OFFSET_B].w; 1959141cc406Sopenharmony_ci scanner->settings.offset[3] = scanner->val[OPT_SET_OFFSET_I].w; /* Infrared */ 1960141cc406Sopenharmony_ci /* Gains */ 1961141cc406Sopenharmony_ci scanner->settings.gain[0] = scanner->val[OPT_SET_GAIN_R].w; 1962141cc406Sopenharmony_ci scanner->settings.gain[1] = scanner->val[OPT_SET_GAIN_G].w; 1963141cc406Sopenharmony_ci scanner->settings.gain[2] = scanner->val[OPT_SET_GAIN_B].w; 1964141cc406Sopenharmony_ci scanner->settings.gain[3] = scanner->val[OPT_SET_GAIN_I].w; /* Infrared */ 1965141cc406Sopenharmony_ci /* Light, extra entries and doubling */ 1966141cc406Sopenharmony_ci scanner->settings.light = scanner->val[OPT_LIGHT].w; 1967141cc406Sopenharmony_ci scanner->settings.extraEntries = DEFAULT_ADDITIONAL_ENTRIES; 1968141cc406Sopenharmony_ci scanner->settings.doubleTimes = scanner->val[OPT_DOUBLE_TIMES].w; 1969141cc406Sopenharmony_ci status.pieusb_status = PIEUSB_STATUS_GOOD; 1970141cc406Sopenharmony_ci } else { /* SCAN_CALIBRATION_AUTO */ 1971141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_set_gain_offset(): get calibration data from scanner\n"); 1972141cc406Sopenharmony_ci sanei_pieusb_cmd_get_gain_offset (scanner->device_number, &scanner->settings, &status); 1973141cc406Sopenharmony_ci } 1974141cc406Sopenharmony_ci /* Check status */ 1975141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_DEVICE_BUSY) { 1976141cc406Sopenharmony_ci ret = sanei_pieusb_wait_ready (scanner, 0); 1977141cc406Sopenharmony_ci if (ret != SANE_STATUS_GOOD) { 1978141cc406Sopenharmony_ci DBG (DBG_error,"sanei_pieusb_set_gain_offset(): not ready after sanei_pieusb_cmd_get_gain_offset(): %d\n", ret); 1979141cc406Sopenharmony_ci return ret; 1980141cc406Sopenharmony_ci } 1981141cc406Sopenharmony_ci } 1982141cc406Sopenharmony_ci else if (status.pieusb_status != PIEUSB_STATUS_GOOD) { 1983141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1984141cc406Sopenharmony_ci } 1985141cc406Sopenharmony_ci /* Adjust gain */ 1986141cc406Sopenharmony_ci gain = 1.0; 1987141cc406Sopenharmony_ci if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_03) == 0) { 1988141cc406Sopenharmony_ci gain = 0.3; 1989141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_05) == 0) { 1990141cc406Sopenharmony_ci gain = 0.5; 1991141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_08) == 0) { 1992141cc406Sopenharmony_ci gain = 0.8; 1993141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_10) == 0) { 1994141cc406Sopenharmony_ci gain = 1.0; 1995141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_12) == 0) { 1996141cc406Sopenharmony_ci gain = 1.2; 1997141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_16) == 0) { 1998141cc406Sopenharmony_ci gain = 1.6; 1999141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_19) == 0) { 2000141cc406Sopenharmony_ci gain = 1.9; 2001141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_24) == 0) { 2002141cc406Sopenharmony_ci gain = 2.4; 2003141cc406Sopenharmony_ci } else if (strcmp (scanner->val[OPT_GAIN_ADJUST].s, SCAN_GAIN_ADJUST_30) == 0) { 2004141cc406Sopenharmony_ci gain = 3.0; 2005141cc406Sopenharmony_ci } 2006141cc406Sopenharmony_ci switch (scanner->mode.passes) { 2007141cc406Sopenharmony_ci case SCAN_ONE_PASS_RGBI: 2008141cc406Sopenharmony_ci case SCAN_ONE_PASS_COLOR: 2009141cc406Sopenharmony_ci updateGain2 (scanner, 0, gain); 2010141cc406Sopenharmony_ci updateGain2 (scanner, 1, gain); 2011141cc406Sopenharmony_ci updateGain2 (scanner, 2, gain); 2012141cc406Sopenharmony_ci /* Don't correct IR, hampers cleaning process... */ 2013141cc406Sopenharmony_ci break; 2014141cc406Sopenharmony_ci case SCAN_FILTER_INFRARED: 2015141cc406Sopenharmony_ci updateGain2 (scanner, 3, gain); 2016141cc406Sopenharmony_ci break; 2017141cc406Sopenharmony_ci case SCAN_FILTER_BLUE: 2018141cc406Sopenharmony_ci updateGain2 (scanner, 2, gain); 2019141cc406Sopenharmony_ci break; 2020141cc406Sopenharmony_ci case SCAN_FILTER_GREEN: 2021141cc406Sopenharmony_ci updateGain2 (scanner, 1, gain); 2022141cc406Sopenharmony_ci break; 2023141cc406Sopenharmony_ci case SCAN_FILTER_RED: 2024141cc406Sopenharmony_ci updateGain2 (scanner, 0, gain); 2025141cc406Sopenharmony_ci break; 2026141cc406Sopenharmony_ci case SCAN_FILTER_NEUTRAL: 2027141cc406Sopenharmony_ci break; 2028141cc406Sopenharmony_ci } 2029141cc406Sopenharmony_ci /* Now set values for gain, offset and exposure */ 2030141cc406Sopenharmony_ci sanei_pieusb_cmd_set_gain_offset (scanner->device_number, &(scanner->settings), &status); 2031141cc406Sopenharmony_ci ret = sanei_pieusb_convert_status (status.pieusb_status); 2032141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_set_gain_offset(): status %s\n", sane_strstatus (ret)); 2033141cc406Sopenharmony_ci return ret; 2034141cc406Sopenharmony_ci} 2035141cc406Sopenharmony_ci 2036141cc406Sopenharmony_ci/* 2037141cc406Sopenharmony_ci * get shading data 2038141cc406Sopenharmony_ci * must be called immediately after sanei_pieusb_set_gain_offset 2039141cc406Sopenharmony_ci */ 2040141cc406Sopenharmony_ci 2041141cc406Sopenharmony_ciSANE_Status 2042141cc406Sopenharmony_cisanei_pieusb_get_shading_data(Pieusb_Scanner * scanner) 2043141cc406Sopenharmony_ci{ 2044141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 2045141cc406Sopenharmony_ci SANE_Int shading_width; 2046141cc406Sopenharmony_ci SANE_Int shading_height; 2047141cc406Sopenharmony_ci SANE_Byte* buffer; 2048141cc406Sopenharmony_ci SANE_Int lines; 2049141cc406Sopenharmony_ci SANE_Int cols; 2050141cc406Sopenharmony_ci SANE_Int size; 2051141cc406Sopenharmony_ci SANE_Status res = SANE_STATUS_GOOD; 2052141cc406Sopenharmony_ci 2053141cc406Sopenharmony_ci DBG (DBG_info_sane, "sanei_pieusb_get_shading_data()\n"); 2054141cc406Sopenharmony_ci shading_width = scanner->device->shading_parameters[0].pixelsPerLine; 2055141cc406Sopenharmony_ci shading_height = scanner->device->shading_parameters[0].nLines; 2056141cc406Sopenharmony_ci if (shading_height < 1) { 2057141cc406Sopenharmony_ci DBG (DBG_error, "shading_height < 1\n"); 2058141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2059141cc406Sopenharmony_ci } 2060141cc406Sopenharmony_ci switch (scanner->mode.colorFormat) { 2061141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_PIXEL: /* Pixel */ 2062141cc406Sopenharmony_ci lines = shading_height * 4; 2063141cc406Sopenharmony_ci cols = 2 * shading_width; 2064141cc406Sopenharmony_ci break; 2065141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_INDEX: /* Indexed */ 2066141cc406Sopenharmony_ci lines = shading_height * 4; 2067141cc406Sopenharmony_ci cols = (2 * shading_width + 2); 2068141cc406Sopenharmony_ci break; 2069141cc406Sopenharmony_ci default: 2070141cc406Sopenharmony_ci DBG (DBG_error, "sanei_pieusb_get_shading_data(): color format %d not implemented\n", scanner->mode.colorFormat); 2071141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2072141cc406Sopenharmony_ci } 2073141cc406Sopenharmony_ci 2074141cc406Sopenharmony_ci size = cols * lines; 2075141cc406Sopenharmony_ci buffer = malloc (size); 2076141cc406Sopenharmony_ci if (buffer == NULL) { 2077141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2078141cc406Sopenharmony_ci } 2079141cc406Sopenharmony_ci sanei_pieusb_cmd_get_scanned_lines (scanner->device_number, buffer, 4, cols * 4, &status); 2080141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_GOOD) { 2081141cc406Sopenharmony_ci res = sanei_pieusb_wait_ready (scanner, 0); 2082141cc406Sopenharmony_ci if (res == SANE_STATUS_GOOD) { 2083141cc406Sopenharmony_ci sanei_pieusb_cmd_get_scanned_lines (scanner->device_number, buffer + cols*4, lines - 4, (lines - 4) * cols, &status); 2084141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_GOOD) { 2085141cc406Sopenharmony_ci pieusb_calculate_shading (scanner, buffer); 2086141cc406Sopenharmony_ci } 2087141cc406Sopenharmony_ci res = sanei_pieusb_convert_status (status.pieusb_status); 2088141cc406Sopenharmony_ci } 2089141cc406Sopenharmony_ci } 2090141cc406Sopenharmony_ci else { 2091141cc406Sopenharmony_ci res = sanei_pieusb_convert_status (status.pieusb_status); 2092141cc406Sopenharmony_ci } 2093141cc406Sopenharmony_ci free (buffer); 2094141cc406Sopenharmony_ci return res; 2095141cc406Sopenharmony_ci} 2096141cc406Sopenharmony_ci 2097141cc406Sopenharmony_ci/* 2098141cc406Sopenharmony_ci * 2099141cc406Sopenharmony_ci */ 2100141cc406Sopenharmony_ci 2101141cc406Sopenharmony_ciSANE_Status 2102141cc406Sopenharmony_cisanei_pieusb_get_ccd_mask(Pieusb_Scanner * scanner) 2103141cc406Sopenharmony_ci{ 2104141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 2105141cc406Sopenharmony_ci 2106141cc406Sopenharmony_ci DBG(DBG_info_proc, "sanei_pieusb_get_ccd_mask()\n"); 2107141cc406Sopenharmony_ci 2108141cc406Sopenharmony_ci sanei_pieusb_cmd_get_ccd_mask(scanner->device_number, scanner->ccd_mask, scanner->ccd_mask_size, &status); 2109141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_GOOD) { 2110141cc406Sopenharmony_ci /* Save CCD mask */ 2111141cc406Sopenharmony_ci if (scanner->val[OPT_SAVE_CCDMASK].b) { 2112141cc406Sopenharmony_ci FILE* fs = fopen ("pieusb.ccd", "w"); 2113141cc406Sopenharmony_ci fwrite (scanner->ccd_mask, 1, scanner->ccd_mask_size, fs); 2114141cc406Sopenharmony_ci fclose (fs); 2115141cc406Sopenharmony_ci } 2116141cc406Sopenharmony_ci } 2117141cc406Sopenharmony_ci return sanei_pieusb_convert_status(status.pieusb_status); 2118141cc406Sopenharmony_ci 2119141cc406Sopenharmony_ci} 2120141cc406Sopenharmony_ci 2121141cc406Sopenharmony_ci/** 2122141cc406Sopenharmony_ci * Read parameters from scanner 2123141cc406Sopenharmony_ci * and initialize SANE parameters 2124141cc406Sopenharmony_ci * 2125141cc406Sopenharmony_ci * @param scanner 2126141cc406Sopenharmony_ci * @return parameter_bytes for use in get_scan_data() 2127141cc406Sopenharmony_ci */ 2128141cc406Sopenharmony_ciSANE_Status 2129141cc406Sopenharmony_cisanei_pieusb_get_parameters(Pieusb_Scanner * scanner, SANE_Int *parameter_bytes) 2130141cc406Sopenharmony_ci{ 2131141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 2132141cc406Sopenharmony_ci struct Pieusb_Scan_Parameters parameters; 2133141cc406Sopenharmony_ci const char *mode; 2134141cc406Sopenharmony_ci 2135141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_get_parameters()\n"); 2136141cc406Sopenharmony_ci 2137141cc406Sopenharmony_ci sanei_pieusb_cmd_get_parameters (scanner->device_number, ¶meters, &status); 2138141cc406Sopenharmony_ci if (status.pieusb_status != PIEUSB_STATUS_GOOD) { 2139141cc406Sopenharmony_ci return sanei_pieusb_convert_status (status.pieusb_status); 2140141cc406Sopenharmony_ci } 2141141cc406Sopenharmony_ci *parameter_bytes = parameters.bytes; 2142141cc406Sopenharmony_ci /* Use response from sanei_pieusb_cmd_get_parameters() for initialization of SANE parameters. 2143141cc406Sopenharmony_ci * Note the weird values of the bytes-field: this is because of the colorFormat 2144141cc406Sopenharmony_ci * setting in sanei_pieusb_cmd_set_mode(). The single-color modes all use the pixel format, 2145141cc406Sopenharmony_ci * which makes sanei_pieusb_cmd_get_parameters() return a full color line although just 2146141cc406Sopenharmony_ci * one color actually contains data. For the index format, the bytes field 2147141cc406Sopenharmony_ci * gives the size of a single color line. */ 2148141cc406Sopenharmony_ci mode = scanner->val[OPT_MODE].s; 2149141cc406Sopenharmony_ci if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) { 2150141cc406Sopenharmony_ci scanner->scan_parameters.format = SANE_FRAME_GRAY; 2151141cc406Sopenharmony_ci scanner->scan_parameters.depth = 1; 2152141cc406Sopenharmony_ci scanner->scan_parameters.bytes_per_line = parameters.bytes/3; 2153141cc406Sopenharmony_ci } else if (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) { 2154141cc406Sopenharmony_ci scanner->scan_parameters.format = SANE_FRAME_GRAY; 2155141cc406Sopenharmony_ci scanner->scan_parameters.depth = 1; 2156141cc406Sopenharmony_ci scanner->scan_parameters.bytes_per_line = parameters.bytes/3; 2157141cc406Sopenharmony_ci } else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) { 2158141cc406Sopenharmony_ci scanner->scan_parameters.format = SANE_FRAME_GRAY; 2159141cc406Sopenharmony_ci scanner->scan_parameters.depth = scanner->val[OPT_BIT_DEPTH].w; 2160141cc406Sopenharmony_ci scanner->scan_parameters.bytes_per_line = parameters.bytes/3; 2161141cc406Sopenharmony_ci } else if (strcmp (mode, SANE_VALUE_SCAN_MODE_RGBI) == 0) { 2162141cc406Sopenharmony_ci scanner->scan_parameters.format = SANE_FRAME_RGB; /* was: SANE_FRAME_RGBI */ 2163141cc406Sopenharmony_ci scanner->scan_parameters.depth = scanner->val[OPT_BIT_DEPTH].w; 2164141cc406Sopenharmony_ci scanner->scan_parameters.bytes_per_line = 4*parameters.bytes; 2165141cc406Sopenharmony_ci } else { /* SANE_VALUE_SCAN_MODE_COLOR, with and without option clean image set */ 2166141cc406Sopenharmony_ci scanner->scan_parameters.format = SANE_FRAME_RGB; 2167141cc406Sopenharmony_ci scanner->scan_parameters.depth = scanner->val[OPT_BIT_DEPTH].w; 2168141cc406Sopenharmony_ci scanner->scan_parameters.bytes_per_line = 3*parameters.bytes; 2169141cc406Sopenharmony_ci } 2170141cc406Sopenharmony_ci scanner->scan_parameters.lines = parameters.lines; 2171141cc406Sopenharmony_ci scanner->scan_parameters.pixels_per_line = parameters.width; 2172141cc406Sopenharmony_ci scanner->scan_parameters.last_frame = SANE_TRUE; 2173141cc406Sopenharmony_ci 2174141cc406Sopenharmony_ci DBG (DBG_info_sane,"sanei_pieusb_get_parameters(): mode '%s'\n", mode); 2175141cc406Sopenharmony_ci DBG (DBG_info_sane," format = %d\n", scanner->scan_parameters.format); 2176141cc406Sopenharmony_ci DBG (DBG_info_sane," depth = %d\n", scanner->scan_parameters.depth); 2177141cc406Sopenharmony_ci DBG (DBG_info_sane," bytes_per_line = %d\n", scanner->scan_parameters.bytes_per_line); 2178141cc406Sopenharmony_ci DBG (DBG_info_sane," lines = %d\n", scanner->scan_parameters.lines); 2179141cc406Sopenharmony_ci DBG (DBG_info_sane," pixels_per_line = %d\n", scanner->scan_parameters.pixels_per_line); 2180141cc406Sopenharmony_ci DBG (DBG_info_sane," last_frame = %d\n", scanner->scan_parameters.last_frame); 2181141cc406Sopenharmony_ci 2182141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2183141cc406Sopenharmony_ci} 2184141cc406Sopenharmony_ci 2185141cc406Sopenharmony_ciSANE_Status 2186141cc406Sopenharmony_cisanei_pieusb_get_scan_data(Pieusb_Scanner * scanner, SANE_Int parameter_bytes) 2187141cc406Sopenharmony_ci{ 2188141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 2189141cc406Sopenharmony_ci SANE_Parameters *parameters = &scanner->scan_parameters; 2190141cc406Sopenharmony_ci SANE_Int lines_to_read, lines_remaining; 2191141cc406Sopenharmony_ci SANE_Int ppl, bpl; 2192141cc406Sopenharmony_ci SANE_Byte *linebuf, *lboff; 2193141cc406Sopenharmony_ci SANE_Bool compress; 2194141cc406Sopenharmony_ci int n, k, i; 2195141cc406Sopenharmony_ci 2196141cc406Sopenharmony_ci switch (scanner->mode.colorFormat) { 2197141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_PIXEL: /* Pixel */ 2198141cc406Sopenharmony_ci lines_to_read = scanner->buffer.height; 2199141cc406Sopenharmony_ci break; 2200141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_INDEX: /* Indexed */ 2201141cc406Sopenharmony_ci lines_to_read = scanner->buffer.colors * scanner->buffer.height; 2202141cc406Sopenharmony_ci break; 2203141cc406Sopenharmony_ci default: 2204141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_get_scan_data(): color format %d not implemented\n",scanner->mode.colorFormat); 2205141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2206141cc406Sopenharmony_ci } 2207141cc406Sopenharmony_ci lines_remaining = lines_to_read; 2208141cc406Sopenharmony_ci 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); 2209141cc406Sopenharmony_ci 2210141cc406Sopenharmony_ci /* 2211141cc406Sopenharmony_ci fdraw = open("/tmp/pieusb.raw", O_WRONLY | O_CREAT | O_TRUNC, (mode_t)0600); 2212141cc406Sopenharmony_ci if (fdraw == -1) { 2213141cc406Sopenharmony_ci perror("error opening raw image buffer file"); 2214141cc406Sopenharmony_ci } 2215141cc406Sopenharmony_ci*/ 2216141cc406Sopenharmony_ci while (lines_remaining > 0) { 2217141cc406Sopenharmony_ci SANE_Int lines; 2218141cc406Sopenharmony_ci /* Read lines */ 2219141cc406Sopenharmony_ci /* The amount of bytes_per_line varies with color format setting; only 'pixel' and 'index' implemented */ 2220141cc406Sopenharmony_ci ppl = parameters->pixels_per_line; 2221141cc406Sopenharmony_ci switch (scanner->mode.colorFormat) { 2222141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_PIXEL: /* Pixel */ 2223141cc406Sopenharmony_ci bpl = parameter_bytes; 2224141cc406Sopenharmony_ci break; 2225141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_INDEX: /* Indexed */ 2226141cc406Sopenharmony_ci bpl = parameter_bytes + 2; /* Index bytes! */ 2227141cc406Sopenharmony_ci break; 2228141cc406Sopenharmony_ci default: 2229141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_get_scan_data(): color format %d not implemented\n", scanner->mode.colorFormat); 2230141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2231141cc406Sopenharmony_ci } 2232141cc406Sopenharmony_ci lines = (lines_remaining < 256) ? lines_remaining : 255; 2233141cc406Sopenharmony_ci DBG(DBG_info_sane, "sanei_pieusb_get_scan_data(): reading lines: now %d, bytes per line = %d\n", lines, bpl); 2234141cc406Sopenharmony_ci linebuf = malloc(lines * bpl); 2235141cc406Sopenharmony_ci sanei_pieusb_cmd_get_scanned_lines(scanner->device_number, linebuf, lines, lines * bpl, &status); 2236141cc406Sopenharmony_ci if (status.pieusb_status != PIEUSB_STATUS_GOOD ) { 2237141cc406Sopenharmony_ci /* Error, return */ 2238141cc406Sopenharmony_ci free(linebuf); 2239141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2240141cc406Sopenharmony_ci } 2241141cc406Sopenharmony_ci /* Save raw data */ 2242141cc406Sopenharmony_ci/* 2243141cc406Sopenharmony_ci if (fdraw != -1) { 2244141cc406Sopenharmony_ci wcnt = write(fdraw,linebuf,parameters.lines*bpl); 2245141cc406Sopenharmony_ci DBG(DBG_info_sane,"Raw written %d\n",wcnt); 2246141cc406Sopenharmony_ci } 2247141cc406Sopenharmony_ci*/ 2248141cc406Sopenharmony_ci /* Copy into official buffer 2249141cc406Sopenharmony_ci * Sometimes the scanner returns too many lines. Take care not to 2250141cc406Sopenharmony_ci * overflow the buffer. */ 2251141cc406Sopenharmony_ci lboff = linebuf; 2252141cc406Sopenharmony_ci switch (scanner->mode.colorFormat) { 2253141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_PIXEL: 2254141cc406Sopenharmony_ci /* The scanner may return lines with 3 colors even though only 2255141cc406Sopenharmony_ci * one color is actually scanned. Detect this situation and 2256141cc406Sopenharmony_ci * eliminate the excess samples from the line buffer before 2257141cc406Sopenharmony_ci * handing it to buffer_put_full_color_line(). */ 2258141cc406Sopenharmony_ci compress = SANE_FALSE; 2259141cc406Sopenharmony_ci if (scanner->buffer.colors == 1 2260141cc406Sopenharmony_ci && (bpl * scanner->buffer.packing_density / ppl) == (3 * scanner->buffer.packet_size_bytes)) { 2261141cc406Sopenharmony_ci compress = SANE_TRUE; 2262141cc406Sopenharmony_ci } 2263141cc406Sopenharmony_ci for (n = 0; n < lines; n++) { 2264141cc406Sopenharmony_ci if (compress) { 2265141cc406Sopenharmony_ci /* Move samples to fill up all unused locations */ 2266141cc406Sopenharmony_ci int ps = scanner->buffer.packet_size_bytes; 2267141cc406Sopenharmony_ci for (k = 0; k < scanner->buffer.line_size_packets; k++) { 2268141cc406Sopenharmony_ci for (i = 0; i < ps; i++) { 2269141cc406Sopenharmony_ci lboff[ps*k+i] = lboff[3*ps*k+i]; 2270141cc406Sopenharmony_ci } 2271141cc406Sopenharmony_ci } 2272141cc406Sopenharmony_ci } 2273141cc406Sopenharmony_ci if (sanei_pieusb_buffer_put_full_color_line(&scanner->buffer, lboff, bpl/3) == 0) { 2274141cc406Sopenharmony_ci /* Error, return */ 2275141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2276141cc406Sopenharmony_ci } 2277141cc406Sopenharmony_ci lboff += bpl; 2278141cc406Sopenharmony_ci } 2279141cc406Sopenharmony_ci break; 2280141cc406Sopenharmony_ci case SCAN_COLOR_FORMAT_INDEX: 2281141cc406Sopenharmony_ci /* Indexed data */ 2282141cc406Sopenharmony_ci for (n = 0; n < lines; n++) { 2283141cc406Sopenharmony_ci if (sanei_pieusb_buffer_put_single_color_line(&scanner->buffer, *lboff, lboff+2, bpl-2) == 0) { 2284141cc406Sopenharmony_ci /* Error, return */ 2285141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2286141cc406Sopenharmony_ci } 2287141cc406Sopenharmony_ci lboff += bpl; 2288141cc406Sopenharmony_ci } 2289141cc406Sopenharmony_ci break; 2290141cc406Sopenharmony_ci default: 2291141cc406Sopenharmony_ci DBG(DBG_error, "sanei_pieusb_get_scan_data(): store color format %d not implemented\n", scanner->mode.colorFormat); 2292141cc406Sopenharmony_ci free(linebuf); 2293141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2294141cc406Sopenharmony_ci } 2295141cc406Sopenharmony_ci free(linebuf); 2296141cc406Sopenharmony_ci lines_remaining -= lines; /* Note: excess discarded */ 2297141cc406Sopenharmony_ci DBG(DBG_info_sane, "sanei_pieusb_get_scan_data(): reading lines: remaining %d\n", lines_remaining); 2298141cc406Sopenharmony_ci } 2299141cc406Sopenharmony_ci/* 2300141cc406Sopenharmony_ci if (fdraw != -1) close(fdraw); 2301141cc406Sopenharmony_ci*/ 2302141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2303141cc406Sopenharmony_ci} 2304141cc406Sopenharmony_ci 2305141cc406Sopenharmony_ci/** 2306141cc406Sopenharmony_ci * Wait for scanner to get ready 2307141cc406Sopenharmony_ci * 2308141cc406Sopenharmony_ci * loop of test_ready/read_state 2309141cc406Sopenharmony_ci * 2310141cc406Sopenharmony_ci * @param scanner 2311141cc406Sopenharmony_ci * @param device_number, used if scanner == NULL 2312141cc406Sopenharmony_ci * @return SANE_Status 2313141cc406Sopenharmony_ci */ 2314141cc406Sopenharmony_ci 2315141cc406Sopenharmony_ciSANE_Status 2316141cc406Sopenharmony_cisanei_pieusb_wait_ready(Pieusb_Scanner * scanner, SANE_Int device_number) 2317141cc406Sopenharmony_ci{ 2318141cc406Sopenharmony_ci struct Pieusb_Command_Status status; 2319141cc406Sopenharmony_ci struct Pieusb_Scanner_State state; 2320141cc406Sopenharmony_ci time_t start, elapsed; 2321141cc406Sopenharmony_ci 2322141cc406Sopenharmony_ci DBG (DBG_info_proc, "sanei_pieusb_wait_ready()\n"); 2323141cc406Sopenharmony_ci start = time(NULL); 2324141cc406Sopenharmony_ci if (scanner) 2325141cc406Sopenharmony_ci device_number = scanner->device_number; 2326141cc406Sopenharmony_ci 2327141cc406Sopenharmony_ci for(;;) { 2328141cc406Sopenharmony_ci sanei_pieusb_cmd_test_unit_ready(device_number, &status); 2329141cc406Sopenharmony_ci DBG (DBG_info_proc, "-> sanei_pieusb_cmd_test_unit_ready: %d\n", status.pieusb_status); 2330141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_GOOD) 2331141cc406Sopenharmony_ci break; 2332141cc406Sopenharmony_ci if (status.pieusb_status == PIEUSB_STATUS_IO_ERROR) 2333141cc406Sopenharmony_ci break; 2334141cc406Sopenharmony_ci sanei_pieusb_cmd_read_state(device_number, &state, &status); 2335141cc406Sopenharmony_ci DBG (DBG_info_proc, "-> sanei_pieusb_cmd_read_state: %d\n", status.pieusb_status); 2336141cc406Sopenharmony_ci if (status.pieusb_status != PIEUSB_STATUS_DEVICE_BUSY) 2337141cc406Sopenharmony_ci break; 2338141cc406Sopenharmony_ci sleep(2); 2339141cc406Sopenharmony_ci elapsed = time(NULL) - start; 2340141cc406Sopenharmony_ci if (elapsed > 120) { /* 2 minute overall timeout */ 2341141cc406Sopenharmony_ci DBG (DBG_error, "scanner not ready after 2 minutes\n"); 2342141cc406Sopenharmony_ci break; 2343141cc406Sopenharmony_ci } 2344141cc406Sopenharmony_ci if (elapsed % 2) { 2345141cc406Sopenharmony_ci DBG (DBG_info, "still waiting for scanner to get ready\n"); 2346141cc406Sopenharmony_ci } 2347141cc406Sopenharmony_ci } 2348141cc406Sopenharmony_ci return sanei_pieusb_convert_status(status.pieusb_status); 2349141cc406Sopenharmony_ci} 2350141cc406Sopenharmony_ci 2351141cc406Sopenharmony_ci 2352141cc406Sopenharmony_ciSANE_Status sanei_pieusb_analyze_preview(Pieusb_Scanner * scanner) 2353141cc406Sopenharmony_ci{ 2354141cc406Sopenharmony_ci int k, n; 2355141cc406Sopenharmony_ci SANE_Parameters params; 2356141cc406Sopenharmony_ci SANE_Int N; 2357141cc406Sopenharmony_ci double *norm_histo; 2358141cc406Sopenharmony_ci double level; 2359141cc406Sopenharmony_ci 2360141cc406Sopenharmony_ci DBG(DBG_info, "sanei_pieusb_analyze_preview(): saving preview data\n"); 2361141cc406Sopenharmony_ci 2362141cc406Sopenharmony_ci /* Settings */ 2363141cc406Sopenharmony_ci scanner->preview_done = SANE_TRUE; 2364141cc406Sopenharmony_ci for (k = 0; k < 4; k++) { 2365141cc406Sopenharmony_ci scanner->preview_exposure[k] = scanner->settings.exposureTime[k]; 2366141cc406Sopenharmony_ci scanner->preview_gain[k] = scanner->settings.gain[k]; 2367141cc406Sopenharmony_ci scanner->preview_offset[k] = scanner->settings.offset[k]; 2368141cc406Sopenharmony_ci } 2369141cc406Sopenharmony_ci /* Analyze color planes */ 2370141cc406Sopenharmony_ci N = scanner->buffer.width * scanner->buffer.height; 2371141cc406Sopenharmony_ci params.format = SANE_FRAME_GRAY; 2372141cc406Sopenharmony_ci params.depth = scanner->buffer.depth; 2373141cc406Sopenharmony_ci params.pixels_per_line = scanner->buffer.width; 2374141cc406Sopenharmony_ci params.lines = scanner->buffer.height; 2375141cc406Sopenharmony_ci for (k = 0; k < scanner->buffer.colors; k++) { 2376141cc406Sopenharmony_ci /* Create histogram for color k */ 2377141cc406Sopenharmony_ci sanei_ir_create_norm_histogram (¶ms, scanner->buffer.data + k * N, &norm_histo); 2378141cc406Sopenharmony_ci /* Find 1% and 99% limits */ 2379141cc406Sopenharmony_ci level = 0; 2380141cc406Sopenharmony_ci for (n =0; n < HISTOGRAM_SIZE; n++) { 2381141cc406Sopenharmony_ci 2382141cc406Sopenharmony_ci level += norm_histo[n]; 2383141cc406Sopenharmony_ci if (level < 0.01) { 2384141cc406Sopenharmony_ci scanner->preview_lower_bound[k] = n; 2385141cc406Sopenharmony_ci } 2386141cc406Sopenharmony_ci if (level < 0.99) { 2387141cc406Sopenharmony_ci scanner->preview_upper_bound[k] = n; 2388141cc406Sopenharmony_ci } 2389141cc406Sopenharmony_ci } 2390141cc406Sopenharmony_ci 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]); 2391141cc406Sopenharmony_ci } 2392141cc406Sopenharmony_ci /* Disable remaining color planes */ 2393141cc406Sopenharmony_ci for (k = scanner->buffer.colors; k < 4; k++) { 2394141cc406Sopenharmony_ci scanner->preview_lower_bound[k] = 0; 2395141cc406Sopenharmony_ci scanner->preview_upper_bound[k] = 0; 2396141cc406Sopenharmony_ci } 2397141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2398141cc406Sopenharmony_ci} 2399141cc406Sopenharmony_ci 2400141cc406Sopenharmony_ci 2401141cc406Sopenharmony_ci/** 2402141cc406Sopenharmony_ci * Return actual gain at given gain setting 2403141cc406Sopenharmony_ci * 2404141cc406Sopenharmony_ci * @param gain Gain setting (0 - 63) 2405141cc406Sopenharmony_ci * @return 2406141cc406Sopenharmony_ci */ 2407141cc406Sopenharmony_cistatic double getGain(int gain) 2408141cc406Sopenharmony_ci{ 2409141cc406Sopenharmony_ci int k; 2410141cc406Sopenharmony_ci 2411141cc406Sopenharmony_ci /* Actually an error, but don't be picky */ 2412141cc406Sopenharmony_ci if (gain <= 0) { 2413141cc406Sopenharmony_ci return gains[0]; 2414141cc406Sopenharmony_ci } 2415141cc406Sopenharmony_ci /* A gain > 63 is also an error, but don't be picky */ 2416141cc406Sopenharmony_ci if (gain >= 60) { 2417141cc406Sopenharmony_ci return (gain-55)*(gains[12]-gains[11])/5 + gains[11]; 2418141cc406Sopenharmony_ci } 2419141cc406Sopenharmony_ci /* Interpolate other values */ 2420141cc406Sopenharmony_ci k = gain/5; /* index of array value just below given gain */ 2421141cc406Sopenharmony_ci return (gain-5*k)*(gains[k+1]-gains[k])/5 + gains[k]; 2422141cc406Sopenharmony_ci} 2423141cc406Sopenharmony_ci 2424141cc406Sopenharmony_cistatic int getGainSetting(double gain) 2425141cc406Sopenharmony_ci{ 2426141cc406Sopenharmony_ci int k, m; 2427141cc406Sopenharmony_ci 2428141cc406Sopenharmony_ci /* Out of bounds */ 2429141cc406Sopenharmony_ci if (gain < 1.0) { 2430141cc406Sopenharmony_ci return 0; 2431141cc406Sopenharmony_ci } 2432141cc406Sopenharmony_ci if (gain >= gains[12]) { 2433141cc406Sopenharmony_ci m = 60 + lround((gain-gains[11])/(gains[12]-gains[11])*5); 2434141cc406Sopenharmony_ci if (m > 63) m = 63; 2435141cc406Sopenharmony_ci return m; 2436141cc406Sopenharmony_ci } 2437141cc406Sopenharmony_ci /* Interpolate the rest */ 2438141cc406Sopenharmony_ci m = 0; 2439141cc406Sopenharmony_ci for (k = 0; k <= 11; k++) { 2440141cc406Sopenharmony_ci if (gains[k] <= gain && gain < gains[k+1]) { 2441141cc406Sopenharmony_ci m = 5*k + lround((gain-gains[k])/(gains[k+1]-gains[k])*5); 2442141cc406Sopenharmony_ci } 2443141cc406Sopenharmony_ci } 2444141cc406Sopenharmony_ci return m; 2445141cc406Sopenharmony_ci} 2446141cc406Sopenharmony_ci 2447141cc406Sopenharmony_ci/** 2448141cc406Sopenharmony_ci * Modify gain and exposure times in order to make maximal use of the scan depth. 2449141cc406Sopenharmony_ci * Each color treated separately, infrared excluded. 2450141cc406Sopenharmony_ci * 2451141cc406Sopenharmony_ci * This may be too aggressive => leads to a noisy whitish border instead of the orange. 2452141cc406Sopenharmony_ci * In a couuple of tries, gain was set to values of 60 and above, which introduces 2453141cc406Sopenharmony_ci * the noise? 2454141cc406Sopenharmony_ci * The whitish border is logical since the brightest parts of the negative, the 2455141cc406Sopenharmony_ci * unexposed borders, are amplified to values near CCD saturation, which is white. 2456141cc406Sopenharmony_ci * Maybe a uniform gain increase for each color is more appropriate? Somewhere 2457141cc406Sopenharmony_ci * between 2.5 and 3 seems worthwhile trying, see updateGain2(). 2458141cc406Sopenharmony_ci * 2459141cc406Sopenharmony_ci switch (scanner->mode.passes) { 2460141cc406Sopenharmony_ci case SCAN_ONE_PASS_RGBI: 2461141cc406Sopenharmony_ci updateGain(scanner,0); 2462141cc406Sopenharmony_ci updateGain(scanner,1); 2463141cc406Sopenharmony_ci updateGain(scanner,2); 2464141cc406Sopenharmony_ci updateGain(scanner,3); 2465141cc406Sopenharmony_ci break; 2466141cc406Sopenharmony_ci case SCAN_ONE_PASS_COLOR: 2467141cc406Sopenharmony_ci updateGain(scanner,0); 2468141cc406Sopenharmony_ci updateGain(scanner,1); 2469141cc406Sopenharmony_ci updateGain(scanner,2); 2470141cc406Sopenharmony_ci break; 2471141cc406Sopenharmony_ci case SCAN_FILTER_INFRARED: 2472141cc406Sopenharmony_ci updateGain(scanner,3); 2473141cc406Sopenharmony_ci break; 2474141cc406Sopenharmony_ci case SCAN_FILTER_BLUE: 2475141cc406Sopenharmony_ci updateGain(scanner,2); 2476141cc406Sopenharmony_ci break; 2477141cc406Sopenharmony_ci case SCAN_FILTER_GREEN: 2478141cc406Sopenharmony_ci updateGain(scanner,1); 2479141cc406Sopenharmony_ci break; 2480141cc406Sopenharmony_ci case SCAN_FILTER_RED: 2481141cc406Sopenharmony_ci updateGain(scanner,0); 2482141cc406Sopenharmony_ci break; 2483141cc406Sopenharmony_ci case SCAN_FILTER_NEUTRAL: 2484141cc406Sopenharmony_ci break; 2485141cc406Sopenharmony_ci } 2486141cc406Sopenharmony_ci * @param scanner 2487141cc406Sopenharmony_ci */ 2488141cc406Sopenharmony_ci/* 2489141cc406Sopenharmony_cistatic void updateGain(Pieusb_Scanner *scanner, int color_index) 2490141cc406Sopenharmony_ci{ 2491141cc406Sopenharmony_ci double g, dg; 2492141cc406Sopenharmony_ci 2493141cc406Sopenharmony_ci 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]); 2494141cc406Sopenharmony_ci // Additional gain to obtain 2495141cc406Sopenharmony_ci dg = ((double)scanner->settings.saturationLevel[color_index] / 65536) / ((double)scanner->preview_upper_bound[color_index] / HISTOGRAM_SIZE); 2496141cc406Sopenharmony_ci DBG(DBG_info_sane,"updateGain(): additional gain %f\n", dg); 2497141cc406Sopenharmony_ci // Achieve this by modifying gain and exposure 2498141cc406Sopenharmony_ci // Gain used for preview 2499141cc406Sopenharmony_ci g = getGain(scanner->preview_gain[color_index]); 2500141cc406Sopenharmony_ci DBG(DBG_info_sane,"updateGain(): preview had gain %d => %f\n",scanner->preview_gain[color_index],g); 2501141cc406Sopenharmony_ci // Look up new gain setting g*sqrt(dg) 2502141cc406Sopenharmony_ci DBG(DBG_info_sane,"updateGain(): optimized gain * %f = %f\n",sqrt(dg),sqrt(dg)*g); 2503141cc406Sopenharmony_ci scanner->settings.gain[color_index] = getGainSetting(g*sqrt(dg)); 2504141cc406Sopenharmony_ci DBG(DBG_info_sane,"updateGain(): optimized gain setting %d => %f\n",scanner->settings.gain[color_index],getGain(scanner->settings.gain[color_index])); 2505141cc406Sopenharmony_ci // Exposure change is straightforward 2506141cc406Sopenharmony_ci DBG(DBG_info_sane,"updateGain(): remains for exposure %f\n",dg/(getGain(scanner->settings.gain[color_index])/g)); 2507141cc406Sopenharmony_ci scanner->settings.exposureTime[color_index] = lround( g / getGain(scanner->settings.gain[color_index]) * dg * scanner->preview_exposure[color_index] ); 2508141cc406Sopenharmony_ci DBG(DBG_info_sane,"updateGain(): new setting G=%d Exp=%d\n", scanner->settings.gain[color_index], scanner->settings.exposureTime[color_index]); 2509141cc406Sopenharmony_ci} 2510141cc406Sopenharmony_ci*/ 2511141cc406Sopenharmony_ci 2512141cc406Sopenharmony_cistatic void updateGain2(Pieusb_Scanner *scanner, int color_index, double gain_increase) 2513141cc406Sopenharmony_ci{ 2514141cc406Sopenharmony_ci double g; 2515141cc406Sopenharmony_ci 2516141cc406Sopenharmony_ci 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]); 2517141cc406Sopenharmony_ci /* Additional gain to obtain */ 2518141cc406Sopenharmony_ci DBG(DBG_info,"updateGain2(): additional gain %f\n", gain_increase); 2519141cc406Sopenharmony_ci /* Achieve this by modifying gain and exposure */ 2520141cc406Sopenharmony_ci /* Gain used for preview */ 2521141cc406Sopenharmony_ci g = getGain(scanner->settings.gain[color_index]); 2522141cc406Sopenharmony_ci DBG(DBG_info,"updateGain2(): preview had gain %d => %f\n", scanner->settings.gain[color_index], g); 2523141cc406Sopenharmony_ci /* Look up new gain setting g*sqrt(dg) */ 2524141cc406Sopenharmony_ci DBG(DBG_info,"updateGain2(): optimized gain * %f = %f\n", sqrt(gain_increase), sqrt(gain_increase) * g); 2525141cc406Sopenharmony_ci scanner->settings.gain[color_index] = getGainSetting(g * sqrt(gain_increase)); 2526141cc406Sopenharmony_ci DBG(DBG_info,"updateGain2(): optimized gain setting %d => %f\n", scanner->settings.gain[color_index], getGain(scanner->settings.gain[color_index])); 2527141cc406Sopenharmony_ci /* Exposure change is straightforward */ 2528141cc406Sopenharmony_ci DBG(DBG_info,"updateGain2(): remains for exposure %f\n", gain_increase / (getGain(scanner->settings.gain[color_index]) / g)); 2529141cc406Sopenharmony_ci scanner->settings.exposureTime[color_index] = lround( g / getGain(scanner->settings.gain[color_index]) * gain_increase * scanner->settings.exposureTime[color_index] ); 2530141cc406Sopenharmony_ci DBG(DBG_info,"updateGain2(): new setting G=%d Exp=%d\n", scanner->settings.gain[color_index], scanner->settings.exposureTime[color_index]); 2531141cc406Sopenharmony_ci} 2532