kopia lustrzana https://gitlab.com/sane-project/backends
1938 wiersze
61 KiB
C
1938 wiersze
61 KiB
C
/* sane - Scanner Access Now Easy.
|
|
Copyright (C) 1997 BYTEC GmbH Germany
|
|
Written by Helmut Koeberle, Email: helmut.koeberle@bytec.de
|
|
Modified by Manuel Panea <Manuel.Panea@rzg.mpg.de>
|
|
and Markus Mertinat <Markus.Mertinat@Physik.Uni-Augsburg.DE>
|
|
|
|
This file is part of the SANE package.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
to produce an executable, this does not by itself cause the
|
|
resulting executable to be covered by the GNU General Public
|
|
License. Your use of that executable is in no way restricted on
|
|
account of linking the SANE library code into it.
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
the executable file might be covered by the GNU General Public
|
|
License.
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
a subsequent release, you agree by submitting the changes that
|
|
those changes may be distributed with this exception intact.
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
whether to permit this exception to apply to your modifications.
|
|
If you do not wish that, delete this exception notice. */
|
|
|
|
/* This file implements the sane-api */
|
|
|
|
/* SANE-FLOW-DIAGRAMM
|
|
|
|
- sane_init() : initialize backend, attach scanners(devicename,0)
|
|
. - sane_get_devices() : query list of scanner-devices
|
|
. - sane_open() : open a particular scanner-device and attach_scanner(devicename,&dev)
|
|
. . - sane_set_io_mode : set blocking-mode
|
|
. . - sane_get_select_fd : get scanner-fd
|
|
. . - sane_get_option_descriptor() : get option informations
|
|
. . - sane_control_option() : change option values
|
|
. .
|
|
. . - sane_start() : start image aquisition
|
|
. . - sane_get_parameters() : returns actual scan-parameters
|
|
. . - sane_read() : read image-data (from pipe)
|
|
. . - sane_cancel() : cancel operation, kill reader_process
|
|
|
|
. - sane_close() : close opened scanner-device, do_cancel, free buffer and handle
|
|
- sane_exit() : terminate use of backend, free devicename and device-struture
|
|
*/
|
|
|
|
/* This driver's flow:
|
|
|
|
- sane_init
|
|
. - attach_one
|
|
. . - inquiry
|
|
. . - test_unit_ready
|
|
. . - medium_position
|
|
. . - extended inquiry
|
|
. . - mode sense
|
|
. . - get_density_curve
|
|
- sane_get_devices
|
|
- sane_open
|
|
. - init_options
|
|
- sane_set_io_mode : set blocking-mode
|
|
- sane_get_select_fd : get scanner-fd
|
|
- sane_get_option_descriptor() : get option informations
|
|
- sane_control_option() : change option values
|
|
- sane_start() : start image aquisition
|
|
- sane_get_parameters() : returns actual scan-parameters
|
|
- sane_read() : read image-data (from pipe)
|
|
- sane_cancel() : cancel operation, kill reader_process
|
|
- sane_close() : close opened scanner-device, do_cancel, free buffer and handle
|
|
- sane_exit() : terminate use of backend, free devicename and device-struture
|
|
*/
|
|
|
|
#include "sane/config.h"
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "sane/sane.h"
|
|
#include "sane/saneopts.h"
|
|
#include "sane/sanei_scsi.h"
|
|
#include "canon.h"
|
|
|
|
#define BACKEND_NAME canon
|
|
#include "sane/sanei_backend.h"
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
|
|
#include "sane/sanei_config.h"
|
|
#define CANON_CONFIG_FILE "canon.conf"
|
|
|
|
#define MM_PER_INCH 25.4
|
|
|
|
static int num_devices = 0;
|
|
static CANON_Device *first_dev = NULL;
|
|
static CANON_Scanner *first_handle = NULL;
|
|
|
|
static const SANE_String_Const mode_list[] =
|
|
{
|
|
"Lineart", "Halftone", "Gray", "Color",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const tpu_dc_mode_list[] =
|
|
{
|
|
"No transparency correction",
|
|
"Correction according to Film type",
|
|
"Correction according to Transparency Ratio",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const page_list[] =
|
|
{
|
|
"Show normal options",
|
|
"Show advanced options",
|
|
"Show all options",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const filmtype_list[] =
|
|
{
|
|
"Negatives",
|
|
"Slides",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const negative_filmtype_list[] =
|
|
{
|
|
"Film type 0", "Film type 1", "Film type 2", "Film type 3",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const scanning_speed_list[] =
|
|
{
|
|
"Automatic", "Normal speed", "1/2 normal speed", "1/3 normal speed",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const tpu_filmtype_list[] =
|
|
{
|
|
"Film 0", "Film 1", "Film 2", "Film 3",
|
|
0
|
|
};
|
|
|
|
static const SANE_String_Const papersize_list[] =
|
|
{
|
|
"A4", "Letter", "B5", "Maximal",
|
|
0
|
|
};
|
|
|
|
static const SANE_Range u8_range =
|
|
{
|
|
0, /* minimum */
|
|
255, /* maximum */
|
|
0 /* quantization */
|
|
};
|
|
|
|
|
|
#include "canon-scsi.c"
|
|
|
|
/**************************************************************************/
|
|
|
|
static size_t
|
|
max_string_size (const SANE_String_Const strings[])
|
|
{
|
|
size_t size, max_size = 0;
|
|
int i;
|
|
DBG (11, ">> max_string_size\n");
|
|
|
|
for (i = 0; strings[i]; ++i)
|
|
{
|
|
size = strlen (strings[i]) + 1;
|
|
if (size > max_size)
|
|
max_size = size;
|
|
}
|
|
|
|
DBG (11, "<< max_string_size\n");
|
|
return max_size;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static void
|
|
get_tpu_stat(int fd, CANON_Device *dev)
|
|
{
|
|
unsigned char tbuf[12+5];
|
|
size_t buf_size;
|
|
SANE_Status status;
|
|
int i;
|
|
|
|
DBG (3, ">> get tpu stat\n");
|
|
|
|
/* Check wether it is a CS-600 at all */
|
|
if (strncmp(dev->sane.model, "IX-06015", 8))
|
|
{
|
|
dev->tpu.Status = TPU_STAT_NONE;
|
|
return;
|
|
}
|
|
|
|
memset (tbuf, 0, sizeof (tbuf));
|
|
buf_size = sizeof (tbuf);
|
|
status = get_scan_mode (fd, TRANSPARENCY_UNIT, tbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "get scan mode failed: %s\n", sane_strstatus (status));
|
|
return;
|
|
}
|
|
|
|
for (i=0; i<buf_size; i++)
|
|
{
|
|
DBG(3, "scan mode control byte[%d] = %d\n", i, tbuf[i]);
|
|
}
|
|
dev->tpu.Status = ( tbuf[2 + 4 + 5] >> 7 ) ?
|
|
TPU_STAT_INACTIVE : TPU_STAT_NONE;
|
|
if ( dev->tpu.Status == SANE_TRUE ) /* TPU available */
|
|
{
|
|
dev->tpu.Status = ( tbuf[2 + 4 + 5] && 0x04 ) ?
|
|
TPU_STAT_INACTIVE : TPU_STAT_ACTIVE;
|
|
}
|
|
dev->tpu.ControlMode = tbuf[3 + 4 + 5] && 0x03;
|
|
dev->tpu.Transparency = tbuf[4 + 4 + 5] * 256 + tbuf[5 + 4 + 5];
|
|
dev->tpu.PosNeg = tbuf[6 + 4 + 5] && 0x01;
|
|
dev->tpu.FilmType = tbuf[7 + 4 + 5];
|
|
|
|
DBG(11,"TPU Status: %d\n", dev->tpu.Status);
|
|
DBG(11,"TPU ControlMode: %d\n", dev->tpu.ControlMode);
|
|
DBG(11,"TPU Transparency: %d\n", dev->tpu.Transparency);
|
|
DBG(11,"TPU PosNeg: %d\n", dev->tpu.PosNeg);
|
|
DBG(11,"TPU FilmType: %d\n", dev->tpu.FilmType);
|
|
|
|
DBG (3, "<< get tpu stat\n");
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static void
|
|
get_adf_stat(int fd, CANON_Device *dev)
|
|
{
|
|
unsigned char abuf[0x0C];
|
|
size_t buf_size = sizeof(abuf);
|
|
SANE_Status status;
|
|
int i;
|
|
|
|
DBG(3, ">> get adf stat\n");
|
|
|
|
if ( strncmp(dev->sane.model, FB620S, 9) == 0 )
|
|
{
|
|
dev->adf.Status = ADF_STAT_NONE;
|
|
return;
|
|
}
|
|
|
|
memset (abuf, 0, buf_size);
|
|
status = get_scan_mode (fd, AUTO_DOC_FEEDER_UNIT, abuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "get scan mode failed: %s\n", sane_strstatus (status));
|
|
perror("get scan mode failed");
|
|
return;
|
|
}
|
|
|
|
for (i=0; i<buf_size; i++)
|
|
{
|
|
DBG(3, "scan mode control byte[%d] = %d\n", i, abuf[i]);
|
|
/* printf("scan mode control byte[%d] = %d\n", i, abuf[i]); */
|
|
}
|
|
|
|
dev->adf.Status = ( abuf[ADF_Status] & ADF_NOT_PRESENT) ?
|
|
ADF_STAT_NONE : ADF_STAT_INACTIVE;
|
|
|
|
if ( dev->adf.Status == SANE_TRUE ) /* ADF available / INACTIVE */
|
|
{
|
|
dev->adf.Status = ( abuf[ADF_Status] & ADF_PROBLEM) ?
|
|
ADF_STAT_INACTIVE : ADF_STAT_ACTIVE;
|
|
}
|
|
dev->adf.Problem = (abuf[ADF_Status] & ADF_PROBLEM);
|
|
dev->adf.Priority = (abuf[ADF_Settings] & ADF_PRIORITY);
|
|
dev->adf.Feeder = (abuf[ADF_Settings] & ADF_FEEDER);
|
|
|
|
/*#ifndef NDEBUG
|
|
printf("ADF Status: %d\n", dev->adf.Status);
|
|
printf("ADF Priority: %d\n", dev->adf.Priority);
|
|
printf("ADF Problem: %d\n", dev->adf.Problem);
|
|
printf("ADF Feeder: %d\n", dev->adf.Feeder);
|
|
# else */
|
|
DBG(11, "ADF Status: %d\n", dev->adf.Status);
|
|
DBG(11, "ADF Priority: %d\n", dev->adf.Priority);
|
|
DBG(11, "ADF Problem: %d\n", dev->adf.Problem);
|
|
DBG(11, "ADF Feeder: %d\n", dev->adf.Feeder);
|
|
|
|
DBG(3, "<< get adf stat\n");
|
|
/* # endif */
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
sense_handler (int scsi_fd, u_char * result, void *arg)
|
|
{
|
|
static char me[] = "canon_sense_handler";
|
|
CANON_Scanner *s = (CANON_Scanner *) arg;
|
|
u_char sense;
|
|
char *sense_str = NULL;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
DBG (1, ">> sense_handler\n");
|
|
|
|
DBG (11, "%s(%ld, %p, %p)\n", me, (long) scsi_fd,
|
|
(void *) result, (void *) arg);
|
|
|
|
sense = result[0];
|
|
|
|
switch (sense)
|
|
{
|
|
case 0x00: /* Good */
|
|
sense_str = "Good. Command has executed normally";
|
|
break;
|
|
case 0x02: /* Check Condition */
|
|
sense_str = "Check Condition";
|
|
break;
|
|
case 0x08: /* Busy */
|
|
sense_str = "Scanner is busy";
|
|
break;
|
|
case 0x18: /* Reservation Conflict */
|
|
sense_str = "The scanner is reserved by another SCSI device";
|
|
break;
|
|
default:
|
|
DBG (5, "%s: no handling for sense %x.\n", me, sense);
|
|
break;
|
|
}
|
|
|
|
if (s)
|
|
{
|
|
s->sense_str = sense_str;
|
|
}
|
|
DBG (1, "<< sense_handler\n");
|
|
return status;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
do_gamma(CANON_Scanner *s)
|
|
{
|
|
SANE_Status status;
|
|
u_char gbuf[256];
|
|
size_t buf_size;
|
|
int i, j, neg;
|
|
|
|
|
|
DBG (7, "sending SET_DENSITY_CURVE\n");
|
|
buf_size = 256 * sizeof (u_char);
|
|
neg = (s->hw->info.model == CS2700) ?
|
|
s->val[OPT_NEGATIVE].w :
|
|
s->val[OPT_HNEGATIVE].w;
|
|
|
|
if (!strcmp(s->val[OPT_MODE].s, "Gray"))
|
|
{
|
|
/* If scanning in gray mode, use the first curve for the
|
|
scanner's monochrome gamma component */
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
if(neg == SANE_FALSE)
|
|
{
|
|
gbuf[j] = (u_char)(255.0/256.0 * s->gamma_table[0][j]);
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", 0, j, gbuf[j]);
|
|
}
|
|
else
|
|
{
|
|
gbuf[255-j] = (u_char)(255-255.0/256.0*s->gamma_table[0][j]);
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", 0, 255-j, gbuf[255-j]);
|
|
}
|
|
}
|
|
|
|
status = set_density_curve (s->fd, 0, gbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (7, "SET_DENSITY_CURVE\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
}
|
|
else if (s->val[OPT_CUSTOM_GAMMA_BIND].w == SANE_TRUE)
|
|
{
|
|
/* If in RGB mode but with gamma bind, use the first curve
|
|
for all 3 colors red, green, blue */
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
if(neg == SANE_FALSE)
|
|
{
|
|
gbuf[j] = (u_char)(255.0/256.0 * s->gamma_table[0][j]);
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, j, gbuf[j]);
|
|
}
|
|
else
|
|
{
|
|
gbuf[255-j] = (u_char)(255 - 255.0/256.0 * s->gamma_table[0][j]);
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, 255-j, gbuf[255-j]);
|
|
}
|
|
}
|
|
|
|
status = set_density_curve (s->fd, i, gbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (7, "SET_DENSITY_CURVE\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* If in RGB mode without gamma bind, use the 3 curves for RGB */
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
if(neg == SANE_FALSE)
|
|
{
|
|
gbuf[j] = (u_char)(255.0/256.0 * s->gamma_table[i][j]);
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, j, gbuf[j]);
|
|
}
|
|
else
|
|
{
|
|
gbuf[255-j] = (u_char)(255 - 255.0/256.0 * s->gamma_table[i][j]);
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, 255-j, gbuf[255-j]);
|
|
}
|
|
}
|
|
|
|
status = set_density_curve (s->fd, i, gbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (7, "SET_DENSITY_CURVE\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
attach (const char *devnam, CANON_Device ** devp)
|
|
{
|
|
SANE_Status status;
|
|
CANON_Device *dev;
|
|
|
|
int fd;
|
|
u_char ibuf[36], ebuf[74], mbuf[12];
|
|
size_t buf_size;
|
|
char *str;
|
|
int i;
|
|
|
|
DBG (1, ">> attach\n");
|
|
|
|
for (dev = first_dev; dev; dev = dev->next)
|
|
{
|
|
if (strcmp (dev->sane.name, devnam) == 0)
|
|
{
|
|
if (devp)
|
|
*devp = dev;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
}
|
|
|
|
DBG (3, "attach: opening %s\n", devnam);
|
|
status = sanei_scsi_open (devnam, &fd, sense_handler, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
|
|
return (status);
|
|
}
|
|
|
|
DBG (3, "attach: sending (standard) INQUIRY\n");
|
|
memset (ibuf, 0, sizeof (ibuf));
|
|
buf_size = sizeof (ibuf);
|
|
status = inquiry (fd, 0, ibuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status));
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (status);
|
|
}
|
|
|
|
if (ibuf[0] != 6
|
|
|| strncmp (ibuf + 8, "CANON", 5) != 0
|
|
|| strncmp (ibuf + 16, "IX-", 3) != 0)
|
|
{
|
|
DBG (1, "attach: device doesn't look like a Canon scanner\n");
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
DBG (3, "attach: sending TEST_UNIT_READY\n");
|
|
status = test_unit_ready (fd);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: test unit ready failed (%s)\n",
|
|
sane_strstatus (status));
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (status);
|
|
}
|
|
|
|
#if 0
|
|
DBG (3, "attach: sending REQUEST SENSE\n");
|
|
memset (sbuf, 0, sizeof (sbuf));
|
|
buf_size = sizeof (sbuf);
|
|
status = request_sense (fd, sbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: REQUEST_SENSE failed\n");
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
DBG (3, "attach: sending MEDIUM POSITION\n");
|
|
status = medium_position (fd);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: MEDIUM POSTITION failed\n");
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
/* s->val[OPT_AF_NOW].w == SANE_TRUE; */
|
|
#endif
|
|
|
|
DBG (3, "attach: sending RESERVE UNIT\n");
|
|
status = reserve_unit(fd);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: RESERVE UNIT failed\n");
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
/* DBG (3, "attach: sending GET SCAN MODE for transparency unit\n"); */
|
|
/* memset (ebuf, 0, sizeof (ebuf)); */
|
|
/* buf_size = sizeof (ebuf); */
|
|
/* buf_size = 12; */
|
|
/* status = get_scan_mode (fd, TRANSPARENCY_UNIT, ebuf, &buf_size); */
|
|
/* if (status != SANE_STATUS_GOOD) */
|
|
/* { */
|
|
/* DBG (1, "attach: GET SCAN MODE for transparency unit failed\n"); */
|
|
/* sanei_scsi_close (fd); */
|
|
/* return (SANE_STATUS_INVAL); */
|
|
/* } */
|
|
/* for (i=0; i<buf_size; i++) */
|
|
/* { */
|
|
/* DBG(3, "scan mode trans byte[%d] = %d\n", i, ebuf[i]); */
|
|
/* } */
|
|
|
|
DBG (3, "attach: sending GET SCAN MODE for scan control conditions\n");
|
|
memset (ebuf, 0, sizeof (ebuf));
|
|
buf_size = sizeof (ebuf);
|
|
status = get_scan_mode (fd, SCAN_CONTROL_CONDITIONS, ebuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n");
|
|
sanei_scsi_close (fd);
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
for (i=0; i<buf_size; i++)
|
|
{
|
|
DBG(3, "scan mode byte[%d] = %d\n", i, ebuf[i]);
|
|
}
|
|
|
|
DBG (3, "attach: sending (extended) INQUIRY\n");
|
|
memset (ebuf, 0, sizeof (ebuf));
|
|
buf_size = sizeof (ebuf);
|
|
status = inquiry (fd, 1, ebuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: (extended) INQUIRY failed\n");
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
#if 0
|
|
DBG (3, "attach: sending GET SCAN MODE for transparency unit\n");
|
|
|
|
|
|
memset (ebuf, 0, sizeof (ebuf));
|
|
buf_size = 64;
|
|
status = get_scan_mode (fd, ALL_SCAN_MODE_PAGES,/* TRANSPARENCY_UNIT,*/
|
|
ebuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n");
|
|
sanei_scsi_close (fd);
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
for (i=0; i<buf_size; i++)
|
|
{
|
|
DBG(3, "scan mode control byte[%d] = %d\n", i, ebuf[i]);
|
|
}
|
|
#endif
|
|
|
|
/* DBG (3, "attach: sending GET SCAN MODE for all scan mode pages\n"); */
|
|
/* memset (ebuf, 0, sizeof (ebuf)); */
|
|
/* buf_size = 32; */
|
|
/* status = get_scan_mode (fd, (u_char)ALL_SCAN_MODE_PAGES, */
|
|
/* ebuf, &buf_size); */
|
|
/* if (status != SANE_STATUS_GOOD) */
|
|
/* { */
|
|
/* DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n"); */
|
|
/* sanei_scsi_close (fd); */
|
|
/* return (SANE_STATUS_INVAL); */
|
|
/* } */
|
|
/* for (i=0; i<buf_size; i++) */
|
|
/* { */
|
|
/* DBG(3, "scan mode control byte[%d] = %d\n", i, ebuf[i]); */
|
|
/* } */
|
|
|
|
|
|
DBG (3, "attach: sending MODE SENSE\n");
|
|
memset (mbuf, 0, sizeof (mbuf));
|
|
buf_size = sizeof (mbuf);
|
|
status = mode_sense (fd, mbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: MODE_SENSE failed\n");
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
dev = malloc (sizeof (*dev));
|
|
if (!dev)
|
|
{
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
return (SANE_STATUS_NO_MEM);
|
|
}
|
|
memset (dev, 0, sizeof (*dev));
|
|
|
|
dev->sane.name = strdup (devnam);
|
|
dev->sane.vendor = "CANON";
|
|
str = malloc (16 + 1);
|
|
memset (str, 0, sizeof (str));
|
|
strncpy (str, ibuf + 16, 16);
|
|
dev->sane.model = str;
|
|
/* if (!strncmp(str, "IX-27015", 5)) */
|
|
if (strncmp(str, "IX-27015", 8) == 0)
|
|
{
|
|
dev->info.model = CS2700;
|
|
dev->sane.type = "film scanner";
|
|
}
|
|
else
|
|
{
|
|
dev->info.model = CS3_600;
|
|
dev->sane.type = "flatbed scanner";
|
|
}
|
|
|
|
|
|
DBG (5, "dev->sane.name = '%s'\n", dev->sane.name);
|
|
DBG (5, "dev->sane.vendor = '%s'\n", dev->sane.vendor);
|
|
DBG (5, "dev->sane.model = '%s'\n", dev->sane.model);
|
|
DBG (5, "dev->sane.type = '%s'\n", dev->sane.type);
|
|
|
|
get_tpu_stat(fd, dev); /* Query TPU */
|
|
get_adf_stat(fd, dev); /* Query ADF */
|
|
|
|
dev->info.bmu = mbuf[6];
|
|
DBG (5, "bmu=%d\n", dev->info.bmu);
|
|
dev->info.mud = (mbuf[8] * 256) + mbuf[9];
|
|
DBG (5, "mud=%d\n", dev->info.mud);
|
|
|
|
dev->info.xres_default = (ebuf[5] * 256) + ebuf[6];
|
|
DBG (5, "xres_default=%d\n", dev->info.xres_default);
|
|
dev->info.xres_range.max = (ebuf[10] * 256) + ebuf[11];
|
|
DBG (5, "xres_range.max=%d\n", dev->info.xres_range.max);
|
|
dev->info.xres_range.min = (ebuf[14] * 256) + ebuf[15];
|
|
DBG (5, "xres_range.min=%d\n", dev->info.xres_range.min);
|
|
dev->info.xres_range.quant = ebuf[9] >> 4;
|
|
DBG (5, "xres_range.quant=%d\n", dev->info.xres_range.quant);
|
|
|
|
dev->info.yres_default = (ebuf[7] * 256) + ebuf[8];
|
|
DBG (5, "yres_default=%d\n", dev->info.yres_default);
|
|
dev->info.yres_range.max = (ebuf[12] * 256) + ebuf[13];
|
|
DBG (5, "yres_range.max=%d\n", dev->info.yres_range.max);
|
|
dev->info.yres_range.min = (ebuf[16] * 256) + ebuf[17];
|
|
DBG (5, "yres_range.min=%d\n", dev->info.yres_range.min);
|
|
dev->info.yres_range.quant = ebuf[9] & 0x0f;
|
|
DBG (5, "xres_range.quant=%d\n", dev->info.xres_range.quant);
|
|
|
|
dev->info.x_range.min = SANE_FIX(0.0);
|
|
dev->info.x_range.max = (ebuf[20] * 256 * 256 * 256)
|
|
+ (ebuf[21] * 256 * 256) + (ebuf[22] * 256) + ebuf[23] - 1;
|
|
dev->info.x_range.max = SANE_FIX(dev->info.x_range.max * MM_PER_INCH / dev->info.mud);
|
|
DBG (5, "x_range.max=%d\n", dev->info.x_range.max);
|
|
dev->info.x_range.quant = 0;
|
|
|
|
dev->info.y_range.min = SANE_FIX(0.0);
|
|
dev->info.y_range.max = (ebuf[24] * 256 * 256 * 256)
|
|
+ (ebuf[25] * 256 * 256) + (ebuf[26] * 256) + ebuf[27] - 1;
|
|
dev->info.y_range.max = SANE_FIX(dev->info.y_range.max * MM_PER_INCH / dev->info.mud);
|
|
DBG (5, "y_range.max=%d\n", dev->info.y_range.max);
|
|
dev->info.y_range.quant = 0;
|
|
|
|
dev->info.x_adf_range.max = (ebuf[30] * 256 * 256 * 256)
|
|
+ (ebuf[31] * 256 * 256) + (ebuf[32] * 256) + ebuf[33] - 1;
|
|
DBG (5, "x_adf_range.max=%d\n", dev->info.x_adf_range.max);
|
|
dev->info.y_adf_range.max = (ebuf[34] * 256 * 256 * 256)
|
|
+ (ebuf[35] * 256 * 256) + (ebuf[36] * 256) + ebuf[37] - 1;
|
|
DBG (5, "y_adf_range.max=%d\n", dev->info.y_adf_range.max);
|
|
|
|
|
|
dev->info.brightness_range.min = 1;
|
|
dev->info.brightness_range.max = 255;
|
|
dev->info.brightness_range.quant = 0;
|
|
|
|
dev->info.contrast_range.min = 1;
|
|
dev->info.contrast_range.max = 255;
|
|
dev->info.contrast_range.quant = 0;
|
|
|
|
dev->info.threshold_range.min = 1;
|
|
dev->info.threshold_range.max = 255;
|
|
dev->info.threshold_range.quant = 0;
|
|
|
|
dev->info.HiliteR_range.min = 0;
|
|
dev->info.HiliteR_range.max = 255;
|
|
dev->info.HiliteR_range.quant = 0;
|
|
|
|
dev->info.ShadowR_range.min = 0;
|
|
dev->info.ShadowR_range.max = 254;
|
|
dev->info.ShadowR_range.quant = 0;
|
|
|
|
dev->info.HiliteG_range.min = 1;
|
|
dev->info.HiliteG_range.max = 255;
|
|
dev->info.HiliteG_range.quant = 0;
|
|
|
|
dev->info.ShadowG_range.min = 0;
|
|
dev->info.ShadowG_range.max = 254;
|
|
dev->info.ShadowG_range.quant = 0;
|
|
|
|
dev->info.HiliteB_range.min = 0;
|
|
dev->info.HiliteB_range.max = 255;
|
|
dev->info.HiliteB_range.quant = 0;
|
|
|
|
dev->info.ShadowB_range.min = 0;
|
|
dev->info.ShadowB_range.max = 254;
|
|
dev->info.ShadowB_range.quant = 0;
|
|
|
|
dev->info.focus_range.min = 0;
|
|
dev->info.focus_range.max = 255;
|
|
dev->info.focus_range.quant = 0;
|
|
|
|
dev->info.TPU_Transparency_range.min = 0;
|
|
dev->info.TPU_Transparency_range.max = 10000;
|
|
dev->info.TPU_Transparency_range.quant = 100;
|
|
|
|
sanei_scsi_close (fd);
|
|
fd = -1;
|
|
|
|
++num_devices;
|
|
dev->next = first_dev;
|
|
first_dev = dev;
|
|
|
|
if (devp)
|
|
*devp = dev;
|
|
|
|
DBG (1, "<< attach\n");
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
do_cancel (CANON_Scanner * s)
|
|
{
|
|
SANE_Status status;
|
|
|
|
DBG (1, ">> do_cancel\n");
|
|
|
|
s->scanning = SANE_FALSE;
|
|
|
|
if (s->fd >= 0)
|
|
{
|
|
if (s->val[OPT_EJECT_AFTERSCAN].w == SANE_TRUE)
|
|
{
|
|
DBG (3, "attach: sending MEDIUM POSITION\n");
|
|
status = medium_position (s->fd);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: MEDIUM POSTITION failed\n");
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
s->AF_NOW = SANE_TRUE;
|
|
DBG(1, "do_cancel AF_NOW = '%d'\n", s->AF_NOW);
|
|
}
|
|
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
}
|
|
|
|
DBG (1, "<< do_cancel\n");
|
|
return (SANE_STATUS_CANCELLED);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
adjust_hilo_points(CANON_Scanner *s)
|
|
{
|
|
int mode;
|
|
char *mode_str;
|
|
SANE_Status status;
|
|
u_char wbuf[72], dbuf[28], gbuf[256];
|
|
size_t buf_size;
|
|
int i, j;
|
|
size_t nread, bread;
|
|
SANE_Byte *adjbuf;
|
|
double histo[3][256], sum[3], partsum[3], newsum;
|
|
double percentage, next_percentage;
|
|
float gamma[3];
|
|
int maxhi, minlo;
|
|
SANE_Word save_xres, new_xres;
|
|
|
|
DBG (1, ">> adjust_hilo_points\n");
|
|
|
|
/* First make sure we have a current parameter set. Some of the
|
|
parameters will be overwritten below, but that's OK. */
|
|
status = sane_get_parameters (s, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
|
|
status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "open of %s failed: %s\n",
|
|
s->hw->sane.name, sane_strstatus (status));
|
|
return (status);
|
|
}
|
|
|
|
if (s->val[OPT_CUSTOM_GAMMA].w == 1)
|
|
{
|
|
buf_size = 256 * sizeof (u_char);
|
|
for (i=0; i<4; i++)
|
|
{
|
|
for (j=0; j<256; j++)
|
|
{
|
|
/* Use a straight intensity curve for all colors */
|
|
gbuf[j] = (u_char)j;
|
|
DBG (22, "set_density %d: gbuf[%d] = [%d]\n", i, j, gbuf[j]);
|
|
}
|
|
|
|
status = set_density_curve (s->fd, i, gbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (7, "SET_DENSITY_CURVE failed\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
mode_str = s->val[OPT_MODE].s;
|
|
|
|
save_xres = (SANE_Word)s->val[OPT_X_RESOLUTION].w;
|
|
|
|
s->scanning = SANE_FALSE;
|
|
new_xres = 170;
|
|
sane_control_option (s, OPT_X_RESOLUTION, SANE_ACTION_SET_VALUE,
|
|
&new_xres, 0);
|
|
|
|
status = sane_get_parameters (s, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
|
|
s->xres = s->val[OPT_X_RESOLUTION].w;
|
|
s->yres = s->val[OPT_X_RESOLUTION].w;
|
|
|
|
s->ulx = SANE_UNFIX(s->val[OPT_TL_X].w) * s->hw->info.mud / MM_PER_INCH;
|
|
s->uly = SANE_UNFIX(s->val[OPT_TL_Y].w) * s->hw->info.mud / MM_PER_INCH;
|
|
|
|
s->width = SANE_UNFIX(s->val[OPT_BR_X].w - s->val[OPT_TL_X].w)
|
|
* s->hw->info.mud / MM_PER_INCH;
|
|
s->length = SANE_UNFIX(s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w)
|
|
* s->hw->info.mud / MM_PER_INCH;
|
|
|
|
DBG(11, "ahl: s->width='%d', s->length='%d'\n", s->width, s->length);
|
|
|
|
s->RIF = (s->hw->info.model == CS2700) ?
|
|
s->RIF :
|
|
s->val[OPT_HNEGATIVE].w;
|
|
|
|
/* s->brightness = (s->RIF == 0) ? */
|
|
/* s->val[OPT_BRIGHTNESS].w : (255 - s->val[OPT_BRIGHTNESS].w); */
|
|
s->brightness = s->val[OPT_BRIGHTNESS].w;
|
|
s->contrast = s->val[OPT_CONTRAST].w;
|
|
s->threshold = s->val[OPT_THRESHOLD].w;
|
|
s->bpp = s->params.depth;
|
|
|
|
s->GRC = s->val[OPT_CUSTOM_GAMMA].w;
|
|
s->Mirror = s->val[OPT_MIRROR].w;
|
|
s->AE = 0;
|
|
|
|
s->HiliteR = 255;
|
|
s->ShadowR = 0;
|
|
s->HiliteG = 255;
|
|
s->ShadowG = 0;
|
|
s->HiliteB = 255;
|
|
s->ShadowB = 0;
|
|
|
|
if (strcmp (mode_str, "Lineart") == 0)
|
|
{
|
|
mode = 4;
|
|
s->image_composition = 0;
|
|
}
|
|
else if (strcmp (mode_str, "Halftone") == 0)
|
|
{
|
|
mode = 4;
|
|
s->image_composition = 1;
|
|
}
|
|
else if (strcmp (mode_str, "Gray") == 0)
|
|
{
|
|
mode = 5;
|
|
s->image_composition = 2;
|
|
}
|
|
else if (strcmp (mode_str, "Color") == 0)
|
|
{
|
|
mode = 6;
|
|
s->image_composition = 5;
|
|
}
|
|
|
|
DBG(11, "ahl: s->xres='%d', s->yres='%d'\n", s->xres, s->yres);
|
|
|
|
memset (wbuf, 0, sizeof (wbuf));
|
|
wbuf[7] = 64;
|
|
wbuf[10] = s->xres >> 8;
|
|
wbuf[11] = s->xres;
|
|
wbuf[12] = s->yres >> 8;
|
|
wbuf[13] = s->yres;
|
|
wbuf[14] = s->ulx >> 24;
|
|
wbuf[15] = s->ulx >> 16;
|
|
wbuf[16] = s->ulx >> 8;
|
|
wbuf[17] = s->ulx;
|
|
wbuf[18] = s->uly >> 24;
|
|
wbuf[19] = s->uly >> 16;
|
|
wbuf[20] = s->uly >> 8;
|
|
wbuf[21] = s->uly;
|
|
wbuf[22] = s->width >> 24;
|
|
wbuf[23] = s->width >> 16;
|
|
wbuf[24] = s->width >> 8;
|
|
wbuf[25] = s->width;
|
|
wbuf[26] = s->length >> 24;
|
|
wbuf[27] = s->length >> 16;
|
|
wbuf[28] = s->length >> 8;
|
|
wbuf[29] = s->length;
|
|
wbuf[30] = s->brightness;
|
|
wbuf[31] = s->threshold;
|
|
wbuf[32] = s->contrast;
|
|
wbuf[33] = s->image_composition;
|
|
wbuf[34] = s->bpp;
|
|
wbuf[36] = 1;
|
|
/* wbuf[37] = (s->RIF << 7) + 3; */
|
|
wbuf[37] = (1 << 7) + 3;
|
|
/* wbuf[50] = (s->GRC << 3) | (s->Mirror << 2) | (s->AE); */
|
|
wbuf[50] = (s->GRC << 3) | (s->Mirror << 2);
|
|
wbuf[54] = 2;
|
|
wbuf[57] = 1;
|
|
wbuf[58] = 1;
|
|
wbuf[59] = s->HiliteR;
|
|
wbuf[60] = s->ShadowR;
|
|
wbuf[62] = s->HiliteG;
|
|
wbuf[64] = s->ShadowG;
|
|
wbuf[70] = s->HiliteB;
|
|
wbuf[71] = s->ShadowB;
|
|
|
|
|
|
DBG(7, "ahl: RIF=%d, GRC=%d, Mirror=%d, AE=%d\n",
|
|
s->RIF, s->GRC, s->Mirror, s->AE);
|
|
DBG(7, "ahl: HR=%d, SR=%d, HG=%d, SG=%d, HB=%d, SB=%d\n",
|
|
s->HiliteR, s->ShadowR,
|
|
s->HiliteG, s->ShadowG,
|
|
s->HiliteB, s->ShadowB);
|
|
|
|
|
|
buf_size = sizeof (wbuf);
|
|
status = set_window (s->fd, wbuf);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status));
|
|
return (status);
|
|
}
|
|
|
|
DBG(7, "adjust_hilo: set_window done\n");
|
|
|
|
buf_size = sizeof (wbuf);
|
|
memset (wbuf, 0, buf_size);
|
|
status = get_window (s->fd, wbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status));
|
|
return (status);
|
|
}
|
|
|
|
DBG (5, "ahl: xres=%d\n", (wbuf[10] * 256) + wbuf[11]);
|
|
DBG (5, "ahl: yres=%d\n", (wbuf[12] * 256) + wbuf[13]);
|
|
DBG (5, "ahl: ulx=%d\n", (wbuf[14] * 256 * 256 * 256)
|
|
+ (wbuf[15] * 256 * 256) + (wbuf[16] * 256) + wbuf[17]);
|
|
DBG (5, "ahl: uly=%d\n", (wbuf[18] * 256 * 256 * 256)
|
|
+ (wbuf[19] * 256 * 256) + (wbuf[20] * 256) + wbuf[21]);
|
|
DBG (5, "ahl: width=%d\n", (wbuf[22] * 256 * 256 * 256)
|
|
+ (wbuf[23] * 256 * 256) + (wbuf[24] * 256) + wbuf[25]);
|
|
DBG (5, "ahl: length=%d\n", (wbuf[26] * 256 * 256 * 256)
|
|
+ (wbuf[27] * 256 * 256) + (wbuf[28] * 256) + wbuf[29]);
|
|
|
|
|
|
status = scan (s->fd);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "start of scan failed: %s\n", sane_strstatus (status));
|
|
return (status);
|
|
}
|
|
|
|
buf_size = sizeof (dbuf);
|
|
memset (dbuf, 0, buf_size);
|
|
status = get_data_status (s->fd, dbuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status));
|
|
return (status);
|
|
}
|
|
DBG (5, "ahl: Magnified Width=%d\n", (dbuf[12] * 256 * 256 * 256)
|
|
+ (dbuf[13] * 256 * 256) + (dbuf[14] * 256) + dbuf[15]);
|
|
DBG (5, "ahl: Magnified Length=%d\n", (dbuf[16] * 256 * 256 * 256)
|
|
+ (dbuf[17] * 256 * 256) + (dbuf[18] * 256) + dbuf[19]);
|
|
DBG (5, "ahl: Data=%d bytes\n", (dbuf[20] * 256 * 256 * 256)
|
|
+ (dbuf[21] * 256 * 256) + (dbuf[22] * 256) + dbuf[23]);
|
|
|
|
if (s->xres > 0 && s->yres > 0 && s->width > 0 && s->length > 0)
|
|
{
|
|
s->params.pixels_per_line = s->width * s->xres / s->hw->info.mud;
|
|
s->params.lines = s->length * s->yres / s->hw->info.mud;
|
|
}
|
|
s->bytes_to_read = s->params.bytes_per_line * s->params.lines;
|
|
|
|
DBG (1, "ahl: %d pixels per line, %d bytes, %d lines high, total %lu bytes, "
|
|
"dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line,
|
|
s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_X_RESOLUTION].w);
|
|
|
|
if(s->bytes_to_read == 0)
|
|
{
|
|
return(SANE_STATUS_GOOD);
|
|
}
|
|
|
|
if( (adjbuf = (SANE_Byte *) malloc(s->bytes_to_read)) == NULL )
|
|
{
|
|
DBG (1, "adjust_hilo: malloc failed\n");
|
|
do_cancel (s);
|
|
return (SANE_STATUS_IO_ERROR);
|
|
}
|
|
|
|
bread = 0;
|
|
nread = 16384;
|
|
while(s->bytes_to_read > 0)
|
|
{
|
|
if (nread > s->bytes_to_read)
|
|
nread = s->bytes_to_read;
|
|
status = read_data (s->fd, &adjbuf[bread], &nread);
|
|
bread += nread;
|
|
s->bytes_to_read -= nread;
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "adjust_hilo: read_data failed: %s\n", sane_strstatus (status));
|
|
do_cancel (s);
|
|
return (SANE_STATUS_IO_ERROR);
|
|
}
|
|
}
|
|
|
|
DBG(7, "adjust_hilo: bread='%lu'\n", (unsigned long) bread);
|
|
|
|
sane_control_option (s, OPT_X_RESOLUTION, SANE_ACTION_SET_VALUE, &save_xres, 0);
|
|
status = sane_get_parameters (s, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
|
|
|
|
/* Negative film color: Red 71, Green 164, Blue 180 (inverted) */
|
|
/* Negative film color: Red 184, Green 91, Blue 74 (not inverted) */
|
|
|
|
DBG(7, "adjust_hilo: building histograms\n");
|
|
|
|
/* Build the histograms */
|
|
DBG(7, "sizeof(histo)='%lu'\n", (unsigned long) sizeof(histo));
|
|
memset (histo, 0, sizeof(histo));
|
|
|
|
for(i=0; i<bread; i+=3)
|
|
{
|
|
/* j = (int)adjbuf[i] - 71; */
|
|
/* j = (j<0) ? -j : j; */
|
|
/* ++histo[RED][j]; */
|
|
++histo[RED][(int)adjbuf[i]];
|
|
|
|
/* j = (int)adjbuf[i+1] - 164; */
|
|
/* j = (j<0) ? -j : j; */
|
|
/* ++histo[GREEN][j]; */
|
|
/* ++histo[GREEN][(int)adjbuf[i+1]-164]; */
|
|
++histo[GREEN][(int)adjbuf[i+1]];
|
|
|
|
/* j = (int)adjbuf[i] - 180; */
|
|
/* j = (j<0) ? -j : j; */
|
|
/* ++histo[BLUE][j]; */
|
|
/* ++histo[BLUE][(int)adjbuf[i+2]-180]; */
|
|
++histo[BLUE][(int)adjbuf[i+2]];
|
|
}
|
|
|
|
for(i=0; i<256; i++)
|
|
{
|
|
DBG(7, "adjust_hilo: histo[%d]=(%03.3f, %03.3f, %03.3f)\n",
|
|
i,
|
|
histo[RED][i],
|
|
histo[GREEN][i],
|
|
histo[BLUE][i]);
|
|
}
|
|
|
|
|
|
/* For each color */
|
|
minlo=255;
|
|
maxhi=0;
|
|
for(i=RED; i<=BLUE; i++)
|
|
{
|
|
/* Count the "total weight" of the histogram */
|
|
for(j=0; j<256; j++)
|
|
{
|
|
sum[i] += histo[i][j];
|
|
}
|
|
|
|
/* Find the "middle weight point" in the histogram */
|
|
j=0;
|
|
while( (partsum[i] <= sum[i]/2) && (j<256) )
|
|
{
|
|
partsum[i] += histo[i][j];
|
|
j++;
|
|
}
|
|
|
|
/* We set the gamma value to the middle weight point */
|
|
/* s->gamma_table[][] = */
|
|
gamma[i] = (float)--j;
|
|
DBG(1, "adjust_hilo: gamma[%d] = '%f'\n", i, gamma[i]);
|
|
|
|
/* Find the shadow point */
|
|
newsum = 0.0;
|
|
for (j = 0; j < 255; j++)
|
|
{
|
|
newsum += histo[i][j];
|
|
percentage = newsum / sum[i];
|
|
next_percentage = (newsum + histo[i][j+1]) / sum[i];
|
|
|
|
if ( fabs(percentage - 0.004) < fabs(next_percentage - 0.004) )
|
|
{
|
|
minlo = j+1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Find the hilight point */
|
|
newsum = 0.0;
|
|
for (j = 255; j > 0; j--)
|
|
{
|
|
newsum += histo[i][j];
|
|
percentage = newsum / sum[i];
|
|
next_percentage = (newsum + histo[i][j-1]) / sum[i];
|
|
|
|
if ( fabs(percentage - 0.004) < fabs(next_percentage - 0.004) )
|
|
{
|
|
maxhi = j+32;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/* minlo = 255 - maxhi; */
|
|
/* maxhi = 255 - minlo; */
|
|
|
|
s->val[OPT_SHADOW_R+i*2].w = *((SANE_Word *)&minlo);
|
|
DBG(1, "adjust_hilo: lo[%d]='%d'\n", i, minlo);
|
|
DBG(1, "adjust_hilo: s->val[OPT_SHADOW_R+%d*2]='%d'\n",
|
|
i, s->val[OPT_SHADOW_R+i*2].w);
|
|
|
|
s->val[OPT_HILITE_R+i*2].w = *((SANE_Word *)&maxhi);
|
|
DBG(1, "adjust_hilo: hi[%d]='%d'\n", i, maxhi);
|
|
DBG(1, "adjust_hilo: s->val[OPT_HILITE_R+%d*2]='%d'\n",
|
|
i, s->val[OPT_HILITE_R+i*2].w);
|
|
}
|
|
|
|
DBG (1, "<< adjust_hilo_points\n");
|
|
|
|
|
|
free(adjbuf);
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
init_options (CANON_Scanner * s)
|
|
{
|
|
int i;
|
|
DBG (1, ">> init_options\n");
|
|
|
|
memset (s->opt, 0, sizeof (s->opt));
|
|
memset (s->val, 0, sizeof (s->val));
|
|
|
|
s->AF_NOW = SANE_TRUE;
|
|
|
|
for (i = 0; i < NUM_OPTIONS; ++i)
|
|
{
|
|
s->opt[i].size = sizeof (SANE_Word);
|
|
s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
|
|
}
|
|
|
|
s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
|
|
s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
|
|
s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
|
|
s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
|
|
|
|
s->opt[OPT_PAGE].name = "options-page";
|
|
s->opt[OPT_PAGE].title = "";
|
|
s->opt[OPT_PAGE].desc = "Selects the options page to show";
|
|
s->opt[OPT_PAGE].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_PAGE].size = max_string_size (page_list);
|
|
s->opt[OPT_PAGE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_PAGE].constraint.string_list = page_list;
|
|
s->val[OPT_PAGE].s = strdup (page_list[0]);
|
|
|
|
/* "Mode" group: */
|
|
s->opt[OPT_MODE_GROUP].title = "Scan Mode";
|
|
s->opt[OPT_MODE_GROUP].desc = "";
|
|
s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_MODE_GROUP].cap = 0;
|
|
s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* scan mode */
|
|
s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
|
|
s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
|
|
s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
|
|
s->opt[OPT_MODE].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_MODE].size = max_string_size (mode_list);
|
|
s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_MODE].constraint.string_list = mode_list;
|
|
s->val[OPT_MODE].s = strdup (mode_list[3]);
|
|
|
|
/* Slides or negatives */
|
|
s->opt[OPT_NEGATIVE].name = "film-type";
|
|
s->opt[OPT_NEGATIVE].title = "Film type";
|
|
s->opt[OPT_NEGATIVE].desc = "Selects the film type, i.e. negatives or slides";
|
|
s->opt[OPT_NEGATIVE].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_NEGATIVE].size = max_string_size (filmtype_list);
|
|
s->opt[OPT_NEGATIVE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_NEGATIVE].constraint.string_list = filmtype_list;
|
|
s->opt[OPT_NEGATIVE].cap |=
|
|
(s->hw->info.model == CS2700) ? 0: SANE_CAP_INACTIVE;
|
|
s->val[OPT_NEGATIVE].s = strdup(filmtype_list[0]);
|
|
|
|
/* Negative film type */
|
|
s->opt[OPT_NEGATIVE_TYPE].name = "negative-film-type";
|
|
s->opt[OPT_NEGATIVE_TYPE].title = "Negative film type";
|
|
s->opt[OPT_NEGATIVE_TYPE].desc = "Selects the negative film type";
|
|
s->opt[OPT_NEGATIVE_TYPE].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_NEGATIVE_TYPE].size = max_string_size (negative_filmtype_list);
|
|
s->opt[OPT_NEGATIVE_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_NEGATIVE_TYPE].constraint.string_list = negative_filmtype_list;
|
|
/* s->opt[OPT_NEGATIVE_TYPE].cap |= SANE_CAP_INACTIVE; */
|
|
s->opt[OPT_NEGATIVE_TYPE].cap |=
|
|
(s->hw->info.model == CS2700) ? 0: SANE_CAP_INACTIVE;
|
|
s->val[OPT_NEGATIVE_TYPE].s = strdup(negative_filmtype_list[0]);
|
|
|
|
/* Scanning speed */
|
|
s->opt[OPT_SCANNING_SPEED].name = "scanning-speed";
|
|
s->opt[OPT_SCANNING_SPEED].title = "Scanning speed";
|
|
s->opt[OPT_SCANNING_SPEED].desc = "Selects the scanning speed";
|
|
s->opt[OPT_SCANNING_SPEED].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_SCANNING_SPEED].size = max_string_size (scanning_speed_list);
|
|
s->opt[OPT_SCANNING_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_SCANNING_SPEED].constraint.string_list = scanning_speed_list;
|
|
/* s->opt[OPT_SCANNING_SPEED].cap |= SANE_CAP_INACTIVE; */
|
|
s->opt[OPT_SCANNING_SPEED].cap |=
|
|
(s->hw->info.model == CS2700) ? 0: SANE_CAP_INACTIVE;
|
|
s->val[OPT_SCANNING_SPEED].s = strdup(scanning_speed_list[0]);
|
|
|
|
/* "Resolution" group: */
|
|
s->opt[OPT_RESOLUTION_GROUP].title = "Scan Resolution";
|
|
s->opt[OPT_RESOLUTION_GROUP].desc = "";
|
|
s->opt[OPT_RESOLUTION_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_RESOLUTION_GROUP].cap = 0;;
|
|
s->opt[OPT_RESOLUTION_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* bind resolution */
|
|
s->opt[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND;
|
|
s->opt[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND;
|
|
s->opt[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND;
|
|
s->opt[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_RESOLUTION_BIND].w = SANE_TRUE;
|
|
|
|
/* hardware resolution only */
|
|
s->opt[OPT_HW_RESOLUTION_ONLY].name = "hw-resolution-only";
|
|
s->opt[OPT_HW_RESOLUTION_ONLY].title = "Hardware resolution";
|
|
s->opt[OPT_HW_RESOLUTION_ONLY].desc = "Use only hardware resolutions";
|
|
s->opt[OPT_HW_RESOLUTION_ONLY].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_HW_RESOLUTION_ONLY].w = SANE_TRUE;
|
|
s->opt[OPT_HW_RESOLUTION_ONLY].cap |=
|
|
(s->hw->info.model == CS2700) ? 0: SANE_CAP_INACTIVE;
|
|
|
|
/* x-resolution */
|
|
s->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
|
|
s->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
|
|
s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
|
|
s->opt[OPT_X_RESOLUTION].type = SANE_TYPE_INT;
|
|
s->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI;
|
|
s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_X_RESOLUTION].constraint.range = &s->hw->info.xres_range;
|
|
s->val[OPT_X_RESOLUTION].w = (s->hw->info.model == CS2700) ? 340 : 300;
|
|
|
|
/* 990320, ss: use only hardware resolutions */
|
|
/* to get option menue instead of slider in xscanimage */
|
|
if (s->hw->info.model == CS2700)
|
|
{
|
|
int iCnt, iNum, iRes;
|
|
|
|
s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
|
|
iNum = 0;
|
|
iCnt = 0;
|
|
iRes = s->hw->info.xres_range.max;
|
|
s->opt[OPT_X_RESOLUTION].constraint.word_list = s->xres_word_list;
|
|
|
|
/* go to minimum resolution by dividing by 2 */
|
|
while (iRes >= s->hw->info.xres_range.min)
|
|
{
|
|
iRes /= 2;
|
|
}
|
|
|
|
/* fill array upto maximum resolution */
|
|
while (iRes < s->hw->info.xres_range.max)
|
|
{
|
|
iCnt++;
|
|
iRes *= 2;
|
|
s->xres_word_list[iCnt] = iRes;
|
|
}
|
|
s->xres_word_list[0] = iCnt;
|
|
s->val[OPT_X_RESOLUTION].w = s->xres_word_list[2]; /* 340 */
|
|
}
|
|
|
|
/* y-resolution */
|
|
s->opt[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION;
|
|
s->opt[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION;
|
|
s->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION;
|
|
s->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_INT;
|
|
s->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
|
|
s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_Y_RESOLUTION].constraint.range = &s->hw->info.yres_range;
|
|
s->val[OPT_Y_RESOLUTION].w = (s->hw->info.model == CS2700) ? 340 : 300;
|
|
s->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
|
|
|
|
/* 990320, ss: use only hardware resolutions */
|
|
/* to get option menue instead of slider in xscanimage */
|
|
if (s->hw->info.model == CS2700)
|
|
{
|
|
int iCnt, iNum, iRes;
|
|
|
|
s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
|
|
iNum = 0;
|
|
iCnt = 0;
|
|
iRes = s->hw->info.yres_range.max;
|
|
s->opt[OPT_Y_RESOLUTION].constraint.word_list = s->yres_word_list;
|
|
|
|
/* go to minimum resolution by dividing by 2 */
|
|
while (iRes >= s->hw->info.yres_range.min)
|
|
{
|
|
iRes /= 2;
|
|
}
|
|
|
|
/* fill array upto maximum resolution */
|
|
while (iRes < s->hw->info.yres_range.max)
|
|
{
|
|
iCnt++;
|
|
iRes *= 2;
|
|
s->yres_word_list[iCnt] = iRes;
|
|
}
|
|
s->yres_word_list[0] = iCnt;
|
|
s->val[OPT_Y_RESOLUTION].w = s->yres_word_list[2]; /* 340 */
|
|
}
|
|
|
|
/* Focus group: */
|
|
s->opt[OPT_FOCUS_GROUP].title = "Focus";
|
|
s->opt[OPT_FOCUS_GROUP].desc = "";
|
|
s->opt[OPT_FOCUS_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_FOCUS_GROUP].cap = SANE_CAP_ADVANCED;
|
|
s->opt[OPT_FOCUS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* Auto-Focus switch */
|
|
s->opt[OPT_AF].name = "af";
|
|
s->opt[OPT_AF].title = "Auto Focus";
|
|
s->opt[OPT_AF].desc = "Enable/disable Auto Focus";
|
|
s->opt[OPT_AF].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_AF].w = SANE_TRUE;
|
|
|
|
/* Auto-Focus once switch */
|
|
s->opt[OPT_AF_ONCE].name = "afonce";
|
|
s->opt[OPT_AF_ONCE].title = "Auto Focus only once";
|
|
s->opt[OPT_AF_ONCE].desc = "Do Auto Focus only once between ejects";
|
|
s->opt[OPT_AF_ONCE].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_AF_ONCE].cap |=
|
|
(s->hw->info.model == CS2700) ? 0: SANE_CAP_INACTIVE;
|
|
s->val[OPT_AF_ONCE].w =
|
|
(s->hw->info.model == CS2700) ? SANE_TRUE: SANE_FALSE;
|
|
|
|
/* Manual focus */
|
|
s->opt[OPT_FOCUS].name = "focus";
|
|
s->opt[OPT_FOCUS].title = "Manual focus position";
|
|
s->opt[OPT_FOCUS].desc = "Set the optical system's focus position by hand. The default position is 128.";
|
|
s->opt[OPT_FOCUS].type = SANE_TYPE_INT;
|
|
s->opt[OPT_FOCUS].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_FOCUS].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_FOCUS].constraint.range = &s->hw->info.focus_range;
|
|
s->opt[OPT_FOCUS].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_FOCUS].w = 128;
|
|
|
|
/* Margins group: */
|
|
s->opt[OPT_MARGINS_GROUP].title = "Scan margins";
|
|
s->opt[OPT_MARGINS_GROUP].desc = "";
|
|
s->opt[OPT_MARGINS_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_MARGINS_GROUP].cap = SANE_CAP_ADVANCED;
|
|
s->opt[OPT_MARGINS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* top-left x */
|
|
s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
|
|
s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
|
|
s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
|
|
s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
|
|
s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
|
|
s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_TL_X].constraint.range = &s->hw->info.x_range;
|
|
s->val[OPT_TL_X].w = 0;
|
|
|
|
/* top-left y */
|
|
s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
|
|
s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
|
|
s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
|
|
s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
|
|
s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
|
|
s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_TL_Y].constraint.range = &s->hw->info.y_range;
|
|
s->val[OPT_TL_Y].w = 0;
|
|
|
|
/* bottom-right x */
|
|
s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
|
|
s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
|
|
s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
|
|
s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
|
|
s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
|
|
s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_BR_X].constraint.range = &s->hw->info.x_range;
|
|
s->val[OPT_BR_X].w = s->hw->info.x_range.max;
|
|
|
|
/* bottom-right y */
|
|
s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
|
|
s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
|
|
s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
|
|
s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
|
|
s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
|
|
s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_BR_Y].constraint.range = &s->hw->info.y_range;
|
|
s->val[OPT_BR_Y].w = s->hw->info.y_range.max;
|
|
|
|
/* Colors group: */
|
|
s->opt[OPT_COLORS_GROUP].title = "Extra color adjustments";
|
|
s->opt[OPT_COLORS_GROUP].desc = "";
|
|
s->opt[OPT_COLORS_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_COLORS_GROUP].cap = SANE_CAP_ADVANCED;
|
|
s->opt[OPT_COLORS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* Positive/Negative switch for the CanoScan 300/600 models */
|
|
s->opt[OPT_HNEGATIVE].name = SANE_NAME_NEGATIVE;
|
|
s->opt[OPT_HNEGATIVE].title = SANE_TITLE_NEGATIVE;
|
|
s->opt[OPT_HNEGATIVE].desc = SANE_DESC_NEGATIVE;
|
|
s->opt[OPT_HNEGATIVE].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_HNEGATIVE].cap |=
|
|
(s->hw->info.model == CS2700) ? SANE_CAP_INACTIVE : 0;
|
|
s->val[OPT_HNEGATIVE].w = SANE_FALSE;
|
|
|
|
/* Same values vor highlight and shadow points for red, green, blue */
|
|
s->opt[OPT_BIND_HILO].name = "bind-highlight-shadow-points";
|
|
s->opt[OPT_BIND_HILO].title = SANE_TITLE_RGB_BIND;
|
|
s->opt[OPT_BIND_HILO].desc = SANE_DESC_RGB_BIND;
|
|
s->opt[OPT_BIND_HILO].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_BIND_HILO].w = SANE_TRUE;
|
|
|
|
/* highlight point for red */
|
|
s->opt[OPT_HILITE_R].name = SANE_NAME_HIGHLIGHT_R;
|
|
s->opt[OPT_HILITE_R].title = SANE_TITLE_HIGHLIGHT_R;
|
|
s->opt[OPT_HILITE_R].desc = SANE_DESC_HIGHLIGHT_R;
|
|
s->opt[OPT_HILITE_R].type = SANE_TYPE_INT;
|
|
s->opt[OPT_HILITE_R].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_HILITE_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_HILITE_R].constraint.range = &s->hw->info.HiliteR_range;
|
|
s->opt[OPT_HILITE_R].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_HILITE_R].w = 0;
|
|
|
|
/* shadow point for red */
|
|
s->opt[OPT_SHADOW_R].name = SANE_NAME_SHADOW_R;
|
|
s->opt[OPT_SHADOW_R].title = SANE_TITLE_SHADOW_R;
|
|
s->opt[OPT_SHADOW_R].desc = SANE_DESC_SHADOW_R;
|
|
s->opt[OPT_SHADOW_R].type = SANE_TYPE_INT;
|
|
s->opt[OPT_SHADOW_R].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_SHADOW_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_SHADOW_R].constraint.range = &s->hw->info.ShadowR_range;
|
|
s->opt[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_SHADOW_R].w = 0;
|
|
|
|
/* highlight point for green */
|
|
s->opt[OPT_HILITE_G].name = SANE_NAME_HIGHLIGHT;
|
|
s->opt[OPT_HILITE_G].title = SANE_TITLE_HIGHLIGHT;
|
|
s->opt[OPT_HILITE_G].desc = SANE_DESC_HIGHLIGHT;
|
|
s->opt[OPT_HILITE_G].type = SANE_TYPE_INT;
|
|
s->opt[OPT_HILITE_G].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_HILITE_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_HILITE_G].constraint.range = &s->hw->info.HiliteG_range;
|
|
s->val[OPT_HILITE_G].w = 255;
|
|
|
|
/* shadow point for green */
|
|
s->opt[OPT_SHADOW_G].name = SANE_NAME_SHADOW;
|
|
s->opt[OPT_SHADOW_G].title = SANE_TITLE_SHADOW;
|
|
s->opt[OPT_SHADOW_G].desc = SANE_DESC_SHADOW;
|
|
s->opt[OPT_SHADOW_G].type = SANE_TYPE_INT;
|
|
s->opt[OPT_SHADOW_G].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_SHADOW_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_SHADOW_G].constraint.range = &s->hw->info.ShadowG_range;
|
|
s->val[OPT_SHADOW_G].w = 0;
|
|
|
|
/* highlight point for blue */
|
|
s->opt[OPT_HILITE_B].name = SANE_NAME_HIGHLIGHT_B;
|
|
s->opt[OPT_HILITE_B].title = SANE_TITLE_HIGHLIGHT_B;
|
|
s->opt[OPT_HILITE_B].desc = SANE_DESC_HIGHLIGHT_B;
|
|
s->opt[OPT_HILITE_B].type = SANE_TYPE_INT;
|
|
s->opt[OPT_HILITE_B].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_HILITE_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_HILITE_B].constraint.range = &s->hw->info.HiliteB_range;
|
|
s->opt[OPT_HILITE_B].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_HILITE_B].w = 0;
|
|
|
|
/* shadow point for blue */
|
|
s->opt[OPT_SHADOW_B].name = SANE_NAME_SHADOW_B;
|
|
s->opt[OPT_SHADOW_B].title = SANE_TITLE_SHADOW_B;
|
|
s->opt[OPT_SHADOW_B].desc = SANE_DESC_SHADOW_B;
|
|
s->opt[OPT_SHADOW_B].type = SANE_TYPE_INT;
|
|
s->opt[OPT_SHADOW_B].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_SHADOW_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_SHADOW_B].constraint.range = &s->hw->info.ShadowB_range;
|
|
s->opt[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_SHADOW_B].w = 0;
|
|
|
|
|
|
/* "Enhancement" group: */
|
|
s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
|
|
s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
|
|
s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
|
|
s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* brightness */
|
|
s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
|
|
s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
|
|
s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
|
|
s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
|
|
s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_BRIGHTNESS].constraint.range = &s->hw->info.brightness_range;
|
|
s->val[OPT_BRIGHTNESS].w = 128;
|
|
|
|
/* contrast */
|
|
s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
|
|
s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
|
|
s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
|
|
s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
|
|
s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_CONTRAST].constraint.range = &s->hw->info.contrast_range;
|
|
s->val[OPT_CONTRAST].w = 128;
|
|
|
|
/* threshold */
|
|
s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
|
|
s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
|
|
s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
|
|
s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
|
|
s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_THRESHOLD].constraint.range = &s->hw->info.threshold_range;
|
|
s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_THRESHOLD].w = 128;
|
|
|
|
s->opt[OPT_MIRROR].name = "mirror";
|
|
s->opt[OPT_MIRROR].title = "Mirror image";
|
|
s->opt[OPT_MIRROR].desc = "Mirror the image horizontally";
|
|
s->opt[OPT_MIRROR].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_MIRROR].w = SANE_FALSE;
|
|
|
|
/* analog-gamma curve */
|
|
s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
|
|
s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
|
|
s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
|
|
s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
|
|
|
|
/* bind analog-gamma */
|
|
s->opt[OPT_CUSTOM_GAMMA_BIND].name = "bind-custom-gamma";
|
|
s->opt[OPT_CUSTOM_GAMMA_BIND].title = SANE_TITLE_RGB_BIND;
|
|
s->opt[OPT_CUSTOM_GAMMA_BIND].desc = SANE_DESC_RGB_BIND;
|
|
s->opt[OPT_CUSTOM_GAMMA_BIND].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_CUSTOM_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
|
|
s->val[OPT_CUSTOM_GAMMA_BIND].w = SANE_TRUE;
|
|
|
|
/* grayscale gamma vector */
|
|
s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
|
|
s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
|
|
s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
|
|
s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
|
|
s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
|
|
s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
|
|
s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
|
|
s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0];
|
|
|
|
/* red gamma vector */
|
|
s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
|
|
s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
|
|
s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
|
|
s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
|
|
s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
|
|
s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
|
|
s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
|
|
s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0];
|
|
|
|
/* green gamma vector */
|
|
s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
|
|
s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
|
|
s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
|
|
s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
|
|
s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
|
|
s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
|
|
s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
|
|
s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0];
|
|
|
|
/* blue gamma vector */
|
|
s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
|
|
s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
|
|
s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
|
|
s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
|
|
s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
|
|
s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
|
|
s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
|
|
s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0];
|
|
|
|
s->opt[OPT_AE].name = "ae";
|
|
s->opt[OPT_AE].title = "Auto Exposure";
|
|
s->opt[OPT_AE].desc = "Enable/disable the Auto Exposure feature";
|
|
s->opt[OPT_AE].cap |=
|
|
(s->hw->info.model == CS2700) ? SANE_CAP_INACTIVE : 0;
|
|
s->opt[OPT_AE].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_AE].w = SANE_FALSE;
|
|
|
|
/* "Eject" group (active only for model 2700F) */
|
|
s->opt[OPT_EJECT_GROUP].title = "Medium handling";
|
|
s->opt[OPT_EJECT_GROUP].desc = "";
|
|
s->opt[OPT_EJECT_GROUP].type = SANE_TYPE_GROUP;
|
|
/* s->opt[OPT_EJECT_GROUP].cap |= */
|
|
/* (s->hw->info.model == CS2700) ? 0 : SANE_CAP_INACTIVE; */
|
|
s->opt[OPT_EJECT_GROUP].cap = 0;
|
|
s->opt[OPT_EJECT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
/* eject after scan */
|
|
s->opt[OPT_EJECT_AFTERSCAN].name = "eject-after-scan";
|
|
s->opt[OPT_EJECT_AFTERSCAN].title = "Eject film after each scan";
|
|
s->opt[OPT_EJECT_AFTERSCAN].desc =
|
|
"Automatically eject the film from the device after each scan";
|
|
s->opt[OPT_EJECT_AFTERSCAN].cap |=
|
|
(s->hw->info.model == CS2700) ? 0 : SANE_CAP_INACTIVE;
|
|
s->opt[OPT_EJECT_AFTERSCAN].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_EJECT_AFTERSCAN].w = SANE_FALSE;
|
|
|
|
/* eject before exit */
|
|
s->opt[OPT_EJECT_BEFOREEXIT].name = "eject-before-exit";
|
|
s->opt[OPT_EJECT_BEFOREEXIT].title = "Eject film before exit";
|
|
s->opt[OPT_EJECT_BEFOREEXIT].desc =
|
|
"Automatically eject the film from the device before exiting the program";
|
|
s->opt[OPT_EJECT_BEFOREEXIT].cap |=
|
|
(s->hw->info.model == CS2700) ? 0 : SANE_CAP_INACTIVE;
|
|
s->opt[OPT_EJECT_BEFOREEXIT].type = SANE_TYPE_BOOL;
|
|
s->val[OPT_EJECT_BEFOREEXIT].w = SANE_FALSE;
|
|
|
|
/* eject now */
|
|
s->opt[OPT_EJECT_NOW].name = "eject-now";
|
|
s->opt[OPT_EJECT_NOW].title = "Eject film now";
|
|
s->opt[OPT_EJECT_NOW].desc = "Eject the film from the device *now*";
|
|
s->opt[OPT_EJECT_NOW].type = SANE_TYPE_BUTTON;
|
|
s->opt[OPT_EJECT_NOW].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_EJECT_NOW].cap |=
|
|
(s->hw->info.model == CS2700) ? 0 : SANE_CAP_INACTIVE;
|
|
s->opt[OPT_EJECT_NOW].constraint_type = SANE_CONSTRAINT_NONE;
|
|
s->opt[OPT_EJECT_NOW].constraint.range = NULL;
|
|
|
|
/* "NO-ADF" option: */
|
|
s->opt[OPT_ADF_GROUP].title = "Document Feeder Extras";
|
|
s->opt[OPT_ADF_GROUP].desc = "";
|
|
s->opt[OPT_ADF_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_ADF_GROUP].cap = 0;
|
|
s->opt[OPT_ADF_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
|
|
s->opt[OPT_FLATBED_ONLY].name = "noadf";
|
|
s->opt[OPT_FLATBED_ONLY].title = "Flatbed Only";
|
|
s->opt[OPT_FLATBED_ONLY].desc = "Disable Auto Document Feeder and use Flatbed only";
|
|
s->opt[OPT_FLATBED_ONLY].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_FLATBED_ONLY].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_FLATBED_ONLY].size = sizeof(SANE_Word);
|
|
s->opt[OPT_FLATBED_ONLY].cap |=
|
|
(s->hw->adf.Status == ADF_STAT_NONE) ? SANE_CAP_INACTIVE : 0;
|
|
s->val[OPT_FLATBED_ONLY].w = SANE_FALSE;
|
|
|
|
/* "TPU" group: */
|
|
s->opt[OPT_TPU_GROUP].title = "Transparency Unit";
|
|
s->opt[OPT_TPU_GROUP].desc = "";
|
|
s->opt[OPT_TPU_GROUP].type = SANE_TYPE_GROUP;
|
|
s->opt[OPT_TPU_GROUP].cap = 0;
|
|
s->opt[OPT_TPU_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
|
|
s->opt[OPT_TPU_GROUP].cap |=
|
|
(s->hw->tpu.Status != TPU_STAT_NONE) ? 0 : SANE_CAP_INACTIVE;
|
|
|
|
|
|
/* Transparency Unit (FAU, Film Adapter Unit) */
|
|
s->opt[OPT_TPU_ON].name = "transparency-unit-on-off";
|
|
s->opt[OPT_TPU_ON].title =
|
|
(s->hw->tpu.Status == TPU_STAT_ACTIVE) ?
|
|
"Turn Off the Transparency Unit" : "Turn On the Transparency Unit";
|
|
s->opt[OPT_TPU_ON].desc =
|
|
"Switch on/off the Transparency Unit (FAU, Film Adapter Unit)";
|
|
s->opt[OPT_TPU_ON].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_TPU_ON].unit = SANE_UNIT_NONE;
|
|
s->val[OPT_TPU_ON].w = s->hw->tpu.Status;
|
|
s->opt[OPT_TPU_ON].cap |=
|
|
(s->hw->tpu.Status != TPU_STAT_NONE) ? 0 : SANE_CAP_INACTIVE;
|
|
|
|
s->opt[OPT_TPU_PN].name = "transparency-unit-negative-film";
|
|
s->opt[OPT_TPU_PN].title = "Negative Film";
|
|
s->opt[OPT_TPU_PN].desc = "Positive or Negative Film";
|
|
s->opt[OPT_TPU_PN].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_TPU_PN].unit = SANE_UNIT_NONE;
|
|
s->val[OPT_TPU_PN].w = s->hw->tpu.PosNeg;
|
|
s->opt[OPT_TPU_PN].cap |=
|
|
(s->hw->tpu.Status == TPU_STAT_ACTIVE) ? 0 : SANE_CAP_INACTIVE;
|
|
|
|
/* density control mode */
|
|
s->opt[OPT_TPU_DCM].name = "TPMDC";
|
|
s->opt[OPT_TPU_DCM].title = "Density Control";
|
|
s->opt[OPT_TPU_DCM].desc = "Set Density Control Mode";
|
|
s->opt[OPT_TPU_DCM].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_TPU_DCM].size = max_string_size (tpu_dc_mode_list);
|
|
s->opt[OPT_TPU_DCM].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_TPU_DCM].constraint.string_list = tpu_dc_mode_list;
|
|
s->val[OPT_TPU_DCM].s = strdup (tpu_dc_mode_list[s->hw->tpu.ControlMode]);
|
|
s->opt[OPT_TPU_DCM].cap |=
|
|
(s->hw->tpu.Status == TPU_STAT_ACTIVE) ? 0 : SANE_CAP_INACTIVE;
|
|
|
|
/* Transparency Ratio */
|
|
s->opt[OPT_TPU_TRANSPARENCY].name = "Transparency-Ratio";
|
|
s->opt[OPT_TPU_TRANSPARENCY].title = "Transparency Ratio";
|
|
s->opt[OPT_TPU_TRANSPARENCY].desc = "";
|
|
s->opt[OPT_TPU_TRANSPARENCY].type = SANE_TYPE_INT;
|
|
s->opt[OPT_TPU_TRANSPARENCY].unit = SANE_UNIT_NONE;
|
|
s->opt[OPT_TPU_TRANSPARENCY].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->opt[OPT_TPU_TRANSPARENCY].constraint.range =
|
|
&s->hw->info.TPU_Transparency_range;
|
|
s->val[OPT_TPU_TRANSPARENCY].w = s->hw->tpu.Transparency;
|
|
s->opt[OPT_TPU_TRANSPARENCY].cap |=
|
|
(s->hw->tpu.Status == TPU_STAT_ACTIVE &&
|
|
s->hw->tpu.ControlMode == 3) ?
|
|
0 : SANE_CAP_INACTIVE;
|
|
|
|
|
|
/* Select Film type */
|
|
s->opt[OPT_TPU_FILMTYPE].name = "Filmtype";
|
|
s->opt[OPT_TPU_FILMTYPE].title = "Select Film type";
|
|
s->opt[OPT_TPU_FILMTYPE].desc = "Select the film type";
|
|
s->opt[OPT_TPU_FILMTYPE].type = SANE_TYPE_STRING;
|
|
s->opt[OPT_TPU_FILMTYPE].size = max_string_size (tpu_filmtype_list);
|
|
s->opt[OPT_TPU_FILMTYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->opt[OPT_TPU_FILMTYPE].constraint.string_list = tpu_filmtype_list;
|
|
s->val[OPT_TPU_FILMTYPE].s = strdup (tpu_filmtype_list[s->hw->tpu.FilmType]);
|
|
s->opt[OPT_TPU_FILMTYPE].cap |=
|
|
(s->hw->tpu.Status == TPU_STAT_ACTIVE &&
|
|
s->hw->tpu.ControlMode == 1) ?
|
|
0 : SANE_CAP_INACTIVE;
|
|
|
|
|
|
/* preview */
|
|
s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
|
|
s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
|
|
s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
|
|
s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
|
|
s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
|
|
s->val[OPT_PREVIEW].w = SANE_FALSE;
|
|
|
|
DBG (1, "<< init_options\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
attach_one (const char *dev)
|
|
{
|
|
DBG (1, ">> attach_one\n");
|
|
attach (dev, 0);
|
|
DBG (1, "<< attach_one\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
static SANE_Status
|
|
do_focus(CANON_Scanner *s)
|
|
{
|
|
SANE_Status status;
|
|
u_char ebuf[74];
|
|
size_t buf_size;
|
|
|
|
DBG (3, "do_focus: sending GET FILM STATUS\n");
|
|
memset (ebuf, 0, sizeof (ebuf));
|
|
buf_size = 4;
|
|
status = get_film_status (s->fd, ebuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "do_focus: GET FILM STATUS failed\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
DBG(3, "focus point before autofocus : %d\n", ebuf[3]);
|
|
|
|
if (s->val[OPT_AF].w == SANE_TRUE)
|
|
{
|
|
/* Auto-Focus */
|
|
/* status = execute_auto_focus (s->fd, AUTO_FOCUS, NO_AUTO_SCAN_SPEED, */
|
|
/* NO_AUTO_EXPOSURE, 0, NULL, 0); */
|
|
/* status = execute_auto_focus (s->fd, AUTO_FOCUS, NO_AUTO_SCAN_SPEED, */
|
|
/* AUTO_EXPOSURE, 0, NULL, 0); */
|
|
status = execute_auto_focus (s->fd, AUTO_FOCUS,
|
|
(s->scanning_speed == 0) ? AUTO_SCAN_SPEED : NO_AUTO_SCAN_SPEED,
|
|
(s->AE == 0) ? NO_AUTO_EXPOSURE : AUTO_EXPOSURE,
|
|
0, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
/* Manual Focus */
|
|
/* status = execute_auto_focus (s->fd, MANUAL_FOCUS, NO_AUTO_SCAN_SPEED, */
|
|
/* NO_AUTO_EXPOSURE, s->val[OPT_FOCUS].w, NULL, 0); */
|
|
status = execute_auto_focus (s->fd, MANUAL_FOCUS,
|
|
(s->scanning_speed == 0) ? AUTO_SCAN_SPEED : NO_AUTO_SCAN_SPEED,
|
|
(s->AE == 0) ? NO_AUTO_EXPOSURE : AUTO_EXPOSURE,
|
|
s->val[OPT_FOCUS].w, NULL, 0);
|
|
}
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (7, "EXECUTE_AUTO_FOCUS failed\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
DBG (3, "do_focus: sending GET FILM STATUS\n");
|
|
memset (ebuf, 0, sizeof (ebuf));
|
|
buf_size = 4;
|
|
status = get_film_status (s->fd, ebuf, &buf_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "do_focus: GET FILM STATUS failed\n");
|
|
sanei_scsi_close (s->fd);
|
|
s->fd = -1;
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
DBG(3, "focus point after autofocus : %d\n", ebuf[3]);
|
|
|
|
return(SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
#include "canon-sane.c"
|