diff options
Diffstat (limited to 'backend/escl/escl.c')
| -rw-r--r-- | backend/escl/escl.c | 587 | 
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 = ⦥ +      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 = ⦥ +      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 = ⦥ +      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 = ⦥ +      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); | 
