summaryrefslogtreecommitdiff
path: root/backend/escl/escl.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/escl/escl.c')
-rw-r--r--backend/escl/escl.c587
1 files changed, 550 insertions, 37 deletions
diff --git a/backend/escl/escl.c b/backend/escl/escl.c
index c40fd98..bb62219 100644
--- a/backend/escl/escl.c
+++ b/backend/escl/escl.c
@@ -16,8 +16,8 @@
for more details.
You should have received a copy of the GNU General Public License
- along with sane; see the file COPYING. If not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with sane; see the file COPYING.
+ If not, see <https://www.gnu.org/licenses/>.
This file implements a SANE backend for eSCL scanners. */
@@ -29,15 +29,32 @@
#include <setjmp.h>
-#include <curl/curl.h>
-
#include "../include/sane/saneopts.h"
#include "../include/sane/sanei.h"
#include "../include/sane/sanei_backend.h"
#include "../include/sane/sanei_config.h"
+
+#ifndef SANE_NAME_SHARPEN
+# define SANE_NAME_SHARPEN "sharpen"
+# define SANE_TITLE_SHARPEN SANE_I18N("Sharpen")
+# define SANE_DESC_SHARPEN SANE_I18N("Set sharpen value.")
+#endif
+
+#ifndef SANE_NAME_THRESHOLD
+# define SANE_NAME_THRESHOLD "threshold"
+#endif
+#ifndef SANE_TITLE_THRESHOLD
+# define SANE_TITLE_THRESHOLD SANE_I18N("Threshold")
+#endif
+#ifndef SANE_DESC_THRESHOLD
+# define SANE_DESC_THRESHOLD \
+ SANE_I18N("Set threshold for line-art scans.")
+#endif
+
#define min(A,B) (((A)<(B)) ? (A) : (B))
#define max(A,B) (((A)>(B)) ? (A) : (B))
+#define IS_ACTIVE(OPTION) (((handler->opt[OPTION].cap) & SANE_CAP_INACTIVE) == 0)
#define INPUT_BUFFER_SIZE 4096
static const SANE_Device **devlist = NULL;
@@ -56,6 +73,10 @@ typedef struct Handled {
SANE_Range x_range2;
SANE_Range y_range1;
SANE_Range y_range2;
+ SANE_Range brightness_range;
+ SANE_Range contrast_range;
+ SANE_Range sharpen_range;
+ SANE_Range thresold_range;
SANE_Bool cancel;
SANE_Bool write_scan_data;
SANE_Bool decompress_scan_data;
@@ -70,7 +91,10 @@ escl_free_device(ESCL_Device *current)
free((void*)current->ip_address);
free((void*)current->model_name);
free((void*)current->type);
- free(current->unix_socket);
+ free((void*)current->is);
+ free((void*)current->uuid);
+ free((void*)current->unix_socket);
+ curl_slist_free_all(current->hack);
free(current);
return NULL;
}
@@ -110,6 +134,10 @@ escl_check_and_add_device(ESCL_Device *current)
DBG (10, "Scanner Type allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
+ if (!current->is) {
+ DBG (10, "Scanner Is allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
++num_devices;
current->next = list_devices_primary;
list_devices_primary = current;
@@ -150,14 +178,20 @@ escl_add_in_list(ESCL_Device *current)
* \return escl_add_in_list(current)
*/
SANE_Status
-escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type)
+escl_device_add(int port_nb,
+ const char *model_name,
+ char *ip_address,
+ const char *is,
+ const char *uuid,
+ char *type)
{
char tmp[PATH_MAX] = { 0 };
char *model = NULL;
ESCL_Device *current = NULL;
DBG (10, "escl_device_add\n");
for (current = list_devices_primary; current; current = current->next) {
- if (strcmp(current->ip_address, ip_address) == 0)
+ if ((strcmp(current->ip_address, ip_address) == 0) ||
+ (uuid && current->uuid && !strcmp(current->uuid, uuid)))
{
if (strcmp(current->type, type))
{
@@ -166,6 +200,10 @@ escl_device_add(int port_nb, const char *model_name, char *ip_address, char *typ
{
free (current->type);
current->type = strdup(type);
+ if (strcmp(current->ip_address, ip_address)) {
+ free (current->ip_address);
+ current->ip_address = strdup(ip_address);
+ }
current->port_nb = port_nb;
current->https = SANE_TRUE;
}
@@ -191,7 +229,12 @@ escl_device_add(int port_nb, const char *model_name, char *ip_address, char *typ
model = (char*)(tmp[0] != 0 ? tmp : model_name);
current->model_name = strdup(model);
current->ip_address = strdup(ip_address);
+ memset(tmp, 0, PATH_MAX);
+ snprintf(tmp, sizeof(tmp), "%s scanner", (is ? is : "flatbed or ADF"));
+ current->is = strdup(tmp);
current->type = strdup(type);
+ if (uuid)
+ current->uuid = strdup(uuid);
return escl_add_in_list(current);
}
@@ -259,7 +302,7 @@ get_vendor(char *search)
* \brief Function that checks if the url of the received scanner is secured or not (http / https).
* --> if the url is not secured, our own url will be composed like "http://'ip':'port'".
* --> else, our own url will be composed like "https://'ip':'port'".
- * AND, it's in this function that we gather all the informations of the url (that were in our list) :
+ * AND, it's in this function that we gather all the information of the url (that were in our list) :
* the model_name, the port, the ip, and the type of url.
* SO, leaving this function, we have in memory the complete url.
*
@@ -308,7 +351,7 @@ convertFromESCLDev(ESCL_Device *cdev)
DBG (10, "Model allocation failure.\n");
goto freename;
}
- sdev->type = strdup("flatbed scanner");
+ sdev->type = strdup(cdev->is);
if (!sdev->type) {
DBG (10, "Scanner Type allocation failure.\n");
goto freevendor;
@@ -383,7 +426,8 @@ sane_exit(void)
* \return escl_add_in_list(escl_device) if the parsing worked, SANE_STATUS_GOOD otherwise.
*/
static SANE_Status
-attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
+attach_one_config(SANEI_Config __sane_unused__ *config, const char *line,
+ void __sane_unused__ *data)
{
int port = 0;
SANE_Status status;
@@ -392,6 +436,7 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
if (strncmp(line, "device", 6) == 0) {
char *name_str = NULL;
char *opt_model = NULL;
+ char *opt_hack = NULL;
line = sanei_config_get_string(line + 6, &name_str);
DBG (10, "New Escl_Device URL [%s].\n", (name_str ? name_str : "VIDE"));
@@ -403,6 +448,10 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
line = sanei_config_get_string(line, &opt_model);
DBG (10, "New Escl_Device model [%s].\n", opt_model);
}
+ if (*line) {
+ line = sanei_config_get_string(line, &opt_hack);
+ DBG (10, "New Escl_Device hack [%s].\n", opt_hack);
+ }
escl_free_device(escl_device);
escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
@@ -419,7 +468,9 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
return status;
}
escl_device->model_name = opt_model ? opt_model : strdup("Unknown model");
- escl_device->type = strdup("flatbed scanner");
+ escl_device->is = strdup("flatbed or ADF scanner");
+ escl_device->type = strdup("In url");
+ escl_device->uuid = NULL;
}
if (strncmp(line, "[device]", 8) == 0) {
@@ -430,7 +481,7 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
return (SANE_STATUS_NO_MEM);
}
}
- if (strncmp(line, "ip", 2) == 0) {
+ else if (strncmp(line, "ip", 2) == 0) {
const char *ip_space = sanei_config_skip_whitespace(line + 2);
DBG (10, "New Escl_Device IP [%s].", (ip_space ? ip_space : "VIDE"));
if (escl_device != NULL && ip_space != NULL) {
@@ -438,14 +489,14 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
escl_device->ip_address = strdup(ip_space);
}
}
- if (sscanf(line, "port %i", &port) == 1 && port != 0) {
+ else if (sscanf(line, "port %i", &port) == 1 && port != 0) {
DBG (10, "New Escl_Device PORT [%d].", port);
if (escl_device != NULL) {
DBG (10, "New Escl_Device PORT Affected.");
escl_device->port_nb = port;
}
}
- if (strncmp(line, "model", 5) == 0) {
+ else if (strncmp(line, "model", 5) == 0) {
const char *model_space = sanei_config_skip_whitespace(line + 5);
DBG (10, "New Escl_Device MODEL [%s].", (model_space ? model_space : "VIDE"));
if (escl_device != NULL && model_space != NULL) {
@@ -453,7 +504,7 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
escl_device->model_name = strdup(model_space);
}
}
- if (strncmp(line, "type", 4) == 0) {
+ else if (strncmp(line, "type", 4) == 0) {
const char *type_space = sanei_config_skip_whitespace(line + 4);
DBG (10, "New Escl_Device TYPE [%s].", (type_space ? type_space : "VIDE"));
if (escl_device != NULL && type_space != NULL) {
@@ -461,6 +512,8 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
escl_device->type = strdup(type_space);
}
}
+ escl_device->is = strdup("flatbed or ADF scanner");
+ escl_device->uuid = NULL;
status = escl_check_and_add_device(escl_device);
if (status == SANE_STATUS_GOOD)
escl_device = NULL;
@@ -487,7 +540,8 @@ sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
if (device_list == NULL)
return (SANE_STATUS_INVAL);
- status = sanei_configure_attach(ESCL_CONFIG_FILE, NULL, attach_one_config);
+ status = sanei_configure_attach(ESCL_CONFIG_FILE, NULL,
+ attach_one_config, NULL);
if (status != SANE_STATUS_GOOD)
return (status);
escl_devices(&status);
@@ -526,10 +580,156 @@ _source_size_max (SANE_String_Const * sources)
return size;
}
+static int
+_get_resolution(escl_sane_t *handler, int resol)
+{
+ int x = 1;
+ int n = handler->scanner->caps[handler->scanner->source].SupportedResolutions[0] + 1;
+ int old = -1;
+ for (; x < n; x++) {
+ DBG(10, "SEARCH RESOLUTION [ %d | %d]\n", resol, (int)handler->scanner->caps[handler->scanner->source].SupportedResolutions[x]);
+ if (resol == handler->scanner->caps[handler->scanner->source].SupportedResolutions[x])
+ return resol;
+ else if (resol < handler->scanner->caps[handler->scanner->source].SupportedResolutions[x])
+ {
+ if (old == -1)
+ return handler->scanner->caps[handler->scanner->source].SupportedResolutions[1];
+ else
+ return old;
+ }
+ else
+ old = handler->scanner->caps[handler->scanner->source].SupportedResolutions[x];
+ }
+ return old;
+}
+
+
+/**
+ * \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s)
+ * \brief Function thzt initializes all the needed options of the received scanner
+ * (the resolution / the color / the margins) thanks to the information received with
+ * the 'escl_capabilities' function, called just before.
+ *
+ * \return status (if everything is OK, status = SANE_STATUS_GOOD)
+ */
+static SANE_Status
+init_options_small(SANE_String_Const name_source, escl_sane_t *s)
+{
+ int found = 0;
+ DBG (10, "escl init_options\n");
+
+ SANE_Status status = SANE_STATUS_GOOD;
+ if (!s->scanner) return SANE_STATUS_INVAL;
+ if (name_source) {
+ int source = s->scanner->source;
+ if (!strcmp(name_source, SANE_I18N ("ADF Duplex")))
+ s->scanner->source = ADFDUPLEX;
+ else if (!strncmp(name_source, "A", 1) ||
+ !strcmp(name_source, SANE_I18N ("ADF")))
+ s->scanner->source = ADFSIMPLEX;
+ else
+ s->scanner->source = PLATEN;
+ if (source == s->scanner->source) return status;
+ s->scanner->caps[s->scanner->source].default_color =
+ strdup(s->scanner->caps[source].default_color);
+ s->scanner->caps[s->scanner->source].default_resolution =
+ _get_resolution(s, s->scanner->caps[source].default_resolution);
+ }
+ if (s->scanner->caps[s->scanner->source].ColorModes == NULL) {
+ if (s->scanner->caps[PLATEN].ColorModes)
+ s->scanner->source = PLATEN;
+ else if (s->scanner->caps[ADFSIMPLEX].ColorModes)
+ s->scanner->source = ADFSIMPLEX;
+ else if (s->scanner->caps[ADFDUPLEX].ColorModes)
+ s->scanner->source = ADFDUPLEX;
+ else
+ return SANE_STATUS_INVAL;
+ }
+ if (s->scanner->source == PLATEN) {
+ DBG (10, "SOURCE PLATEN.\n");
+ }
+ else if (s->scanner->source == ADFDUPLEX) {
+ DBG (10, "SOURCE ADFDUPLEX.\n");
+ }
+ else if (s->scanner->source == ADFSIMPLEX) {
+ DBG (10, "SOURCE ADFSIMPLEX.\n");
+ }
+ s->x_range1.min = 0;
+ s->x_range1.max =
+ PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxWidth -
+ s->scanner->caps[s->scanner->source].MinWidth),
+ 300.0);
+ s->x_range1.quant = 0;
+ s->x_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinWidth, 300.0);
+ s->x_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxWidth, 300.0);
+ s->x_range2.quant = 0;
+ s->y_range1.min = 0;
+ s->y_range1.max =
+ PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxHeight -
+ s->scanner->caps[s->scanner->source].MinHeight),
+ 300.0);
+ s->y_range1.quant = 0;
+ s->y_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinHeight, 300.0);
+ s->y_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxHeight, 300.0);
+ s->y_range2.quant = 0;
+
+ s->opt[OPT_MODE].constraint.string_list = s->scanner->caps[s->scanner->source].ColorModes;
+ if (s->val[OPT_MODE].s)
+ free(s->val[OPT_MODE].s);
+ s->val[OPT_MODE].s = NULL;
+
+ if (s->scanner->caps[s->scanner->source].default_color) {
+ int x = 0;
+ if (!strcmp(s->scanner->caps[s->scanner->source].default_color, "Grayscale8"))
+ s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_GRAY);
+ else if (!strcmp(s->scanner->caps[s->scanner->source].default_color, "BlackAndWhite1"))
+ s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_LINEART);
+ else
+ s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_COLOR);
+ for (x = 0; s->scanner->caps[s->scanner->source].ColorModes[x]; x++) {
+ if (s->scanner->caps[s->scanner->source].ColorModes[x] &&
+ !strcasecmp(s->scanner->caps[s->scanner->source].ColorModes[x], s->val[OPT_MODE].s)) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!s->scanner->caps[s->scanner->source].default_color || found == 0) {
+ if (s->scanner->caps[s->scanner->source].default_color)
+ free(s->scanner->caps[s->scanner->source].default_color);
+ s->val[OPT_MODE].s = strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
+ if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
+ s->scanner->caps[s->scanner->source].default_color = strdup("Grayscale8");
+ else if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
+ s->scanner->caps[s->scanner->source].default_color = strdup("BlackAndWhite1");
+ else
+ s->scanner->caps[s->scanner->source].default_color = strdup("RGB24");
+ }
+ if (!s->val[OPT_MODE].s) {
+ DBG (10, "Color Mode Default allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ if (!s->scanner->caps[s->scanner->source].default_color) {
+ DBG (10, "Color Mode Default allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ s->val[OPT_RESOLUTION].w = s->scanner->caps[s->scanner->source].default_resolution;
+ s->opt[OPT_TL_X].constraint.range = &s->x_range1;
+ s->opt[OPT_TL_Y].constraint.range = &s->y_range1;
+ s->opt[OPT_BR_X].constraint.range = &s->x_range2;
+ s->opt[OPT_BR_Y].constraint.range = &s->y_range2;
+
+ if (s->val[OPT_SCAN_SOURCE].s)
+ free (s->val[OPT_SCAN_SOURCE].s);
+ s->val[OPT_SCAN_SOURCE].s = strdup (s->scanner->Sources[s->scanner->source]);
+
+ return (SANE_STATUS_GOOD);
+}
+
/**
* \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s)
* \brief Function thzt initializes all the needed options of the received scanner
- * (the resolution / the color / the margins) thanks to the informations received with
+ * (the resolution / the color / the margins) thanks to the information received with
* the 'escl_capabilities' function, called just before.
*
* \return status (if everything is OK, status = SANE_STATUS_GOOD)
@@ -554,8 +754,25 @@ init_options(SANE_String_Const name_source, escl_sane_t *s)
s->scanner->source = PLATEN;
if (source == s->scanner->source) return status;
}
- else
- s->scanner->source = PLATEN;
+ if (s->scanner->caps[s->scanner->source].ColorModes == NULL) {
+ if (s->scanner->caps[PLATEN].ColorModes)
+ s->scanner->source = PLATEN;
+ else if (s->scanner->caps[ADFSIMPLEX].ColorModes)
+ s->scanner->source = ADFSIMPLEX;
+ else if (s->scanner->caps[ADFDUPLEX].ColorModes)
+ s->scanner->source = ADFDUPLEX;
+ else
+ return SANE_STATUS_INVAL;
+ }
+ if (s->scanner->source == PLATEN) {
+ DBG (10, "SOURCE PLATEN.\n");
+ }
+ else if (s->scanner->source == ADFDUPLEX) {
+ DBG (10, "SOURCE ADFDUPLEX.\n");
+ }
+ else if (s->scanner->source == ADFSIMPLEX) {
+ DBG (10, "SOURCE ADFSIMPLEX.\n");
+ }
memset (s->opt, 0, sizeof (s->opt));
memset (s->val, 0, sizeof (s->val));
for (i = 0; i < NUM_OPTIONS; ++i) {
@@ -590,6 +807,7 @@ init_options(SANE_String_Const name_source, escl_sane_t *s)
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].size = 0;
s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
@@ -599,17 +817,39 @@ init_options(SANE_String_Const name_source, escl_sane_t *s)
s->opt[OPT_MODE].unit = SANE_UNIT_NONE;
s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
s->opt[OPT_MODE].constraint.string_list = s->scanner->caps[s->scanner->source].ColorModes;
- s->val[OPT_MODE].s = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
+ if (s->scanner->caps[s->scanner->source].default_color) {
+ if (!strcasecmp(s->scanner->caps[s->scanner->source].default_color, "Grayscale8"))
+ s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_GRAY);
+ else if (!strcasecmp(s->scanner->caps[s->scanner->source].default_color, "BlackAndWhite1"))
+ s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_LINEART);
+ else
+ s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_COLOR);
+ }
+ else {
+ s->val[OPT_MODE].s = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
+ if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) {
+ s->scanner->caps[s->scanner->source].default_color = strdup("Grayscale8");
+ }
+ else if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) {
+ s->scanner->caps[s->scanner->source].default_color =
+ strdup("BlackAndWhite1");
+ }
+ else {
+ s->scanner->caps[s->scanner->source].default_color =
+ strdup("RGB24");
+ }
+ }
if (!s->val[OPT_MODE].s) {
DBG (10, "Color Mode Default allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
+ DBG (10, "++ Color Mode Default allocation [%s].\n", s->scanner->caps[s->scanner->source].default_color);
s->opt[OPT_MODE].size = max_string_size(s->scanner->caps[s->scanner->source].ColorModes);
- s->scanner->caps[s->scanner->source].default_color = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
if (!s->scanner->caps[s->scanner->source].default_color) {
DBG (10, "Color Mode Default allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
+ DBG (10, "Color Mode Default allocation (%s).\n", s->scanner->caps[s->scanner->source].default_color);
s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
@@ -638,6 +878,7 @@ init_options(SANE_String_Const name_source, escl_sane_t *s)
s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY;
s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
+ s->opt[OPT_GEOMETRY_GROUP].size = 0;
s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
@@ -696,6 +937,113 @@ init_options(SANE_String_Const name_source, escl_sane_t *s)
if (s->val[OPT_SCAN_SOURCE].s)
free (s->val[OPT_SCAN_SOURCE].s);
s->val[OPT_SCAN_SOURCE].s = strdup (s->scanner->Sources[s->scanner->source]);
+
+ /* "Enhancement" group: */
+ s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
+ s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; /* not valid for a group */
+ s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
+ s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
+ s->opt[OPT_ENHANCEMENT_GROUP].size = 0;
+ s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
+
+
+ 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;
+ if (s->scanner->brightness) {
+ s->opt[OPT_BRIGHTNESS].constraint.range = &s->brightness_range;
+ s->val[OPT_BRIGHTNESS].w = s->scanner->brightness->normal;
+ s->brightness_range.quant=1;
+ s->brightness_range.min=s->scanner->brightness->min;
+ s->brightness_range.max=s->scanner->brightness->max;
+ }
+ else{
+ SANE_Range range = { 0, 255, 0 };
+ s->opt[OPT_BRIGHTNESS].constraint.range = &range;
+ s->val[OPT_BRIGHTNESS].w = 0;
+ s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
+ }
+ 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;
+ if (s->scanner->contrast) {
+ s->opt[OPT_CONTRAST].constraint.range = &s->contrast_range;
+ s->val[OPT_CONTRAST].w = s->scanner->contrast->normal;
+ s->contrast_range.quant=1;
+ s->contrast_range.min=s->scanner->contrast->min;
+ s->contrast_range.max=s->scanner->contrast->max;
+ }
+ else{
+ SANE_Range range = { 0, 255, 0 };
+ s->opt[OPT_CONTRAST].constraint.range = &range;
+ s->val[OPT_CONTRAST].w = 0;
+ s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
+ }
+ s->opt[OPT_SHARPEN].name = SANE_NAME_SHARPEN;
+ s->opt[OPT_SHARPEN].title = SANE_TITLE_SHARPEN;
+ s->opt[OPT_SHARPEN].desc = SANE_DESC_SHARPEN;
+ s->opt[OPT_SHARPEN].type = SANE_TYPE_INT;
+ s->opt[OPT_SHARPEN].unit = SANE_UNIT_NONE;
+ s->opt[OPT_SHARPEN].constraint_type = SANE_CONSTRAINT_RANGE;
+ if (s->scanner->sharpen) {
+ s->opt[OPT_SHARPEN].constraint.range = &s->sharpen_range;
+ s->val[OPT_SHARPEN].w = s->scanner->sharpen->normal;
+ s->sharpen_range.quant=1;
+ s->sharpen_range.min=s->scanner->sharpen->min;
+ s->sharpen_range.max=s->scanner->sharpen->max;
+ }
+ else{
+ SANE_Range range = { 0, 255, 0 };
+ s->opt[OPT_SHARPEN].constraint.range = &range;
+ s->val[OPT_SHARPEN].w = 0;
+ s->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
+ }
+ /*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;
+ if (s->scanner->threshold) {
+ s->opt[OPT_THRESHOLD].constraint.range = &s->thresold_range;
+ s->val[OPT_THRESHOLD].w = s->scanner->threshold->normal;
+ s->thresold_range.quant=1;
+ s->thresold_range.min= s->scanner->threshold->min;
+ s->thresold_range.max=s->scanner->threshold->max;
+ }
+ else{
+ SANE_Range range = { 0, 255, 0 };
+ s->opt[OPT_THRESHOLD].constraint.range = &range;
+ s->val[OPT_THRESHOLD].w = 0;
+ s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
+ }
+ if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) {
+ if (s->scanner->threshold)
+ s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
+ if (s->scanner->brightness)
+ s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
+ if (s->scanner->contrast)
+ s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
+ if (s->scanner->sharpen)
+ s->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
+ }
+ else {
+ if (s->scanner->threshold)
+ s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
+ if (s->scanner->brightness)
+ s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
+ if (s->scanner->contrast)
+ s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
+ if (s->scanner->sharpen)
+ s->opt[OPT_SHARPEN].cap &= ~SANE_CAP_INACTIVE;
+ }
return (status);
}
@@ -745,6 +1093,50 @@ escl_parse_name(SANE_String_Const name, ESCL_Device *device)
return SANE_STATUS_GOOD;
}
+static void
+_get_hack(SANE_String_Const name, ESCL_Device *device)
+{
+ FILE *fp;
+ SANE_Char line[PATH_MAX];
+ DBG (3, "_get_hack: start\n");
+ if (device->model_name &&
+ (strcasestr(device->model_name, "LaserJet FlowMFP M578") ||
+ strcasestr(device->model_name, "LaserJet MFP M630"))) {
+ device->hack = curl_slist_append(NULL, "Host: localhost");
+ DBG (3, "_get_hack: finish\n");
+ return;
+ }
+
+ /* open configuration file */
+ fp = sanei_config_open (ESCL_CONFIG_FILE);
+ if (!fp)
+ {
+ DBG (2, "_get_hack: couldn't access %s\n", ESCL_CONFIG_FILE);
+ DBG (3, "_get_hack: exit\n");
+ }
+
+ /* loop reading the configuration file, all line beginning by "option " are
+ * parsed for value to store in configuration structure, other line are
+ * used are device to try to attach
+ */
+ while (sanei_config_read (line, PATH_MAX, fp))
+ {
+ if (strstr(line, name)) {
+ DBG (3, "_get_hack: idevice found\n");
+ if (strstr(line, "hack=localhost")) {
+ DBG (3, "_get_hack: device found\n");
+ device->hack = curl_slist_append(NULL, "Host: localhost");
+ }
+ goto finish_hack;
+ }
+ }
+finish_hack:
+ DBG (3, "_get_hack: finish\n");
+ fclose(fp);
+}
+
+
+
/**
* \fn SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h)
* \brief Function that establishes a connection with the device named by 'name',
@@ -786,6 +1178,8 @@ sane_open(SANE_String_Const name, SANE_Handle *h)
escl_free_handler(handler);
return (status);
}
+ _get_hack(name, device);
+
status = init_options(NULL, handler);
if (status != SANE_STATUS_GOOD) {
escl_free_handler(handler);
@@ -897,9 +1291,12 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
case OPT_BR_X:
case OPT_BR_Y:
case OPT_NUM_OPTS:
- case OPT_RESOLUTION:
case OPT_PREVIEW:
case OPT_GRAY_PREVIEW:
+ case OPT_RESOLUTION:
+ case OPT_BRIGHTNESS:
+ case OPT_CONTRAST:
+ case OPT_SHARPEN:
*(SANE_Word *) v = handler->val[n].w;
break;
case OPT_SCAN_SOURCE:
@@ -919,16 +1316,18 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
case OPT_BR_X:
case OPT_BR_Y:
case OPT_NUM_OPTS:
- case OPT_RESOLUTION:
case OPT_PREVIEW:
case OPT_GRAY_PREVIEW:
+ case OPT_BRIGHTNESS:
+ case OPT_CONTRAST:
+ case OPT_SHARPEN:
handler->val[n].w = *(SANE_Word *) v;
if (i)
*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
break;
case OPT_SCAN_SOURCE:
DBG(10, "SET OPT_SCAN_SOURCE(%s)\n", (SANE_String_Const)v);
- init_options((SANE_String_Const)v, handler);
+ init_options_small((SANE_String_Const)v, handler);
if (i)
*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
break;
@@ -940,6 +1339,48 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
DBG (10, "OPT_MODE allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
+ DBG(10, "SET OPT_MODE(%s)\n", (SANE_String_Const)v);
+
+ if (!strcasecmp(handler->val[n].s, SANE_VALUE_SCAN_MODE_GRAY)) {
+ handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8");
+ DBG(10, "SET OPT_MODE(Grayscale8)\n");
+ }
+ else if (!strcasecmp(handler->val[n].s, SANE_VALUE_SCAN_MODE_LINEART)) {
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("BlackAndWhite1");
+ DBG(10, "SET OPT_MODE(BlackAndWhite1)\n");
+ }
+ else {
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("RGB24");
+ DBG(10, "SET OPT_MODE(RGB24)\n");
+ }
+ DBG (10, "Color Mode allocation (%s).\n", handler->scanner->caps[handler->scanner->source].default_color);
+ if (i)
+ *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
+ if (handler->scanner->brightness)
+ handler->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
+ if (handler->scanner->contrast)
+ handler->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
+ if (handler->scanner->threshold)
+ handler->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
+ if (handler->scanner->sharpen)
+ handler->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
+ if (!strcasecmp(handler->val[n].s, SANE_VALUE_SCAN_MODE_LINEART)) {
+ if (handler->scanner->threshold)
+ handler->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
+ }
+ else {
+ if (handler->scanner->brightness)
+ handler->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
+ if (handler->scanner->contrast)
+ handler->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
+ if (handler->scanner->sharpen)
+ handler->opt[OPT_SHARPEN].cap &= ~SANE_CAP_INACTIVE;
+ }
+ break;
+ case OPT_RESOLUTION:
+ handler->val[n].w = _get_resolution(handler, (int)(*(SANE_Word *) v));
if (i)
*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
break;
@@ -975,7 +1416,7 @@ _go_next_page(SANE_Status status,
/**
* \fn SANE_Status sane_start(SANE_Handle h)
- * \brief Function that initiates aquisition of an image from the device represented by handle 'h'.
+ * \brief Function that initiates acquisition of an image from the device represented by handle 'h'.
* This function calls the "escl_newjob" function and the "escl_scan" function.
*
* \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
@@ -1005,11 +1446,13 @@ sane_start(SANE_Handle h)
NULL);
if (st != SANE_STATUS_GOOD)
return st;
- if(handler->scanner->caps[handler->scanner->source].default_color)
- free(handler->scanner->caps[handler->scanner->source].default_color);
if (handler->val[OPT_PREVIEW].w == SANE_TRUE)
{
- int i = 0, val = 9999;;
+ int i = 0, val = 9999;
+
+ if(handler->scanner->caps[handler->scanner->source].default_color)
+ free(handler->scanner->caps[handler->scanner->source].default_color);
+
if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE ||
!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
handler->scanner->caps[handler->scanner->source].default_color =
@@ -1032,15 +1475,18 @@ sane_start(SANE_Handle h)
{
handler->scanner->caps[handler->scanner->source].default_resolution =
handler->val[OPT_RESOLUTION].w;
- if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
- handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8");
- else if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
- handler->scanner->caps[handler->scanner->source].default_color =
- strdup("BlackAndWhite1");
- else
- handler->scanner->caps[handler->scanner->source].default_color =
- strdup("RGB24");
+ if (!handler->scanner->caps[handler->scanner->source].default_color) {
+ if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
+ handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8");
+ else if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("BlackAndWhite1");
+ else
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("RGB24");
+ }
}
+ DBG (10, "Before newjob Color Mode allocation (%s).\n", handler->scanner->caps[handler->scanner->source].default_color);
handler->scanner->caps[handler->scanner->source].height =
MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
handler->scanner->caps[handler->scanner->source].width =
@@ -1066,6 +1512,67 @@ sane_start(SANE_Handle h)
DBG (10, "Default Color allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
+
+ if (handler->scanner->threshold) {
+ DBG(10, "Have Thresold\n");
+ if (IS_ACTIVE(OPT_THRESHOLD)) {
+ DBG(10, "Use Thresold [%d]\n", handler->val[OPT_THRESHOLD].w);
+ handler->scanner->val_threshold = handler->val[OPT_THRESHOLD].w;
+ handler->scanner->use_threshold = 1;
+ }
+ else {
+ DBG(10, "Not use Thresold\n");
+ handler->scanner->use_threshold = 0;
+ }
+ }
+ else
+ DBG(10, "Don't have Thresold\n");
+
+ if (handler->scanner->sharpen) {
+ DBG(10, "Have Sharpen\n");
+ if (IS_ACTIVE(OPT_SHARPEN)) {
+ DBG(10, "Use Sharpen [%d]\n", handler->val[OPT_SHARPEN].w);
+ handler->scanner->val_sharpen = handler->val[OPT_SHARPEN].w;
+ handler->scanner->use_sharpen = 1;
+ }
+ else {
+ DBG(10, "Not use Sharpen\n");
+ handler->scanner->use_sharpen = 0;
+ }
+ }
+ else
+ DBG(10, "Don't have Sharpen\n");
+
+ if (handler->scanner->contrast) {
+ DBG(10, "Have Contrast\n");
+ if (IS_ACTIVE(OPT_CONTRAST)) {
+ DBG(10, "Use Contrast [%d]\n", handler->val[OPT_CONTRAST].w);
+ handler->scanner->val_contrast = handler->val[OPT_CONTRAST].w;
+ handler->scanner->use_contrast = 1;
+ }
+ else {
+ DBG(10, "Not use Contrast\n");
+ handler->scanner->use_contrast = 0;
+ }
+ }
+ else
+ DBG(10, "Don't have Contrast\n");
+
+ if (handler->scanner->brightness) {
+ DBG(10, "Have Brightness\n");
+ if (IS_ACTIVE(OPT_BRIGHTNESS)) {
+ DBG(10, "Use Brightness [%d]\n", handler->val[OPT_BRIGHTNESS].w);
+ handler->scanner->val_brightness = handler->val[OPT_BRIGHTNESS].w;
+ handler->scanner->use_brightness = 1;
+ }
+ else {
+ DBG(10, "Not use Brightness\n");
+ handler->scanner->use_brightness = 0;
+ }
+ }
+ else
+ DBG(10, "Don't have Brightness\n");
+
handler->result = escl_newjob(handler->scanner, handler->device, &status);
if (status != SANE_STATUS_GOOD)
return (status);
@@ -1104,7 +1611,7 @@ sane_start(SANE_Handle h)
status = get_PDF_data(handler->scanner, &w, &he, &bps);
}
else {
- DBG(10, "Unknow image format\n");
+ DBG(10, "Unknown image format\n");
return SANE_STATUS_INVAL;
}
@@ -1257,6 +1764,12 @@ escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
DBG( 1, "escl_curl_url: URL: %s\n", url );
curl_easy_setopt(handle, CURLOPT_URL, url);
free(url);
+ DBG( 1, "Before use hack\n");
+ if (device->hack) {
+ DBG( 1, "Use hack\n");
+ curl_easy_setopt(handle, CURLOPT_HTTPHEADER, device->hack);
+ }
+ DBG( 1, "After use hack\n");
if (device->https) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);