aboutsummaryrefslogtreecommitdiff
path: root/frontend/pisa_sane_scan.cc
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/pisa_sane_scan.cc')
-rw-r--r--frontend/pisa_sane_scan.cc1214
1 files changed, 1214 insertions, 0 deletions
diff --git a/frontend/pisa_sane_scan.cc b/frontend/pisa_sane_scan.cc
new file mode 100644
index 0000000..7a60ab3
--- /dev/null
+++ b/frontend/pisa_sane_scan.cc
@@ -0,0 +1,1214 @@
+/* pisa_sane_scan.cc
+ Copyright (C) 2001, 2004, 2005, 2008, 2009 SEIKO EPSON CORPORATION
+
+ This file is part of the `iscan' program.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ As a special exception, the copyright holders give permission
+ to link the code of this program with the esmod library and
+ distribute linked combinations including the two. You must obey
+ the GNU General Public License in all respects for all of the
+ code used other then esmod.
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string>
+
+#include "pisa_sane_scan.h"
+#include "pisa_error.h"
+#include "pisa_change_unit.h"
+#include "pisa_enums.h"
+
+
+#define MM_PER_INCH 25.4
+
+#define SCSI_STR "SCSI"
+#define PIO_STR "PIO"
+#define USB_STR "USB"
+
+
+bool
+sane_scan::has_flatbed (void) const
+{
+ return (PISA_OP_FLATBED & support_option);
+}
+
+void
+sane_scan::select_flatbed (void)
+{
+ if (!has_flatbed ()) return;
+
+ _source = PISA_OP_FLATBED;
+ _film = PISA_FT_REFLECT;
+}
+
+bool
+sane_scan::using_flatbed (void) const
+{
+ return (PISA_OP_FLATBED == _source);
+}
+
+bool
+sane_scan::has_adf (void) const
+{
+ return ((PISA_OP_ADF | PISA_OP_ADFDPLX) & support_option);
+}
+
+void
+sane_scan::select_adf (bool duplex)
+{
+ if (!has_duplex ()) duplex = false;
+ if (!has_adf ()) return;
+
+ _source = (duplex ? PISA_OP_ADFDPLX : PISA_OP_ADF);
+ _film = PISA_FT_REFLECT;
+}
+
+bool
+sane_scan::using_adf (void) const
+{
+ return (PISA_OP_ADF == _source || PISA_OP_ADFDPLX == _source);
+}
+
+bool
+sane_scan::has_duplex (void) const
+{
+ return (PISA_OP_ADFDPLX & support_option);
+}
+
+bool
+sane_scan::using_duplex (void) const
+{
+ return (PISA_OP_ADFDPLX == _source);
+}
+
+bool
+sane_scan::has_tpu (void) const
+{
+ return (PISA_OP_TPU & support_option);
+}
+
+void
+sane_scan::select_tpu (bool positive)
+{
+ if (!has_tpu ()) return;
+
+ _source = PISA_OP_TPU;
+ _film = (positive ? PISA_FT_POSI : PISA_FT_NEGA);
+}
+
+bool
+sane_scan::using_tpu (void) const
+{
+ return (PISA_OP_TPU == _source);
+}
+
+bool
+sane_scan::has_dfd (void) const
+{
+ const SANE_Option_Descriptor *sod = NULL;
+ int id = 0;
+
+ try {
+ id = get_option_id ("double-feed-detection-sensitivity");
+ sod = sane_get_option_descriptor (m_hdevice, id);
+ return (sod && !(SANE_CAP_INACTIVE & sod->cap));
+ }
+ catch (pisa_error& e) {
+ if (pisa_error (PISA_ERR_UNSUPPORT) == e) return false;
+ throw e;
+ }
+}
+
+void
+sane_scan::set_dfd (long idx)
+{
+ const SANE_Option_Descriptor *sod = NULL;
+ int id = get_option_id ("double-feed-detection-sensitivity");
+
+ sod = sane_get_option_descriptor (m_hdevice, id);
+ if (!sod
+ || SANE_CAP_INACTIVE & sod->cap
+ || SANE_TYPE_STRING != sod->type
+ || SANE_CONSTRAINT_STRING_LIST != sod->constraint_type)
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+
+ const SANE_String_Const *p = sod->constraint.string_list;
+ while (p && *p && ++p)
+ ;
+
+ if (idx < p - sod->constraint.string_list)
+ set_value ("double-feed-detection-sensitivity",
+ sod->constraint.string_list[idx]);
+ else
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+}
+
+char
+sane_scan::get_scan_source (void) const
+{
+ if (PISA_OP_NONE == _source)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ return _source;
+}
+
+char
+sane_scan::get_film_type (void) const
+{
+ return _film;
+}
+
+void
+sane_scan::clear_button_status (void)
+{
+ // We (re)set the scan source. This indirectly resets the scanner's
+ // push button status. I'd like to do something less kludgy but for
+ // the moment can't think of anything better :-(
+ set_scan_source ();
+}
+
+void
+sane_scan::init (void)
+{
+ m_hdevice = 0;
+
+ name = 0;
+ max_resolution = -1;
+
+ _source = PISA_OP_NONE;
+ _film = PISA_FT_REFLECT;
+
+ atexit (sane_exit);
+ sane_init (0, 0);
+}
+
+void
+sane_scan::open_device (char *name)
+{
+ SANE_Status status;
+ char *device_name = 0;
+
+ if (!name)
+ {
+ device_name = new char[64];
+ query_device (device_name);
+ }
+ else
+ device_name = name;
+
+ SANE_Handle device;
+ status = sane_open (device_name, &device);
+
+ if (SANE_STATUS_GOOD != status)
+ {
+ if (device_name != name)
+ delete[] device_name;
+ throw pisa_error (status);
+ }
+
+ // we successfully opened a new device, now close whatever we are
+ // hanging onto and rebind to the newly opened device
+
+ close_device ();
+ m_hdevice = device;
+
+ get_scanner_info (device_name);
+
+ if (device_name != name)
+ delete[] device_name;
+}
+
+void
+sane_scan::close_device (void)
+{
+ if (m_hdevice)
+ sane_close (m_hdevice);
+
+ m_hdevice = 0;
+}
+
+void
+sane_scan::set_scan_source (void)
+{
+ if (!m_hdevice)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ char source[32];
+
+ if (using_flatbed ())
+ strcpy (source, "Flatbed");
+ else if (using_adf ())
+ strcpy (source, "Automatic Document Feeder");
+ else if (using_tpu ())
+ strcpy (source, "Transparency Unit");
+ else
+ throw pisa_error (PISA_ERR_PARAMETER);
+
+ set_value (SANE_NAME_SCAN_SOURCE, source);
+
+ if (using_adf ())
+ {
+ char mode[16];
+
+ strcpy (mode, (using_duplex () ? "Duplex" : "Simplex"));
+ set_value ("adf-mode", mode);
+ }
+
+ max_resolution = -1;
+}
+
+void
+sane_scan::set_film_type (void)
+{
+ char film_type[32];
+
+ switch (_film)
+ {
+ case PISA_FT_POSI:
+ strcpy (film_type, "Positive Film");
+ break;
+
+ case PISA_FT_NEGA:
+ strcpy (film_type, "Negative Film");
+ break;
+
+ case PISA_FT_REFLECT:
+ return;
+ }
+
+ set_value ("film-type", (void *) film_type);
+}
+
+void
+sane_scan::get_current_max_size (double *width, double *height)
+{
+ SANE_Int max_x = 0;
+ SANE_Int max_y = 0;
+
+ if (!m_hdevice)
+ throw pisa_error ( PISA_ERR_CONNECT);
+
+ set_scan_source ();
+ set_film_type ();
+
+ int opt_id = 0;
+ const SANE_Option_Descriptor *opt_desc = NULL;
+
+ opt_id = get_option_id (SANE_NAME_SCAN_BR_X);
+ opt_desc = sane_get_option_descriptor (m_hdevice, opt_id);
+ if (!opt_desc || SANE_CONSTRAINT_RANGE != opt_desc->constraint_type)
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+
+ max_x = opt_desc->constraint.range->max;
+
+ opt_id = get_option_id (SANE_NAME_SCAN_BR_Y);
+ opt_desc = sane_get_option_descriptor (m_hdevice, opt_id);
+ if (!opt_desc || SANE_CONSTRAINT_RANGE != opt_desc->constraint_type)
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+
+ max_y = opt_desc->constraint.range->max;
+
+ *width = SANE_UNFIX (max_x) / MM_PER_INCH;
+ *height = SANE_UNFIX (max_y) / MM_PER_INCH;
+}
+
+
+void
+sane_scan::get_color_profile (double *coef) const
+{
+ SANE_Word value;
+ char option_name[16];
+ int i;
+
+ if (!m_hdevice)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ for (i = 0; i < 9; i++)
+ {
+ sprintf (option_name, "cct-%d", i + 1);
+ get_value (option_name, (void *) &value);
+ coef[i] = SANE_UNFIX (value);
+ }
+}
+
+void
+sane_scan::start_scan (int * width, int * height)
+{
+ SANE_Status status;
+
+ if (! m_hdevice)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ if (SANE_STATUS_GOOD != (status = sane_start (m_hdevice)))
+ {
+ pisa_error oops (status, *this);
+ if (!using_adf ()
+ || SANE_STATUS_NO_DOCS != status) sane_cancel (m_hdevice);
+ throw oops;
+ }
+
+ if (SANE_STATUS_GOOD != (status = sane_get_parameters (m_hdevice,
+ &m_sane_para)))
+ {
+ pisa_error oops (status, *this);
+ sane_cancel (m_hdevice);
+ throw oops;
+ }
+
+ *width = m_sane_para.pixels_per_line;
+ *height = m_sane_para.lines;
+
+ m_rows = 0;
+}
+
+SANE_Status
+sane_scan::acquire_image (unsigned char *img, int row_bytes,
+ int height, int cancel)
+{
+ if (!m_hdevice)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ SANE_Status status = SANE_STATUS_GOOD;
+ unsigned char *cur_pos = img;
+
+ for (int i = 0; i < height; i++, cur_pos += row_bytes)
+ {
+ m_rows++;
+ if (cancel)
+ {
+ sane_cancel (m_hdevice);
+ return SANE_STATUS_CANCELLED;
+ }
+
+ // The SANE standard does not promise to return as much data as
+ // we request, so we keep asking until we got all that we want.
+
+ int cnt = row_bytes;
+ int len = 0;
+ while (SANE_STATUS_GOOD == status && cnt > 0)
+ {
+ status = sane_read (m_hdevice, cur_pos + (row_bytes - cnt),
+ cnt, &len);
+
+ cnt -= len;
+ }
+
+ if (status == SANE_STATUS_EOF)
+ break;
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ throw pisa_error (status, *this);
+ }
+
+ }
+
+ return status;
+}
+
+/*! \brief Returns the largest resolution not larger than a \a cutoff.
+
+ Returns the largest supported hardware resolution that does not
+ exceed the \a cutoff. Passing a negative value for the \a cutoff,
+ which is the default, returns the maximum resolution supported by
+ the hardware.
+
+ Throws an unsupported exception when no suitable resolution can be
+ determined.
+ */
+long
+sane_scan::get_max_resolution (long cutoff) const
+{
+ if (0 > cutoff // use cached value if possible
+ && 0 < max_resolution)
+ return max_resolution;
+
+ long result = -1;
+
+ try
+ {
+ long r;
+
+ r = get_max_resolution (SANE_NAME_SCAN_X_RESOLUTION, cutoff);
+ if (r > result) result = r;
+ r = get_max_resolution (SANE_NAME_SCAN_Y_RESOLUTION, cutoff);
+ if (r > result) result = r;
+ }
+ catch (const pisa_error& e)
+ {
+ pisa_error expected (PISA_STATUS_UNSUPPORTED);
+
+ if (e != expected) throw;
+ }
+
+ if (0 > result)
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+
+ if (0 > cutoff // update cached value if necessary
+ && 0 > max_resolution)
+ const_cast <sane_scan *> (this)->max_resolution = result;
+
+ return result;
+}
+
+long
+sane_scan::get_max_resolution (SANE_String_Const option_name,
+ long cutoff) const
+{
+ int opt_id = get_option_id (option_name);
+
+ const SANE_Option_Descriptor
+ *opt_desc = sane_get_option_descriptor (m_hdevice, opt_id);
+
+ if (!opt_desc || SANE_TYPE_INT != opt_desc->type)
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+
+ long result = -1;
+
+ switch (opt_desc->constraint_type)
+ {
+ case SANE_CONSTRAINT_RANGE:
+ {
+ const SANE_Range *const range = opt_desc->constraint.range;
+
+ if (0 > cutoff) cutoff = range->max;
+ if (0 == range->quant)
+ {
+ result = cutoff;
+ }
+ else
+ { // relies on integer arithmetic
+ result = (((cutoff - range->min) / range->quant)
+ * range->quant) + range->min;
+ }
+ break;
+ }
+ case SANE_CONSTRAINT_WORD_LIST:
+ { // assumes list is in ascending order
+ const SANE_Word *list = opt_desc->constraint.word_list;
+
+ size_t last = list[0];
+
+ if (0 > cutoff) cutoff = list[last];
+ while (0 < last && cutoff < list[last])
+ {
+ --last;
+ }
+ if (0 < last) result = list[last];
+ break;
+ }
+ default:
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+ }
+
+ if (0 > result)
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+
+ return result;
+}
+
+long
+sane_scan::get_resolution (SANE_String_Const scan_direction,
+ int min_res) const
+{
+ SANE_Int def_res_tbl[] = { 75, 150, 300, 600, 1200 };
+ SANE_Int def_res_cnt = 4;
+
+ const SANE_Int *res_tbl;
+ SANE_Int res_cnt;
+
+ { // initialize resolution table
+ int opt_id = get_option_id (scan_direction);
+ const SANE_Option_Descriptor *opt_desc
+ = sane_get_option_descriptor (m_hdevice, opt_id);
+
+ if (opt_desc && SANE_CONSTRAINT_RANGE == opt_desc->constraint_type)
+ {
+ long res = min_res;
+ long min = opt_desc->constraint.range->min;
+ long max = opt_desc->constraint.range->max;
+
+ if (res < min) res = min;
+ if (res > max) res = max;
+
+ return res;
+ }
+ else if (opt_desc
+ && SANE_TYPE_INT == opt_desc->type
+ && SANE_CONSTRAINT_WORD_LIST == opt_desc->constraint_type)
+ {
+ res_cnt = opt_desc->constraint.word_list[0];
+ res_tbl = &(opt_desc->constraint.word_list[1]);
+ }
+ else
+ {
+ res_cnt = def_res_cnt;
+ res_tbl = def_res_tbl;
+
+ if (1200 == get_max_resolution ())
+ ++res_cnt;
+ }
+ }
+
+ { // find appropriate resolution
+ int i = 0;
+ while (i < res_cnt && res_tbl[i] < min_res)
+ {
+ ++i;
+ }
+ return (res_cnt == i ? 0 : res_tbl[i]);
+ }
+}
+
+void
+sane_scan::get_scanner_info (const char *dev_name)
+{
+ int i, opt_id;
+ const SANE_Option_Descriptor *opt_desc;
+ const char *fbf = "Flatbed";
+ const char *tpu = "Transparency Unit";
+ const char *adf = "Automatic Document Feeder";
+
+ if (dev_name)
+ {
+ char *copy = strdup (dev_name);
+ if (!copy)
+ throw pisa_error (PISA_STATUS_NO_MEM);
+
+ if (name)
+ free (name);
+ name = copy;
+ }
+ support_option = 0;
+ opt_id = get_option_id (SANE_NAME_SCAN_SOURCE);
+ opt_desc = sane_get_option_descriptor (m_hdevice, opt_id);
+
+ if (opt_desc->type != SANE_TYPE_STRING ||
+ opt_desc->constraint_type != SANE_CONSTRAINT_STRING_LIST)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ for (i = 0; opt_desc->constraint.string_list[i]; i++)
+ {
+ if (0 == strcmp (opt_desc->constraint.string_list[i], fbf))
+ {
+ support_option |= PISA_OP_FLATBED;
+ }
+ if (0 == strcmp (opt_desc->constraint.string_list[i], tpu))
+ {
+ support_option |= PISA_OP_TPU;
+ }
+ if (0 == strcmp (opt_desc->constraint.string_list[i], adf))
+ {
+ support_option |= PISA_OP_ADF;
+ }
+ }
+
+ if (PISA_OP_NONE == _source)
+ {
+ if (has_flatbed ())
+ _source = PISA_OP_FLATBED;
+ else if (has_adf ())
+ _source = PISA_OP_ADF;
+ else if (has_tpu ())
+ _source = PISA_OP_TPU;
+ else
+ throw pisa_error (PISA_ERR_CONNECT);
+ }
+
+ if (has_adf ())
+ {
+ char old = _source;
+ _source = PISA_OP_ADF;
+ set_scan_source ();
+ if (is_activate ("adf-mode"))
+ support_option |= PISA_OP_ADFDPLX;
+ _source = old;
+ }
+ set_scan_source ();
+
+ max_resolution = get_max_resolution ();
+}
+
+void
+sane_scan::query_device (char *device_name) const
+{
+ const SANE_Device ** ppdevice_list;
+ SANE_Status status;
+ int i;
+
+ status = sane_get_devices (& ppdevice_list, SANE_TRUE);
+
+ if (status != SANE_STATUS_GOOD)
+ throw pisa_error (status);
+
+ if (*ppdevice_list == 0 ||
+ ppdevice_list[0]->vendor == 0)
+ throw pisa_error (PISA_ERR_CONNECT);
+
+ for (i = 0; ppdevice_list[i]; i++)
+ {
+ if (0 == strcasecmp (ppdevice_list[i]->vendor, "epson"))
+ {
+ strcpy (device_name, ppdevice_list[i]->name);
+ return;
+ }
+ }
+
+ throw pisa_error (PISA_ERR_CONNECT);
+}
+
+void
+sane_scan::finish_acquire (bool eject)
+{
+ if (eject && using_adf ())
+ {
+ set_value ("eject", NULL);
+ }
+ sane_cancel (m_hdevice);
+}
+
+int
+sane_scan::is_activate (const char *option_name) const
+{
+ const SANE_Option_Descriptor * opt_desc;
+ SANE_Int num_dev_options;
+ SANE_Status status;
+ int i;
+ int ret;
+
+ ret = 0;
+ status = sane_control_option (m_hdevice, 0,
+ SANE_ACTION_GET_VALUE,
+ &num_dev_options,
+ 0);
+
+ if (status != SANE_STATUS_GOOD)
+ throw pisa_error (status, *this);
+
+ for (i = 0; i < num_dev_options; i++)
+ {
+ opt_desc = sane_get_option_descriptor (m_hdevice, i);
+
+ if (opt_desc->name && strcmp (opt_desc->name, option_name) == 0)
+ {
+ if (SANE_OPTION_IS_ACTIVE (opt_desc->cap))
+ {
+ ret = 1;
+ break;
+ }
+ else
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int
+sane_scan::get_option_id (const char *option_name) const
+{
+ const SANE_Option_Descriptor * opt_desc;
+ SANE_Int num_dev_options;
+ SANE_Status status;
+ int i;
+
+ status = sane_control_option (m_hdevice, 0,
+ SANE_ACTION_GET_VALUE,
+ &num_dev_options,
+ 0);
+
+ if (status != SANE_STATUS_GOOD)
+ throw pisa_error (status, *this);
+
+ for (i = 0; i < num_dev_options; i++)
+ {
+ opt_desc = sane_get_option_descriptor (m_hdevice, i);
+
+ if (opt_desc->name && strcmp (opt_desc->name, option_name) == 0)
+ return i; // found
+ }
+
+ throw pisa_error (PISA_ERR_UNSUPPORT);
+}
+
+void
+sane_scan::set_value (const char * option_name, const void * value)
+{
+ SANE_Status status;
+ int option_id;
+
+ option_id = get_option_id (option_name);
+
+ status = sane_control_option (m_hdevice,
+ option_id,
+ SANE_ACTION_SET_VALUE,
+ const_cast<void *>(value),
+ 0);
+
+ if (status != SANE_STATUS_GOOD)
+ throw pisa_error (status, *this);
+}
+
+void
+sane_scan::get_value (const char *option_name, void *value, bool nothrow) const
+{
+ SANE_Status status;
+ int option_id;
+
+ try
+ {
+ option_id = get_option_id (option_name);
+ }
+ catch (pisa_error& oops)
+ {
+ if (!nothrow) throw oops;
+ return;
+ }
+
+ status = sane_control_option (m_hdevice, option_id,
+ SANE_ACTION_GET_VALUE,
+ value,
+ 0);
+
+ if (!nothrow && status != SANE_STATUS_GOOD)
+ throw pisa_error (status, *this);
+}
+
+void
+sane_scan::get_range (const char *option_name,
+ float *max, float *min, float *step)
+{
+ const SANE_Option_Descriptor *opt_desc = NULL;
+ int opt_id = 0;
+
+ if (!option_name)
+ {
+ throw pisa_error (PISA_ERR_PARAMETER);
+ }
+ if (!m_hdevice)
+ {
+ throw pisa_error (PISA_ERR_CONNECT);
+ }
+ opt_id = get_option_id (option_name);
+ opt_desc = sane_get_option_descriptor (m_hdevice, opt_id);
+ if (!opt_desc
+ || SANE_CONSTRAINT_RANGE != opt_desc->constraint_type)
+ {
+ throw pisa_error (PISA_STATUS_UNSUPPORTED);
+ }
+
+ if ( SANE_TYPE_FIXED == opt_desc->type )
+ {
+ if (max)
+ {
+ *max = SANE_UNFIX (opt_desc->constraint.range->max);
+ }
+ if (min)
+ {
+ *min = SANE_UNFIX (opt_desc->constraint.range->min);
+ }
+ if (step)
+ {
+ *step = SANE_UNFIX (opt_desc->constraint.range->quant);
+ }
+ }
+ else
+ {
+ if (max)
+ {
+ *max = opt_desc->constraint.range->max;
+ }
+ if (min)
+ {
+ *min = opt_desc->constraint.range->min;
+ }
+ if (step)
+ {
+ *step = opt_desc->constraint.range->quant;
+ }
+ }
+}
+
+void
+sane_scan::set_preview (bool value)
+{
+ SANE_Bool v = value;
+ set_value ("preview", &v);
+}
+
+bool
+sane_scan::has_preview (void) const
+{
+ return is_activate ("preview");
+}
+
+void
+sane_scan::set_focus (long position)
+{
+ char focus[32];
+
+ if (0 == is_activate ("focus-position"))
+ return;
+
+ if (position == 25)
+ strcpy (focus, "Focus 2.5mm above glass");
+ else
+ strcpy (focus, "Focus on glass");
+
+ set_value ("focus-position", (void *) focus);
+}
+
+void
+sane_scan::set_speed (long speed)
+{
+ SANE_Bool value;
+
+ if (0 == is_activate ("speed"))
+ return;
+
+ if (speed == 1)
+ value = SANE_TRUE;
+ else
+ value = SANE_FALSE;
+
+ set_value ("speed", (void *) & value);
+}
+
+bool
+sane_scan::has_zoom (void) const
+{
+ return is_activate ("zoom");
+}
+
+bool
+sane_scan::has_focus (void) const
+{
+ return is_activate ("focus-position");
+
+}
+
+bool
+sane_scan::has_draft_mode (void) const
+{
+ return is_activate ("speed");
+}
+
+bool
+sane_scan::get_size_check (void) const
+{
+ SANE_Bool value;
+ get_value ("detect-doc-size", &value);
+ return value;
+}
+
+void
+sane_scan::set_size_check (bool value)
+{
+ SANE_Bool v = value;
+ set_value ("detect-doc-size", &v);
+}
+
+bool
+sane_scan::has_size_check (void) const
+{
+ return is_activate ("detect-doc-size");
+}
+
+bool
+sane_scan::get_autocrop (void) const
+{
+ SANE_Bool value;
+ get_value ("autocrop", &value);
+ return value;
+}
+
+void
+sane_scan::set_autocrop (bool value)
+{
+ SANE_Bool v = value;
+ set_value ("autocrop", &v);
+}
+
+bool
+sane_scan::has_autocrop (void) const
+{
+ return is_activate ("autocrop");
+}
+
+bool
+sane_scan::get_deskew (void) const
+{
+ SANE_Bool value;
+ get_value ("deskew", &value);
+ return value;
+}
+
+void
+sane_scan::set_deskew (bool value)
+{
+ SANE_Bool v = value;
+ set_value ("deskew", &v);
+}
+
+bool
+sane_scan::has_deskew (void) const
+{
+ return is_activate ("deskew");
+}
+
+bool
+sane_scan::has_start_button (void) const
+{
+ return is_activate ("monitor-button");
+}
+
+bool
+sane_scan::is_button_pressed (void) const
+{
+ SANE_Bool value = false;
+
+ get_value ("monitor-button", (void *) &value);
+
+ return value;
+}
+
+long
+sane_scan::get_polling_time (void) const
+{
+ SANE_Word value = 0;
+
+ get_value ("polling-time", (void *) &value);
+
+ return value;
+}
+
+void
+sane_scan::disable_wait_for_button (void)
+{
+ SANE_Bool value = false;
+ SANE_Bool off = false;
+ if (is_activate ("wait-for-button"))
+ {
+ get_value ("wait-for-button", &value);
+ }
+ if (value)
+ {
+ set_value ("wait-for-button", &off);
+ }
+}
+
+void
+sane_scan::set_color_mode (char pixeltype, char bitdepth)
+{
+ char color_mode[32];
+ SANE_Word depth;
+
+ switch (pixeltype)
+ {
+ case PISA_PT_RGB:
+ strcpy (color_mode, "Color");
+ break;
+
+ case PISA_PT_GRAY:
+ strcpy (color_mode, "Gray");
+ break;
+
+ case PISA_PT_BW:
+ strcpy (color_mode, "Binary");
+ break;
+ }
+
+ switch (bitdepth)
+ {
+ case PISA_BD_1:
+ depth = 1;
+ break;
+
+ case PISA_BD_8:
+ depth = 8;
+ break;
+ }
+
+ if (is_activate (SANE_NAME_SCAN_MODE))
+ {
+ set_value (SANE_NAME_SCAN_MODE, (void *) color_mode);
+ }
+ if (is_activate (SANE_NAME_BIT_DEPTH))
+ {
+ set_value (SANE_NAME_BIT_DEPTH, (void *) &depth);
+ }
+}
+
+void
+sane_scan::set_gamma_table (const unsigned char *gamma_table)
+{
+ SANE_Word table[256];
+ int i;
+ char user_defined[32];
+
+ strcpy (user_defined, "User defined (Gamma=1.8)");
+
+ set_value ("gamma-correction", (void *) user_defined);
+
+ // red
+ for (i = 0; i < 256; i++)
+ table[i] = gamma_table[256 * 0 + i];
+ set_value (SANE_NAME_GAMMA_VECTOR_R, (void *) table);
+
+ // green
+ for (i = 0; i < 256; i++)
+ table[i] = gamma_table[256 * 1 + i];
+ set_value (SANE_NAME_GAMMA_VECTOR_G, (void *) table);
+
+ // blue
+ for (i = 0; i < 256; i++)
+ table[i] = gamma_table[256 * 2 + i];
+ set_value (SANE_NAME_GAMMA_VECTOR_B, (void *) table );
+}
+
+void
+sane_scan::set_threshold (long threshold)
+{
+ set_value (SANE_NAME_THRESHOLD, (void *) & threshold);
+}
+
+void
+sane_scan::set_color_profile (const double * coef)
+{
+ SANE_Word value;
+ char option_name[16];
+ int i;
+ char user_defined[32];
+
+ strcpy (user_defined, "User defined");
+
+ set_value ("color-correction", (void *) user_defined);
+
+ for (i = 0; i < 9; i++)
+ {
+ sprintf (option_name, "cct-%d", i + 1);
+ value = SANE_FIX (coef[i]);
+ set_value (option_name, (void *) &value);
+ }
+}
+
+void
+sane_scan::set_brightness (long brightness)
+{
+ set_value (SANE_NAME_BRIGHTNESS, (void *) & brightness);
+}
+
+bool
+sane_scan::has_brightness (void) const
+{
+ return is_activate (SANE_NAME_BRIGHTNESS);
+}
+
+void
+sane_scan::set_contrast (long contrast)
+{
+ set_value (SANE_NAME_CONTRAST, (void *) & contrast);
+}
+
+bool
+sane_scan::has_contrast (void) const
+{
+ return is_activate (SANE_NAME_CONTRAST);
+}
+
+void
+sane_scan::set_brightness_method (br_method_val val)
+{
+ char method[32];
+
+ switch (val)
+ {
+ case br_gimp:
+ strcpy (method, "gimp");
+ break;
+ case br_iscan:
+ default:
+ strcpy (method, "iscan");
+ break;
+ }
+
+ set_value ("brightness-method", (void *) method);
+}
+
+void
+sane_scan::set_scan_resolution (int resolution_x, int resolution_y)
+{
+ set_value (SANE_NAME_SCAN_X_RESOLUTION, (void *) &resolution_x);
+ set_value (SANE_NAME_SCAN_Y_RESOLUTION, (void *) &resolution_y);
+}
+
+void
+sane_scan::set_scan_zoom (int zoom_x, int zoom_y)
+{
+ set_value ("zoom", (void *) & zoom_x);
+
+ zoom_y = zoom_y;
+}
+
+void
+sane_scan::set_scan_area (double offset_x, double offset_y,
+ double width, double height)
+{
+ SANE_Word value;
+ double tmp;
+
+ value = SANE_FIX (offset_x * MM_PER_INCH);
+ set_value (SANE_NAME_SCAN_TL_X, (void *) &value);
+
+ value = SANE_FIX (offset_y * MM_PER_INCH);
+ set_value (SANE_NAME_SCAN_TL_Y, (void *) &value);
+
+ tmp = offset_x + width;
+ value = SANE_FIX (tmp * MM_PER_INCH);
+ set_value (SANE_NAME_SCAN_BR_X, (void *) &value);
+
+ tmp = offset_y + height;
+ value = SANE_FIX (tmp * MM_PER_INCH);
+ set_value (SANE_NAME_SCAN_BR_Y, (void *) &value);
+}
+
+bool
+sane_scan::has_clean (void) const
+{
+ return is_activate ("clean");
+}
+
+bool
+sane_scan::has_calibrate (void) const
+{
+ return is_activate ("calibrate");
+}
+
+void
+sane_scan::clean (void)
+{
+ set_value ("clean", NULL);
+}
+
+void
+sane_scan::calibrate (void)
+{
+ set_value ("calibrate", NULL);
+}