Merge branch 'newyearsbranch' into 'master'

canon_lide70-sequel

See merge request sane-project/backends!315
merge-requests/393/merge
Olaf Meeuwissen 2020-04-04 04:35:45 +00:00
commit f8193494ad
12 zmienionych plików z 4145 dodań i 8 usunięć

Wyświetl plik

@ -13,6 +13,7 @@ Backends:
Mitsuru Okaniwa, Ulrich Deiters
canon630u: Nathan Rutman
canon_dr: m. allan noah (*)
canon_lide70: Juergen Ernst, pimvantend
canon_pp: Matthew Duggan, Simon Krix
cardscan: m. allan noah (*)
coolscan: Didier Carlier, Andreas Rick

Wyświetl plik

@ -65,6 +65,7 @@ EXTRA_DIST += saned.conf.in
BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \
artec_eplus48u.conf avision.conf bh.conf \
canon630u.conf canon.conf canon_dr.conf \
canon_lide70.conf \
canon_pp.conf cardscan.conf coolscan2.conf coolscan3.conf \
coolscan.conf dc210.conf dc240.conf dc25.conf \
dell1600n_net.conf dmc.conf epjitsu.conf epson2.conf \
@ -157,6 +158,7 @@ be_convenience_libs = libabaton.la libagfafocus.la \
libapple.la libartec.la libartec_eplus48u.la \
libas6e.la libavision.la libbh.la \
libcanon.la libcanon630u.la libcanon_dr.la \
libcanon_lide70.la \
libcanon_pp.la libcardscan.la libcoolscan.la \
libcoolscan2.la libcoolscan3.la libdc25.la \
libdc210.la libdc240.la libdell1600n_net.la \
@ -190,6 +192,7 @@ be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \
libsane-apple.la libsane-artec.la libsane-artec_eplus48u.la \
libsane-as6e.la libsane-avision.la libsane-bh.la \
libsane-canon.la libsane-canon630u.la libsane-canon_dr.la \
libsane-canon_lide70.la \
libsane-canon_pp.la libsane-cardscan.la libsane-coolscan.la \
libsane-coolscan2.la libsane-coolscan3.la libsane-dc25.la \
libsane-dc210.la libsane-dc240.la libsane-dell1600n_net.la \
@ -344,6 +347,17 @@ libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += canon_dr.conf.in
libcanon_lide70_la_SOURCES = canon_lide70.c
libcanon_lide70_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_lide70
nodist_libsane_canon_lide70_la_SOURCES = canon_lide70-s.c
libsane_canon_lide70_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_lide70
libsane_canon_lide70_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_canon_lide70_la_LIBADD = $(COMMON_LIBS) libcanon_lide70.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += canon_lide70.conf.in
# TODO: Why are this distributed but not compiled?
EXTRA_DIST += canon_lide70-common.c
libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h
libcanon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,960 @@
/* sane - Scanner Access Now Easy.
BACKEND canon_lide70
Copyright (C) 2019 Juergen Ernst and pimvantend.
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.
This file implements a SANE backend for the Canon CanoScan LiDE 70 */
#define BUILD 0
#define MM_IN_INCH 25.4
#include "../include/sane/config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "../include/sane/sane.h"
#include "../include/sane/sanei.h"
#include "../include/sane/saneopts.h"
#include "../include/sane/sanei_config.h"
#include "../include/sane/sanei_usb.h"
#define BACKEND_NAME canon_lide70
#define CANONUSB_CONFIG_FILE "canon_lide70.conf"
#include "../include/sane/sanei_backend.h"
typedef enum
{
opt_num_opts = 0,
opt_mode_group,
opt_threshold,
opt_mode,
opt_resolution,
opt_non_blocking,
opt_geometry_group,
opt_tl_x,
opt_tl_y,
opt_br_x,
opt_br_y,
/* must come last: */
num_options
}
canon_opts;
#include "canon_lide70-common.c"
static size_t
max_string_size (const SANE_String_Const strings[])
{
size_t size, max_size = 0;
SANE_Int i;
for (i = 0; strings[i]; ++i)
{
size = strlen (strings[i]) + 1;
if (size > max_size)
max_size = size;
}
return max_size;
}
static SANE_String_Const mode_list[] = {
SANE_VALUE_SCAN_MODE_COLOR,
SANE_VALUE_SCAN_MODE_GRAY,
SANE_VALUE_SCAN_MODE_LINEART,
0
};
static SANE_Fixed init_tl_x = SANE_FIX (0.0);
static SANE_Fixed init_tl_y = SANE_FIX (0.0);
static SANE_Fixed init_br_x = SANE_FIX (80.0);
static SANE_Fixed init_br_y = SANE_FIX (100.0);
static SANE_Int init_threshold = 75;
static SANE_Int init_resolution = 600;
static SANE_String init_mode = SANE_VALUE_SCAN_MODE_COLOR;
static SANE_Int init_graymode = 0;
static SANE_Bool init_non_blocking = SANE_FALSE;
/*-----------------------------------------------------------------*/
/*
Scan range
*/
static const SANE_Range widthRange = {
0, /* minimum */
SANE_FIX (CANON_MAX_WIDTH * MM_IN_INCH / 600), /* maximum */
0 /* quantization */
};
static const SANE_Range heightRange = {
0, /* minimum */
/* SANE_FIX (CANON_MAX_HEIGHT * MM_IN_INCH / 600 - TOP_EDGE ), maximum */
SANE_FIX (297.0),
0 /* quantization */
};
static const SANE_Range threshold_range = {
0,
100,
1
};
static SANE_Int resolution_list[] = { 5,
75,
150,
300,
600,
1200
};
typedef struct Canon_Device
{
struct Canon_Device *next;
SANE_String name;
SANE_Device sane;
}
Canon_Device;
/* Canon_Scanner is the type used for the sane handle */
typedef struct Canon_Scanner
{
struct Canon_Scanner *next;
Canon_Device *device;
CANON_Handle scan;
}
Canon_Scanner;
static int num_devices = 0;
static const SANE_Device **devlist = NULL;
static Canon_Device *first_dev = NULL;
static Canon_Scanner *first_handle = NULL;
/*-----------------------------------------------------------------*/
static SANE_Status
attach_scanner (const char *devicename, Canon_Device ** devp)
{
CANON_Handle scan;
Canon_Device *dev;
SANE_Status status;
DBG (3, "attach_scanner: %s\n", devicename);
for (dev = first_dev; dev; dev = dev->next)
{
if (strcmp (dev->sane.name, devicename) == 0)
{
if (devp)
*devp = dev;
return SANE_STATUS_GOOD;
}
}
dev = malloc (sizeof (*dev));
if (!dev)
return SANE_STATUS_NO_MEM;
memset (dev, '\0', sizeof (Canon_Device)); /* clear structure */
DBG (4, "attach_scanner: opening %s\n", devicename);
status = CANON_open_device (&scan, devicename);
if (status != SANE_STATUS_GOOD)
{
DBG (1, "ERROR: attach_scanner: opening %s failed\n", devicename);
free (dev);
return status;
}
dev->name = strdup (devicename);
dev->sane.name = dev->name;
dev->sane.vendor = "CANON";
dev->sane.model = CANON_get_device_name (&scan);
dev->sane.type = "flatbed scanner";
CANON_close_device (&scan);
++num_devices;
dev->next = first_dev;
first_dev = dev;
if (devp)
*devp = dev;
return SANE_STATUS_GOOD;
}
/* callback function for sanei_usb_attach_matching_devices */
static SANE_Status
attach_one (const char *name)
{
attach_scanner (name, 0);
return SANE_STATUS_GOOD;
}
/* Find our devices */
SANE_Status
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
{
char config_line[PATH_MAX];
size_t len;
FILE *fp;
DBG_INIT ();
#if 0
DBG_LEVEL = 10;
#endif
DBG (2, "sane_init: version_code %s 0, authorize %s 0\n",
version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!=");
DBG (1, "sane_init: SANE Canon LiDE70 backend version %d.%d.%d from %s\n",
V_MAJOR, V_MINOR, BUILD, PACKAGE_STRING);
if (version_code)
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BUILD);
sanei_usb_init ();
fp = sanei_config_open (CANONUSB_CONFIG_FILE);
if (!fp)
{
/* no config-file: try these */
attach_scanner ("/dev/scanner", 0);
attach_scanner ("/dev/usbscanner", 0);
attach_scanner ("/dev/usb/scanner", 0);
return SANE_STATUS_GOOD;
}
DBG (3, "reading configure file %s\n", CANONUSB_CONFIG_FILE);
while (sanei_config_read (config_line, sizeof (config_line), fp))
{
if (config_line[0] == '#')
continue; /* ignore line comments */
len = strlen (config_line);
if (!len)
continue; /* ignore empty lines */
DBG (4, "attach_matching_devices(%s)\n", config_line);
sanei_usb_attach_matching_devices (config_line, attach_one);
}
DBG (4, "finished reading configure file\n");
fclose (fp);
return SANE_STATUS_GOOD;
}
void
sane_exit (void)
{
Canon_Device *dev, *next;
DBG (3, "sane_exit\n");
for (dev = first_dev; dev; dev = next)
{
next = dev->next;
free (dev->name);
free (dev);
}
if (devlist)
free (devlist);
return;
}
SANE_Status
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
{
Canon_Device *dev;
int i;
DBG (3, "sane_get_devices(local_only = %d)\n", local_only);
if (devlist)
free (devlist);
devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
if (!devlist)
return SANE_STATUS_NO_MEM;
i = 0;
for (dev = first_dev; i < num_devices; dev = dev->next)
devlist[i++] = &dev->sane;
devlist[i++] = 0;
*device_list = devlist;
return SANE_STATUS_GOOD;
}
static SANE_Status
init_options (CANON_Handle * chndl)
{
SANE_Option_Descriptor *od;
DBG (2, "begin init_options: chndl=%p\n", (void *) chndl);
/* opt_num_opts */
od = &chndl->opt[opt_num_opts];
od->name = "";
od->title = SANE_TITLE_NUM_OPTIONS;
od->desc = SANE_DESC_NUM_OPTIONS;
od->type = SANE_TYPE_INT;
od->unit = SANE_UNIT_NONE;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_num_opts].w = num_options;
DBG (2, "val[opt_num_opts]: %d\n", chndl->val[opt_num_opts].w);
/* opt_mode_group */
od = &chndl->opt[opt_mode_group];
od->name = "";
od->title = SANE_I18N ("Scan Mode");
od->desc = "";
od->type = SANE_TYPE_GROUP;
od->unit = SANE_UNIT_NONE;
od->size = 0;
od->cap = 0;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_mode_group].w = 0;
/* opt_mode */
od = &chndl->opt[opt_mode];
od->name = SANE_NAME_SCAN_MODE;
od->title = SANE_TITLE_SCAN_MODE;
od->desc = SANE_DESC_SCAN_MODE;
od->type = SANE_TYPE_STRING;
od->unit = SANE_UNIT_NONE;
od->size = max_string_size (mode_list);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_STRING_LIST;
od->constraint.string_list = mode_list;
chndl->val[opt_mode].s = malloc (od->size);
if (!chndl->val[opt_mode].s)
return SANE_STATUS_NO_MEM;
strcpy (chndl->val[opt_mode].s, init_mode);
chndl->graymode = init_graymode;
/* opt_threshold */
od = &chndl->opt[opt_threshold];
od->name = SANE_NAME_THRESHOLD;
od->title = SANE_TITLE_THRESHOLD;
od->desc = SANE_DESC_THRESHOLD;
od->type = SANE_TYPE_INT;
od->unit = SANE_UNIT_PERCENT;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &threshold_range;
chndl->val[opt_threshold].w = init_threshold;
/* opt_resolution */
od = &chndl->opt[opt_resolution];
od->name = SANE_NAME_SCAN_RESOLUTION;
od->title = SANE_TITLE_SCAN_RESOLUTION;
od->desc = SANE_DESC_SCAN_RESOLUTION;
od->type = SANE_TYPE_INT;
od->unit = SANE_UNIT_DPI;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_WORD_LIST;
od->constraint.word_list = resolution_list;
chndl->val[opt_resolution].w = init_resolution;
/* opt_non_blocking */
od = &chndl->opt[opt_non_blocking];
od->name = "non-blocking";
od->title = SANE_I18N ("Use non-blocking IO");
od->desc = SANE_I18N ("Use non-blocking IO for sane_read() if supported "
"by the frontend.");
od->type = SANE_TYPE_BOOL;
od->unit = SANE_UNIT_NONE;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_non_blocking].w = init_non_blocking;
/* opt_geometry_group */
od = &chndl->opt[opt_geometry_group];
od->name = "";
od->title = SANE_I18N ("Geometry");
od->desc = "";
od->type = SANE_TYPE_GROUP;
od->unit = SANE_UNIT_NONE;
od->size = 0;
od->cap = 0;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_geometry_group].w = 0;
/* opt_tl_x */
od = &chndl->opt[opt_tl_x];
od->name = SANE_NAME_SCAN_TL_X;
od->title = SANE_TITLE_SCAN_TL_X;
od->desc = SANE_DESC_SCAN_TL_X;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &widthRange;
chndl->val[opt_tl_x].w = init_tl_x;
/* opt_tl_y */
od = &chndl->opt[opt_tl_y];
od->name = SANE_NAME_SCAN_TL_Y;
od->title = SANE_TITLE_SCAN_TL_Y;
od->desc = SANE_DESC_SCAN_TL_Y;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &heightRange;
chndl->val[opt_tl_y].w = init_tl_y;
/* opt_br_x */
od = &chndl->opt[opt_br_x];
od->name = SANE_NAME_SCAN_BR_X;
od->title = SANE_TITLE_SCAN_BR_X;
od->desc = SANE_DESC_SCAN_BR_X;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &widthRange;
chndl->val[opt_br_x].w = init_br_x;
/* opt_br_y */
od = &chndl->opt[opt_br_y];
od->name = SANE_NAME_SCAN_BR_Y;
od->title = SANE_TITLE_SCAN_BR_Y;
od->desc = SANE_DESC_SCAN_BR_Y;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &heightRange;
chndl->val[opt_br_y].w = init_br_y;
DBG (2, "end init_options: chndl=%p\n", (void *) chndl);
return SANE_STATUS_GOOD;
}
SANE_Status
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
{
Canon_Device *dev;
SANE_Status status;
Canon_Scanner *scanner;
DBG (3, "sane_open\n");
if (devicename[0]) /* search for devicename */
{
DBG (4, "sane_open: devicename=%s\n", devicename);
for (dev = first_dev; dev; dev = dev->next)
if (strcmp (dev->sane.name, devicename) == 0)
break;
if (!dev)
{
status = attach_scanner (devicename, &dev);
if (status != SANE_STATUS_GOOD)
return status;
}
}
else
{
DBG (2, "sane_open: no devicename, opening first device\n");
dev = first_dev;
}
if (!dev)
return SANE_STATUS_INVAL;
scanner = malloc (sizeof (*scanner));
if (!scanner)
return SANE_STATUS_NO_MEM;
memset (scanner, 0, sizeof (*scanner));
scanner->device = dev;
status = CANON_open_device (&scanner->scan, dev->sane.name);
if (status != SANE_STATUS_GOOD)
{
free (scanner);
return status;
}
status = init_options (&scanner->scan);
*handle = scanner;
/* insert newly opened handle into list of open handles: */
scanner->next = first_handle;
first_handle = scanner;
return status;
}
static void
print_options (CANON_Handle * chndl)
{
SANE_Option_Descriptor *od;
SANE_Word option_number;
SANE_Char caps[1024];
for (option_number = 0; option_number < num_options; option_number++)
{
od = &chndl->opt[option_number];
DBG (50, "-----> number: %d\n", option_number);
DBG (50, " name: `%s'\n", od->name);
DBG (50, " title: `%s'\n", od->title);
DBG (50, " description: `%s'\n", od->desc);
DBG (50, " type: %s\n",
od->type == SANE_TYPE_BOOL ? "SANE_TYPE_BOOL" :
od->type == SANE_TYPE_INT ? "SANE_TYPE_INT" :
od->type == SANE_TYPE_FIXED ? "SANE_TYPE_FIXED" :
od->type == SANE_TYPE_STRING ? "SANE_TYPE_STRING" :
od->type == SANE_TYPE_BUTTON ? "SANE_TYPE_BUTTON" :
od->type == SANE_TYPE_GROUP ? "SANE_TYPE_GROUP" : "unknown");
DBG (50, " unit: %s\n",
od->unit == SANE_UNIT_NONE ? "SANE_UNIT_NONE" :
od->unit == SANE_UNIT_PIXEL ? "SANE_UNIT_PIXEL" :
od->unit == SANE_UNIT_BIT ? "SANE_UNIT_BIT" :
od->unit == SANE_UNIT_MM ? "SANE_UNIT_MM" :
od->unit == SANE_UNIT_DPI ? "SANE_UNIT_DPI" :
od->unit == SANE_UNIT_PERCENT ? "SANE_UNIT_PERCENT" :
od->unit == SANE_UNIT_MICROSECOND ? "SANE_UNIT_MICROSECOND" :
"unknown");
DBG (50, " size: %d\n", od->size);
caps[0] = '\0';
if (od->cap & SANE_CAP_SOFT_SELECT)
strcat (caps, "SANE_CAP_SOFT_SELECT ");
if (od->cap & SANE_CAP_HARD_SELECT)
strcat (caps, "SANE_CAP_HARD_SELECT ");
if (od->cap & SANE_CAP_SOFT_DETECT)
strcat (caps, "SANE_CAP_SOFT_DETECT ");
if (od->cap & SANE_CAP_EMULATED)
strcat (caps, "SANE_CAP_EMULATED ");
if (od->cap & SANE_CAP_AUTOMATIC)
strcat (caps, "SANE_CAP_AUTOMATIC ");
if (od->cap & SANE_CAP_INACTIVE)
strcat (caps, "SANE_CAP_INACTIVE ");
if (od->cap & SANE_CAP_ADVANCED)
strcat (caps, "SANE_CAP_ADVANCED ");
DBG (50, " capabilities: %s\n", caps);
DBG (50, "constraint type: %s\n",
od->constraint_type == SANE_CONSTRAINT_NONE ?
"SANE_CONSTRAINT_NONE" :
od->constraint_type == SANE_CONSTRAINT_RANGE ?
"SANE_CONSTRAINT_RANGE" :
od->constraint_type == SANE_CONSTRAINT_WORD_LIST ?
"SANE_CONSTRAINT_WORD_LIST" :
od->constraint_type == SANE_CONSTRAINT_STRING_LIST ?
"SANE_CONSTRAINT_STRING_LIST" : "unknown");
if (od->type == SANE_TYPE_INT)
DBG (50, " value: %d\n", chndl->val[option_number].w);
else if (od->type == SANE_TYPE_FIXED)
DBG (50, " value: %f\n",
SANE_UNFIX (chndl->val[option_number].w));
else if (od->type == SANE_TYPE_STRING)
DBG (50, " value: %s\n", chndl->val[option_number].s);
}
}
void
sane_close (SANE_Handle handle)
{
Canon_Scanner *prev, *scanner;
SANE_Status res;
DBG (3, "sane_close\n");
scanner = handle;
print_options (&scanner->scan);
if (!first_handle)
{
DBG (1, "ERROR: sane_close: no handles opened\n");
return;
}
/* remove handle from list of open handles: */
prev = NULL;
for (scanner = first_handle; scanner; scanner = scanner->next)
{
if (scanner == handle)
break;
prev = scanner;
}
if (!scanner)
{
DBG (1, "ERROR: sane_close: invalid handle %p\n", handle);
return; /* oops, not a handle we know about */
}
if (prev)
prev->next = scanner->next;
else
first_handle = scanner->next;
res = CANON_close_device (&scanner->scan);
DBG (3, "CANON_close_device returned: %d\n", res);
free (scanner);
}
const SANE_Option_Descriptor *
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
{
Canon_Scanner *scanner = handle;
CANON_Handle *chndl = &scanner->scan;
DBG (4, "sane_get_option_descriptor: handle=%p, option = %d\n",
(void *) handle, option);
if (option < 0 || option >= num_options)
{
DBG (3, "sane_get_option_descriptor: option < 0 || "
"option > num_options\n");
return 0;
}
return &chndl->opt[option];
}
SANE_Status
sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
void *value, SANE_Int * info)
{
Canon_Scanner *scanner = handle;
CANON_Handle *chndl = &scanner->scan;
SANE_Int myinfo = 0;
SANE_Status status;
DBG (4, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
(void *) handle, option, action, (void *) value, (void *) info);
if (option < 0 || option >= num_options)
{
DBG (1, "sane_control_option: option < 0 || option > num_options\n");
return SANE_STATUS_INVAL;
}
if (!SANE_OPTION_IS_ACTIVE (chndl->opt[option].cap))
{
DBG (1, "sane_control_option: option is inactive\n");
return SANE_STATUS_INVAL;
}
if (chndl->opt[option].type == SANE_TYPE_GROUP)
{
DBG (1, "sane_control_option: option is a group\n");
return SANE_STATUS_INVAL;
}
switch (action)
{
case SANE_ACTION_SET_VALUE:
if (!SANE_OPTION_IS_SETTABLE (chndl->opt[option].cap))
{
DBG (1, "sane_control_option: option is not setable\n");
return SANE_STATUS_INVAL;
}
status = sanei_constrain_value (&chndl->opt[option], value, &myinfo);
if (status != SANE_STATUS_GOOD)
{
DBG (3, "sane_control_option: sanei_constrain_value returned %s\n",
sane_strstatus (status));
return status;
}
switch (option)
{
case opt_tl_x: /* Fixed with parameter reloading */
case opt_tl_y:
case opt_br_x:
case opt_br_y:
if (chndl->val[option].w == *(SANE_Fixed *) value)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
chndl->val[option].w = *(SANE_Fixed *) value;
myinfo |= SANE_INFO_RELOAD_PARAMS;
DBG (4, "sane_control_option: set option %d (%s) to %.0f %s\n",
option, chndl->opt[option].name,
SANE_UNFIX (*(SANE_Fixed *) value),
chndl->opt[option].unit == SANE_UNIT_MM ? "mm" : "dpi");
break;
case opt_non_blocking:
if (chndl->val[option].w == *(SANE_Bool *) value)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
chndl->val[option].w = *(SANE_Bool *) value;
DBG (4, "sane_control_option: set option %d (%s) to %s\n",
option, chndl->opt[option].name,
*(SANE_Bool *) value == SANE_TRUE ? "true" : "false");
break;
case opt_resolution:
case opt_threshold:
if (chndl->val[option].w == *(SANE_Int *) value)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
chndl->val[option].w = *(SANE_Int *) value;
myinfo |= SANE_INFO_RELOAD_PARAMS;
myinfo |= SANE_INFO_RELOAD_OPTIONS;
DBG (4, "sane_control_option: set option %d (%s) to %d\n",
option, chndl->opt[option].name, *(SANE_Int *) value);
break;
case opt_mode:
if (strcmp (chndl->val[option].s, value) == 0)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
strcpy (chndl->val[option].s, (SANE_String) value);
if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) ==
0)
{
chndl->opt[opt_threshold].cap &= ~SANE_CAP_INACTIVE;
chndl->graymode = 2;
}
if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
{
chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE;
chndl->graymode = 0;
}
if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
{
chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE;
chndl->graymode = 1;
}
myinfo |= SANE_INFO_RELOAD_PARAMS;
myinfo |= SANE_INFO_RELOAD_OPTIONS;
DBG (4, "sane_control_option: set option %d (%s) to %s\n",
option, chndl->opt[option].name, (SANE_String) value);
break;
default:
DBG (1, "sane_control_option: trying to set unexpected option\n");
return SANE_STATUS_INVAL;
}
break;
case SANE_ACTION_GET_VALUE:
switch (option)
{
case opt_num_opts:
*(SANE_Word *) value = num_options;
DBG (4, "sane_control_option: get option 0, value = %d\n",
num_options);
break;
case opt_tl_x: /* Fixed options */
case opt_tl_y:
case opt_br_x:
case opt_br_y:
{
*(SANE_Fixed *) value = chndl->val[option].w;
DBG (4,
"sane_control_option: get option %d (%s), value=%.1f %s\n",
option, chndl->opt[option].name,
SANE_UNFIX (*(SANE_Fixed *) value),
chndl->opt[option].unit ==
SANE_UNIT_MM ? "mm" : SANE_UNIT_DPI ? "dpi" : "");
break;
}
case opt_non_blocking:
*(SANE_Bool *) value = chndl->val[option].w;
DBG (4,
"sane_control_option: get option %d (%s), value=%s\n",
option, chndl->opt[option].name,
*(SANE_Bool *) value == SANE_TRUE ? "true" : "false");
break;
case opt_mode: /* String (list) options */
strcpy (value, chndl->val[option].s);
DBG (4, "sane_control_option: get option %d (%s), value=`%s'\n",
option, chndl->opt[option].name, (SANE_String) value);
break;
case opt_resolution:
case opt_threshold:
*(SANE_Int *) value = chndl->val[option].w;
DBG (4, "sane_control_option: get option %d (%s), value=%d\n",
option, chndl->opt[option].name, *(SANE_Int *) value);
break;
default:
DBG (1, "sane_control_option: trying to get unexpected option\n");
return SANE_STATUS_INVAL;
}
break;
default:
DBG (1, "sane_control_option: trying unexpected action %d\n", action);
return SANE_STATUS_INVAL;
}
if (info)
*info = myinfo;
return SANE_STATUS_GOOD;
}
SANE_Status
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
{
Canon_Scanner *hndl = handle; /* Eliminate compiler warning */
CANON_Handle *chndl = &hndl->scan;
int rc = SANE_STATUS_GOOD;
int w = SANE_UNFIX (chndl->val[opt_br_x].w -
chndl->val[opt_tl_x].w) / MM_IN_INCH *
chndl->val[opt_resolution].w;
int h =
SANE_UNFIX (chndl->val[opt_br_y].w -
chndl->val[opt_tl_y].w) / MM_IN_INCH *
chndl->val[opt_resolution].w;
DBG (3, "sane_get_parameters\n");
chndl->params.depth = 8;
chndl->params.last_frame = SANE_TRUE;
chndl->params.pixels_per_line = w;
chndl->params.lines = h;
if (chndl->graymode == 1)
{
chndl->params.format = SANE_FRAME_GRAY;
chndl->params.bytes_per_line = w;
}
else if (chndl->graymode == 2)
{
chndl->params.format = SANE_FRAME_GRAY;
w /= 8;
if ((chndl->params.pixels_per_line % 8) != 0)
w++;
chndl->params.bytes_per_line = w;
chndl->params.depth = 1;
}
else
{
chndl->params.format = SANE_FRAME_RGB;
chndl->params.bytes_per_line = w * 3;
}
*params = chndl->params;
DBG (1, "%d\n", chndl->params.format);
return rc;
}
SANE_Status
sane_start (SANE_Handle handle)
{
Canon_Scanner *scanner = handle;
CANON_Handle *chndl = &scanner->scan;
SANE_Status res;
DBG (3, "sane_start\n");
res = sane_get_parameters (handle, &chndl->params);
res = CANON_set_scan_parameters (&scanner->scan);
if (res != SANE_STATUS_GOOD)
return res;
return CANON_start_scan (&scanner->scan);
}
SANE_Status
sane_read (SANE_Handle handle, SANE_Byte * data,
SANE_Int max_length, SANE_Int * length)
{
Canon_Scanner *scanner = handle;
return CANON_read (&scanner->scan, data, max_length, length);
}
void
sane_cancel (SANE_Handle handle)
{
DBG (3, "sane_cancel: handle = %p\n", handle);
DBG (3, "sane_cancel: cancelling is unsupported in this backend\n");
}
SANE_Status
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
{
DBG (3, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle,
non_blocking);
if (non_blocking != SANE_FALSE)
return SANE_STATUS_UNSUPPORTED;
return SANE_STATUS_GOOD;
}
SANE_Status
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
{
handle = handle; /* silence gcc */
fd = fd; /* silence gcc */
return SANE_STATUS_UNSUPPORTED;
}

Wyświetl plik

@ -0,0 +1,8 @@
# Options for the canon_lide70 backend
# Autodetect the Canon CanoScan LiDE 70
usb 0x04a9 0x2225
# device list for non-linux-systems (enable if autodetect fails):
#/dev/scanner
#/dev/usb/scanner0

Wyświetl plik

@ -19,6 +19,7 @@ bh
canon
canon630u
canon_dr
canon_lide70
#canon_pp
cardscan
coolscan

Wyświetl plik

@ -665,7 +665,7 @@ AC_ARG_ENABLE(local-backends,
[turn off compilation of all backends but net]))
ALL_BACKENDS="abaton agfafocus apple artec artec_eplus48u as6e \
avision bh canon canon630u canon_dr canon_pp cardscan \
avision bh canon canon630u canon_dr canon_lide70 canon_pp cardscan \
coolscan coolscan2 coolscan3 dc25 dc210 dc240 \
dell1600n_net dmc epjitsu epson epson2 epsonds escl fujitsu \
genesys gphoto2 gt68xx hp hp3500 hp3900 hp4200 hp5400 \

Wyświetl plik

@ -18,6 +18,7 @@ EXTRA_DIST = scanimage.man sane-config.man sane-find-scanner.man \
# custom install/uninstall if we required man pages for every backend.
BACKEND_5MANS = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 \
sane-canon_lide70.5 \
sane-dll.5 sane-dc25.5 sane-dmc.5 sane-epson.5 sane-epson2.5 sane-epsonds.5 \
sane-escl.5 sane-hp.5 sane-gphoto2.5 sane-leo.5 sane-lexmark.5 \
sane-matsushita.5 sane-microtek.5 sane-microtek2.5 sane-mustek.5 \
@ -40,6 +41,7 @@ BACKEND_5MANS = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 \
sane-kvs40xx.5 sane-p5.5 sane-magicolor.5
EXTRA_DIST += sane-abaton.man sane-agfafocus.man sane-apple.man sane-as6e.man \
sane-canon_lide70.man \
sane-dll.man sane-dc25.man sane-dmc.man sane-epson.man \
sane-epson2.man sane-epsonds.man sane-escl.man sane-hp.man sane-gphoto2.man \
sane-leo.man sane-lexmark.man sane-matsushita.man sane-microtek.man \
@ -150,6 +152,7 @@ DESC_FILES = descriptions/abaton.desc descriptions/agfafocus.desc \
descriptions/artec_eplus48u.desc descriptions/as6e.desc \
descriptions/avision.desc descriptions/bh.desc descriptions/canon630u.desc \
descriptions/canon.desc descriptions/canon_dr.desc \
descriptions/canon_lide70.desc \
descriptions/canon_pp.desc descriptions/cardscan.desc \
descriptions/coolscan2.desc descriptions/coolscan.desc \
descriptions/coolscan3.desc \

Wyświetl plik

@ -0,0 +1,28 @@
;
; SANE Backend specification file
;
; It's basically emacs-lisp --- so ";" indicates comment to end of line.
; All syntactic elements are keyword tokens, followed by a string or
; keyword argument, as specified.
;
; ":backend" *must* be specified.
; All other information is optional (but what good is the file without it?).
;
:backend "canon_lide70" ; name of backend
:url "http://www.juergen-ernst.de/info_sane.html"
:version "0" ; version of backend
:manpage "sane-canon_lide70" ; name of manpage (if it exists)
:devicetype :scanner ; start of a list of devices....
; other types: :stillcam, :vidcam,
; :meta, :api
:mfg "Canon" ; name a manufacturer
:url "http://www.canon.com/"
;==================================================
:model "CanoScan LiDE 70"
:interface "USB"
:usbid "0x04a9" "0x2225"
:status :basic
:comment "Please test!"

Wyświetl plik

@ -395,13 +395,6 @@
:status :unsupported
:comment "Not supported. However, a stand-alone program for FreeBSD is available."
:model "CanoScan LiDE 70"
:url "http://www.juergen-ernst.de/info_sane.html"
:interface "USB"
:usbid "0x04a9" "0x2225"
:status :unsupported
:comment "Philips chip. Backend started, see link"
:model "CanoScan LiDE 90"
:url "unsupported/canon-lide-90.html"
:interface "USB"

Wyświetl plik

@ -0,0 +1,105 @@
.TH sane\-canon_lide70 5 "26 Nov 2019" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy"
.IX sane\-canon_lide70
.SH NAME
sane\-canon_lide70 \- SANE backend for the Canon LiDE 70 USB flatbed scanner
.SH DESCRIPTION
The
.B canon_lide70
library implements a SANE (Scanner Access Now Easy) backend that
provides access to the Canon Inc. CanoScan LiDE 70 flatbed scanner.
.PP
Due to Canon's unwillingness to provide scanner documentation, this
software was developed by analyzing the USB traffic of the Windows
XP driver. The precise meaning of the individual commands that are sent
to the scanner is known only to a very limited extent. Some sophistication
present in the Windows XP driver has been left out. There is, for example,
no active calibration.
.PP
TESTERS ARE WELCOME. Send your bug reports and comments to
the sane\-devel mailing list <sane\-devel@alioth-lists.debian.net>
.PP
The
.B Canoscan LiDE 600
(or 600f, with film unit) is closely related to the LiDE 70, but
it probably will not work with this backend. The framework of this canon_lide70
backend could likely be used to develop a backend for the LiDE 600 without too
much difficulty.
.PP
.SH CONFIGURATION
The
.I @CONFIGDIR@/canon_lide70.conf
file identifies the LiDE 70 by its vendor code 0x04a9 and its
product code 0x2225. For the LiDE 600(f) the product code would be 0x2224.
.PP
.SH BACKEND SPECIFIC OPTIONS
.PP
.B Scan Mode:
.TP
\-\-resolution 75|150|300|600|1200 [default 600]
.BR
Sets the resolution of the scanned image in dots per inch. Scanning at 1200 dpi is very slow.
.TP
\-\-mode Color|Gray|Lineart [default: Color]
.BR
Selects the scan mode. Lineart means fully black and fully white pixels only.
.TP
\-\-threshold 0..100 (in steps of 1) [default 75]
.BR
Select minimum-brightness percentage to get a white point, relevant only for Lineart
.TP
\-\-non-blocking[=(yes|no)] [inactive]
.BR
This option has not yet been implemented. Scans are captured in a temporary file with a typical size of 100MB.
.PP
.B Geometry:
.TP
\-l 0..216.069 [default 0]
Top-left x position of scan area in millimeters.
.TP
\-t 0..297 [default 0]
Top-left y position of scan area in millimeters.
.TP
\-x 0..216.069 [default 80]
Width of scan-area in millimeters.
.TP
\-y 0..297 [default 100]
Height of scan-area in millimeters.
.PP
.SH FILES
.TP
.I @CONFIGDIR@/canon_lide70.conf
The backend configuration file
.TP
.I @LIBDIR@/libsane\-canon_lide70.a
The static library implementing this backend.
.TP
.I @LIBDIR@/libsane\-canon_lide70.so
The shared library implementing this backend (present on systems that
support dynamic loading).
.SH ENVIRONMENT
.TP
.B SANE_DEBUG_CANON_LIDE70
If the library was compiled with debug support enabled, this
environment variable controls the debug level for this backend. Higher
debug levels increase the verbosity of the output.
Example:
.br
SANE_DEBUG_CANON_LIDE70=128 scanimage > /dev/null
.SH KNOWN PROBLEMS
At low resolutions (75 and 150 dpi, implying high slider speeds)
the scanner misses the top one millimeter of the scan area. This can
be remedied by shifting the document one millimeter downward, in cases
where such precision matters. Note that xsane uses the 75 dpi mode for
prescans.
.PP
It is recommended that in xsane the gamma value be set to approximately 2.0
to get more realistic colors. This also wipes out some artifacts caused by
the lack of real calibration.
.SH "SEE ALSO"
sane(7), sane\-usb(5), sane\-find\-scanner(1), scanimage(1)
.br
http://www.juergen-ernst.de/info_sane.html
.br
.SH AUTHOR
pimvantend, building upon pioneering work by Juergen Ernst.

Wyświetl plik

@ -20,6 +20,7 @@ backend/canon-sane.c
backend/canon.c
backend/canon630u.c
backend/canon_dr.c
backend/canon_lide70.c
backend/epjitsu.c
backend/epson.c
backend/epson.h