diff --git a/backend/Makefile.am b/backend/Makefile.am index 7a7354782..5930c5225 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -437,13 +437,13 @@ EXTRA_DIST += dmc.conf.in if have_libavahi if have_libcurl if have_libxml2 -libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c -libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl +libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c escl/escl_jpeg.c escl/escl_png.c +libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl nodist_libsane_escl_la_SOURCES = escl-s.c -libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl +libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl libsane_escl_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(JPEG_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS) +libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(JPEG_LIBS) $(PNG_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS) endif endif endif diff --git a/backend/escl/escl.c b/backend/escl/escl.c index 6a82d87eb..3c89f8009 100644 --- a/backend/escl/escl.c +++ b/backend/escl/escl.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "../include/sane/saneopts.h" @@ -54,9 +54,6 @@ typedef struct Handled { capabilities_t *scanner; SANE_Range x_range; SANE_Range y_range; - unsigned char *img_data; - long img_size; - long img_read; SANE_Bool cancel; SANE_Bool write_scan_data; SANE_Bool decompress_scan_data; @@ -64,19 +61,6 @@ typedef struct Handled { SANE_Parameters ps; } escl_sane_t; -struct my_error_mgr -{ - struct jpeg_error_mgr errmgr; - jmp_buf escape; -}; - -typedef struct -{ - struct jpeg_source_mgr pub; - FILE *ctx; - unsigned char buffer[INPUT_BUFFER_SIZE]; -} my_source_mgr; - /** * \fn static SANE_Status escl_add_in_list(ESCL_Device *current) * \brief Function that adds all the element needed to my list : @@ -607,43 +591,6 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int return (SANE_STATUS_GOOD); } -#if(defined HAVE_LIBJPEG) -static void -error_exit(j_common_ptr cinfo) -{ - longjmp(cinfo->client_data, 1); -} - -/** - * \fn static void get_JPEG_dimension(FILE *fp, int *w, int *h) - * \brief Function that aims to get the dimensions of the jpeg image wich will be scanned. - * This function is called in the "sane_start" function. - */ -static void -get_JPEG_dimension(FILE *fp, int *w, int *h) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - jmp_buf env; - - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = error_exit; - cinfo.client_data = env; - if (setjmp(env)) - return; - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, fp); - jpeg_read_header(&cinfo, TRUE); - cinfo.out_color_space = JCS_RGB; - jpeg_start_decompress(&cinfo); - *w = cinfo.output_width; - *h = cinfo.output_height; - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fseek(fp, SEEK_SET, 0); -} -#endif - /** * \fn SANE_Status sane_start(SANE_Handle h) * \brief Function that initiates aquisition of an image from the device represented by handle 'h'. @@ -659,6 +606,7 @@ sane_start(SANE_Handle h) escl_sane_t *handler = h; int w = 0; int he = 0; + int bps = 0; if (handler->name == NULL) return (SANE_STATUS_INVAL); @@ -699,12 +647,26 @@ sane_start(SANE_Handle h) if (status != SANE_STATUS_GOOD) return (status); status = escl_scan(handler->scanner, handler->name, handler->result); - get_JPEG_dimension(handler->scanner->tmp, &w, &he); + fprintf(stderr, "DIM : [%s]\n", handler->scanner->default_format); + if (!strncmp(handler->scanner->default_format, "image/jpeg", 10)) + { + get_JPEG_dimension(handler->scanner->tmp, &w, &he, &bps); + fprintf(stderr, "JPEG DIM : [%s]\n", handler->scanner->default_format); + } + else + { + get_PNG_dimension(handler->scanner->tmp, &w, &he, &bps); + fprintf(stderr, "PNG DIM : [%s]\n", handler->scanner->default_format); + } + fprintf(stderr, "SIZE [%dx%dx%d]\n", w, he, bps); + if (bps == 0) + return SANE_STATUS_INVAL; + fprintf(stderr, "2-SIZE [%dx%dx%d]\n", w, he, bps); fseek(handler->scanner->tmp, SEEK_SET, 0); handler->ps.depth = 8; handler->ps.pixels_per_line = w; handler->ps.lines = he; - handler->ps.bytes_per_line = w * 3; + handler->ps.bytes_per_line = w * bps; handler->ps.last_frame = SANE_TRUE; handler->ps.format = SANE_FRAME_RGB; return (status); @@ -733,162 +695,14 @@ sane_get_parameters(SANE_Handle h, SANE_Parameters *p) p->format = SANE_FRAME_RGB; p->pixels_per_line = handler->ps.pixels_per_line; p->lines = handler->ps.lines; - p->bytes_per_line = handler->ps.pixels_per_line * 3; + p->bytes_per_line = handler->ps.bytes_per_line; + fprintf(stderr, "GET SIZE [%dx%dx%d]\n", p->pixels_per_line, + p->lines, + (p->bytes_per_line / p->pixels_per_line)); } return (status); } -#if(defined HAVE_LIBJPEG) -/** - * \fn static boolean fill_input_buffer(j_decompress_ptr cinfo) - * \brief Called in the "skip_input_data" function. - * - * \return TRUE (everything is OK) - */ -static boolean -fill_input_buffer(j_decompress_ptr cinfo) -{ - my_source_mgr *src = (my_source_mgr *) cinfo->src; - int nbytes = 0; - - nbytes = fread(src->buffer, 1, INPUT_BUFFER_SIZE, src->ctx); - if (nbytes <= 0) { - src->buffer[0] = (unsigned char) 0xFF; - src->buffer[1] = (unsigned char) JPEG_EOI; - nbytes = 2; - } - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - return (TRUE); -} - -/** - * \fn static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) - * \brief Called in the "jpeg_RW_src" function. - */ -static void -skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - my_source_mgr *src = (my_source_mgr *) cinfo->src; - - if (num_bytes > 0) { - while (num_bytes > (long) src->pub.bytes_in_buffer) { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) src->pub.fill_input_buffer(cinfo); - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - -static void -term_source(j_decompress_ptr __sane_unused__ cinfo) -{ - return; -} - -static void -init_source(j_decompress_ptr __sane_unused__ cinfo) -{ - return; -} - -/** - * \fn static void jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) - * \brief Called in the "escl_sane_decompressor" function. - */ -static void -jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) -{ - my_source_mgr *src; - - if (cinfo->src == NULL) { - cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); - src = (my_source_mgr *) cinfo->src; - } - src = (my_source_mgr *) cinfo->src; - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; - src->pub.term_source = term_source; - src->ctx = ctx; - src->pub.bytes_in_buffer = 0; - src->pub.next_input_byte = NULL; -} - -static void -my_error_exit(j_common_ptr cinfo) -{ - struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err; - - longjmp(err->escape, 1); -} - -static void -output_no_message(j_common_ptr __sane_unused__ cinfo) -{ -} - -/** - * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) - * \brief Function that aims to decompress the jpeg image to SANE be able to read the image. - * This function is called in the "sane_read" function. - * - * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) - */ -SANE_Status -escl_sane_decompressor(escl_sane_t *handler) -{ - int start = 0; - struct jpeg_decompress_struct cinfo; - JSAMPROW rowptr[1]; - unsigned char *surface = NULL; - struct my_error_mgr jerr; - int lineSize = 0; - - if (handler->scanner->tmp == NULL) - return (SANE_STATUS_INVAL); - fseek(handler->scanner->tmp, SEEK_SET, 0); - start = ftell(handler->scanner->tmp); - cinfo.err = jpeg_std_error(&jerr.errmgr); - jerr.errmgr.error_exit = my_error_exit; - jerr.errmgr.output_message = output_no_message; - if (setjmp(jerr.escape)) { - jpeg_destroy_decompress(&cinfo); - if (surface != NULL) - free(surface); - return (SANE_STATUS_INVAL); - } - jpeg_create_decompress(&cinfo); - jpeg_RW_src(&cinfo, handler->scanner->tmp); - jpeg_read_header(&cinfo, TRUE); - cinfo.out_color_space = JCS_RGB; - cinfo.quantize_colors = FALSE; - jpeg_calc_output_dimensions(&cinfo); - surface = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components); - if (surface == NULL) { - jpeg_destroy_decompress(&cinfo); - fseek(handler->scanner->tmp, start, SEEK_SET); - return (SANE_STATUS_NO_MEM); - } - lineSize = cinfo.output_width * cinfo.output_components; - jpeg_start_decompress(&cinfo); - while (cinfo.output_scanline < cinfo.output_height) { - rowptr[0] = (JSAMPROW)surface + (lineSize * cinfo.output_scanline); - jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); - } - handler->img_data = surface; - handler->img_size = lineSize * cinfo.output_height; - handler->img_read = 0; - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(handler->scanner->tmp); - handler->scanner->tmp = NULL; - return (SANE_STATUS_GOOD); -} -#endif /** * \fn SANE_Status sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) @@ -916,32 +730,40 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) if (!handler->decompress_scan_data) { if (handler->scanner->tmp == NULL) return (SANE_STATUS_INVAL); - status = escl_sane_decompressor(handler); + fprintf(stderr, "READ : [%s]\n", handler->scanner->default_format); + if (!strncmp(handler->scanner->default_format, "image/jpeg", 10)){ + fprintf(stderr, "JPEG READ : [%s]\n", handler->scanner->default_format); + status = get_JPEG_data(handler->scanner); + } + else{ + fprintf(stderr, "PNG READ : [%s]\n", handler->scanner->default_format); + status = get_PNG_data(handler->scanner); + } if (status != SANE_STATUS_GOOD) return (status); handler->decompress_scan_data = SANE_TRUE; } - if (handler->img_data == NULL) + if (handler->scanner->img_data == NULL) return (SANE_STATUS_INVAL); if (!handler->end_read) { - readbyte = min((handler->img_size - handler->img_read), maxlen); - memcpy(buf, handler->img_data + handler->img_read, readbyte); - handler->img_read = handler->img_read + readbyte; + readbyte = min((handler->scanner->img_size - handler->scanner->img_read), maxlen); + memcpy(buf, handler->scanner->img_data + handler->scanner->img_read, readbyte); + handler->scanner->img_read = handler->scanner->img_read + readbyte; *len = readbyte; - if (handler->img_read == handler->img_size) + if (handler->scanner->img_read == handler->scanner->img_size) handler->end_read = SANE_TRUE; - else if (handler->img_read > handler->img_size) { + else if (handler->scanner->img_read > handler->scanner->img_size) { *len = 0; handler->end_read = SANE_TRUE; - free(handler->img_data); - handler->img_data = NULL; + free(handler->scanner->img_data); + handler->scanner->img_data = NULL; return (SANE_STATUS_INVAL); } } else { *len = 0; - free(handler->img_data); - handler->img_data = NULL; + free(handler->scanner->img_data); + handler->scanner->img_data = NULL; return (SANE_STATUS_EOF); } return (SANE_STATUS_GOOD); diff --git a/backend/escl/escl.h b/backend/escl/escl.h index 559825af2..d72593864 100644 --- a/backend/escl/escl.h +++ b/backend/escl/escl.h @@ -40,6 +40,12 @@ #error "The escl backend currently requires libjpeg" #endif +#ifndef HAVE_LIBPNG +/* FIXME: Make PNG support optional. + */ +#warning "The escl backend recommends libpng" +#endif + #include "../include/sane/sane.h" #include @@ -78,7 +84,7 @@ typedef struct capabilities int pos_x; int pos_y; SANE_String default_color; - SANE_String_Const default_format; + SANE_String default_format; SANE_Int default_resolution; int MinWidth; int MaxWidth; @@ -102,6 +108,9 @@ typedef struct capabilities int RiskyTopMargin; int RiskyBottomMargin; FILE *tmp; + unsigned char *img_data; + long img_size; + long img_read; int format_ext; } capabilities_t; @@ -143,4 +152,12 @@ char *escl_newjob(capabilities_t *scanner, SANE_String_Const name, SANE_Status * SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result); void escl_scanner(SANE_String_Const name, char *result); +# JPEG +void get_JPEG_dimension(FILE *fp, int *w, int *h, int *bps); +SANE_Status get_JPEG_data(capabilities_t *scanner); + +# PNG +void get_PNG_dimension(FILE *fp, int *w, int *h, int *bps); +SANE_Status get_PNG_data(capabilities_t *scanner); + #endif diff --git a/backend/escl/escl_capabilities.c b/backend/escl/escl_capabilities.c index 17013c9d3..e7f593670 100644 --- a/backend/escl/escl_capabilities.c +++ b/backend/escl/escl_capabilities.c @@ -181,7 +181,30 @@ find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner) else if (strcmp(name, "ContentType") == 0) scanner->ContentTypes = char_to_array(scanner->ContentTypes, &scanner->ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0); else if (strcmp(name, "DocumentFormat") == 0) + { + int i = 0; scanner->DocumentFormats = char_to_array(scanner->DocumentFormats, &scanner->DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0); + for(; i < scanner->DocumentFormatsSize; i++) + { + if (scanner->default_format == NULL && !strncmp(scanner->DocumentFormats[i], "image/jpeg", 10)) + { + scanner->default_format = strdup("image/jpeg"); +#if(defined HAVE_LIBPNG) + } + else if(!strncmp(scanner->DocumentFormats[i], "image/png", 9)) + { + if (scanner->default_format) + free(scanner->default_format); + scanner->default_format = strdup("image/png"); + break; + } +#else + break; + } +#endif + } + fprintf(stderr, "Capability : [%s]\n", scanner->default_format); + } else if (strcmp(name, "DocumentFormatExt") == 0) scanner->format_ext = 1; else if (strcmp(name, "Intent") == 0) diff --git a/backend/escl/escl_jpeg.c b/backend/escl/escl_jpeg.c new file mode 100644 index 000000000..38ac41c40 --- /dev/null +++ b/backend/escl/escl_jpeg.c @@ -0,0 +1,231 @@ +#include "escl.h" + +#include "../include/sane/sanei.h" + +#include +#include +#include + +#if(defined HAVE_LIBJPEG) +# include +#endif + +#include + +#define INPUT_BUFFER_SIZE 4096 + +#if(defined HAVE_LIBJPEG) +struct my_error_mgr +{ + struct jpeg_error_mgr errmgr; + jmp_buf escape; +}; + +typedef struct +{ + struct jpeg_source_mgr pub; + FILE *ctx; + unsigned char buffer[INPUT_BUFFER_SIZE]; +} my_source_mgr; + + +static void +error_exit(j_common_ptr cinfo) +{ + longjmp(cinfo->client_data, 1); +} + +/** + * \fn static void get_JPEG_dimension(FILE *fp, int *w, int *h) + * \brief Function that aims to get the dimensions of the jpeg image wich will be scanned. + * This function is called in the "sane_start" function. + */ +void +get_JPEG_dimension(FILE *fp, int *w, int *h, int *bps) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + jmp_buf env; + + cinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = error_exit; + cinfo.client_data = env; + if (setjmp(env)) + return; + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, fp); + jpeg_read_header(&cinfo, TRUE); + cinfo.out_color_space = JCS_RGB; + jpeg_start_decompress(&cinfo); + *w = cinfo.output_width; + *h = cinfo.output_height; + *bps = 3; + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fseek(fp, SEEK_SET, 0); +} + + +/** + * \fn static boolean fill_input_buffer(j_decompress_ptr cinfo) + * \brief Called in the "skip_input_data" function. + * + * \return TRUE (everything is OK) + */ +static boolean +fill_input_buffer(j_decompress_ptr cinfo) +{ + my_source_mgr *src = (my_source_mgr *) cinfo->src; + int nbytes = 0; + + nbytes = fread(src->buffer, 1, INPUT_BUFFER_SIZE, src->ctx); + if (nbytes <= 0) { + src->buffer[0] = (unsigned char) 0xFF; + src->buffer[1] = (unsigned char) JPEG_EOI; + nbytes = 2; + } + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + return (TRUE); +} + +/** + * \fn static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) + * \brief Called in the "jpeg_RW_src" function. + */ +static void +skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + my_source_mgr *src = (my_source_mgr *) cinfo->src; + + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) src->pub.fill_input_buffer(cinfo); + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void +term_source(j_decompress_ptr __sane_unused__ cinfo) +{ + return; +} + +static void +init_source(j_decompress_ptr __sane_unused__ cinfo) +{ + return; +} + +/** + * \fn static void jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) + * \brief Called in the "escl_sane_decompressor" function. + */ +static void +jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) +{ + my_source_mgr *src; + + if (cinfo->src == NULL) { + cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); + src = (my_source_mgr *) cinfo->src; + } + src = (my_source_mgr *) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = term_source; + src->ctx = ctx; + src->pub.bytes_in_buffer = 0; + src->pub.next_input_byte = NULL; +} + +static void +my_error_exit(j_common_ptr cinfo) +{ + struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err; + + longjmp(err->escape, 1); +} + +static void +output_no_message(j_common_ptr __sane_unused__ cinfo) +{ +} + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the jpeg image to SANE be able to read the image. + * This function is called in the "sane_read" function. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +get_JPEG_data(capabilities_t *scanner) +{ + int start = 0; + struct jpeg_decompress_struct cinfo; + JSAMPROW rowptr[1]; + unsigned char *surface = NULL; + struct my_error_mgr jerr; + int lineSize = 0; + + if (scanner->tmp == NULL) + return (SANE_STATUS_INVAL); + fseek(scanner->tmp, SEEK_SET, 0); + start = ftell(scanner->tmp); + cinfo.err = jpeg_std_error(&jerr.errmgr); + jerr.errmgr.error_exit = my_error_exit; + jerr.errmgr.output_message = output_no_message; + if (setjmp(jerr.escape)) { + jpeg_destroy_decompress(&cinfo); + if (surface != NULL) + free(surface); + return (SANE_STATUS_INVAL); + } + jpeg_create_decompress(&cinfo); + jpeg_RW_src(&cinfo, scanner->tmp); + jpeg_read_header(&cinfo, TRUE); + cinfo.out_color_space = JCS_RGB; + cinfo.quantize_colors = FALSE; + jpeg_calc_output_dimensions(&cinfo); + surface = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components); + if (surface == NULL) { + jpeg_destroy_decompress(&cinfo); + fseek(scanner->tmp, start, SEEK_SET); + return (SANE_STATUS_NO_MEM); + } + lineSize = cinfo.output_width * cinfo.output_components; + jpeg_start_decompress(&cinfo); + while (cinfo.output_scanline < cinfo.output_height) { + rowptr[0] = (JSAMPROW)surface + (lineSize * cinfo.output_scanline); + jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); + } + scanner->img_data = surface; + scanner->img_size = lineSize * cinfo.output_height; + scanner->img_read = 0; + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(scanner->tmp); + scanner->tmp = NULL; + return (SANE_STATUS_GOOD); +} +#else + +void +get_JPEG_dimension(FILE __sane_unused__ *fp, int __sane_unused__ *w, + int __sane_unused__ *h, int __sane_unused__ *bps) +{ +} + +SANE_Status +get_JPEG_data(capabilities_t __sane_unused__ *scanner) +{ +} + +#endif diff --git a/backend/escl/escl_newjob.c b/backend/escl/escl_newjob.c index 559bf9785..d5caad059 100644 --- a/backend/escl/escl_newjob.c +++ b/backend/escl/escl_newjob.c @@ -54,7 +54,7 @@ static const char settings[] = " %d" \ " " \ " " \ - " image/jpeg" \ + " %s" \ "%s" \ " %s" \ " %d" \ @@ -62,9 +62,12 @@ static const char settings[] = " Platen" \ ""; -static const char formatExt[] = +static char formatExtJPEG[] = " image/jpeg"; +static char formatExtPNG[] = + " image/png"; + /** * \fn static size_t download_callback(void *str, size_t size, size_t nmemb, void *userp) * \brief Callback function that stocks in memory the content of the 'job'. Example below : @@ -127,6 +130,8 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu char *location = NULL; char *result = NULL; char *temporary = NULL; + char *f_ext = ""; + char *format_ext = NULL; *status = SANE_STATUS_GOOD; if (name == NULL || scanner == NULL) { @@ -146,11 +151,20 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu } curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); + if (scanner->format_ext == 1) + { + if (!strncmp(scanner->default_format, "image/jpeg", 10)) + format_ext = formatExtJPEG; + else + format_ext = formatExtPNG; + } + else + format_ext = f_ext; if (curl_handle != NULL) { - snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0, - (scanner->format_ext == 1 ? formatExt : ""), + snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0, scanner->default_format, + format_ext, scanner->default_color, scanner->default_resolution, scanner->default_resolution); - //fprintf(stderr, "CAP_DATA = %s\n", cap_data); + fprintf(stderr, "CAP_DATA = %s\n", cap_data); upload->read_data = strdup(cap_data); upload->size = strlen(cap_data); download->memory = malloc(1); diff --git a/backend/escl/escl_png.c b/backend/escl/escl_png.c new file mode 100644 index 000000000..7964911c3 --- /dev/null +++ b/backend/escl/escl_png.c @@ -0,0 +1,226 @@ +#include "escl.h" + +#include "../include/sane/sanei.h" + +#include +#include +#include + +#if(defined HAVE_LIBPNG) +#include +#endif + +#include + + +#if(defined HAVE_LIBPNG) + +/** + * \fn static void get_PNG_dimension(FILE *fp, int *w, int *h) + * \brief Function that aims to get the dimensions of the png image wich will be scanned. + * This function is called in the "sane_start" function. + */ +void +get_PNG_dimension(FILE *fp, int *w, int *h, int *bps) +{ + unsigned int width, height; + png_byte magic[8]; + fread (magic, 1, sizeof (magic), fp); + /* check for valid magic number */ + if (!png_check_sig (magic, sizeof (magic))) + { + fprintf (stderr, "error: is not a valid PNG image!\n"); + return; + } + /* create a png read struct */ + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + return; + } + /* create a png info struct */ + png_infop info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + png_destroy_read_struct (&png_ptr, NULL, NULL); + return; + } + /* initialize the setjmp for returning properly after a libpng + error occured */ + if (setjmp (png_jmpbuf (png_ptr))) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + return; + } + /* setup libpng for using standard C fread() function + with our FILE pointer */ + png_init_io (png_ptr, fp); + /* tell libpng that we have already read the magic number */ + png_set_sig_bytes (png_ptr, sizeof (magic)); + + /* read png info */ + png_read_info (png_ptr, info_ptr); + + int bit_depth, color_type; + /* get some usefull information from header */ + bit_depth = png_get_bit_depth (png_ptr, info_ptr); + color_type = png_get_color_type (png_ptr, info_ptr); + /* convert index color images to RGB images */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png_ptr); + else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) + { + fprintf(stderr, "Format non pris en charge.\n"); + return; + } + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + *bps = 4; + else + *bps = 3; + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png_ptr); + if (bit_depth == 16) + png_set_strip_16 (png_ptr); + else if (bit_depth < 8) + png_set_packing (png_ptr); + /* update info structure to apply transformations */ + png_read_update_info (png_ptr, info_ptr); + /* retrieve updated information */ + png_get_IHDR (png_ptr, info_ptr, + (png_uint_32*)(&width), + (png_uint_32*)(&height), + &bit_depth, &color_type, + NULL, NULL, NULL); + *w = (int)width; + *h = (int)height; + /* finish decompression and release memory */ + png_read_end (png_ptr, NULL); + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + fseek(fp, SEEK_SET, 0); +} + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the png image to SANE be able to read the image. + * This function is called in the "sane_read" function. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +get_PNG_data(capabilities_t *scanner) +{ + unsigned int width = 0; /* largeur */ + unsigned int height = 0; /* hauteur */ + int bps = 3; /* composantes d'un texel */ + unsigned char *texels = NULL; /* données de l'image */ + unsigned int i = 0; + png_byte magic[8]; + + // read magic number + fread (magic, 1, sizeof (magic), scanner->tmp); + // check for valid magic number + if (!png_check_sig (magic, sizeof (magic))) + { + fprintf(stderr,"PNG error: is not a valid PNG image!\n"); + return (SANE_STATUS_INVAL); + } + // create a png read struct + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + return (SANE_STATUS_INVAL); + } + // create a png info struct + png_infop info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + png_destroy_read_struct (&png_ptr, NULL, NULL); + return (SANE_STATUS_INVAL); + } + // initialize the setjmp for returning properly after a libpng + // error occured + if (setjmp (png_jmpbuf (png_ptr))) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + if (texels) + free (texels); + fprintf(stderr,"PNG read error.\n"); + return (SANE_STATUS_INVAL); + } + // setup libpng for using standard C fread() function + // with our FILE pointer + png_init_io (png_ptr, scanner->tmp); + // tell libpng that we have already read the magic number + png_set_sig_bytes (png_ptr, sizeof (magic)); + + // read png info + png_read_info (png_ptr, info_ptr); + + int bit_depth, color_type; + // get some usefull information from header + bit_depth = png_get_bit_depth (png_ptr, info_ptr); + color_type = png_get_color_type (png_ptr, info_ptr); + // convert index color images to RGB images + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png_ptr); + else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) + { + fprintf(stderr,"PNG format not supported.\n"); + return (SANE_STATUS_INVAL); + } + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bps = 4; + else + bps = 3; + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png_ptr); + if (bit_depth == 16) + png_set_strip_16 (png_ptr); + else if (bit_depth < 8) + png_set_packing (png_ptr); + // update info structure to apply transformations + png_read_update_info (png_ptr, info_ptr); + // retrieve updated information + png_get_IHDR (png_ptr, info_ptr, + (png_uint_32*)(&width), + (png_uint_32*)(&height), + &bit_depth, &color_type, + NULL, NULL, NULL); + // we can now allocate memory for storing pixel data + texels = (unsigned char *)malloc (sizeof (unsigned char) * width + * height * bps); + png_bytep *row_pointers; + // setup a pointer array. Each one points at the begening of a row. + row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * height); + for (i = 0; i < height; ++i) + { + row_pointers[i] = (png_bytep)(texels + + ((height - (i + 1)) * width * bps)); + } + // read pixel data using row pointers + png_read_image (png_ptr, row_pointers); + // we don't need row pointers anymore + scanner->img_data = texels; + scanner->img_size = (int)(width * height * bps); + scanner->img_read = 0; + free (row_pointers); + fclose(scanner->tmp); + scanner->tmp = NULL; + return (SANE_STATUS_GOOD); +} +#else + +void +get_PNG_dimension(FILE __sane_unused__ *fp, int __sane_unused__ *w, + int __sane_unused__ *h, int __sane_unused__ *bps) +{ +} + +SANE_Status +get_PNG_data(capabilities_t __sane_unused__ *scanner) +{ +} + +#endif