kopia lustrzana https://gitlab.com/sane-project/backends
Adding png support. The decompressors (Jpeg and Png) are in separate files.
rodzic
92308130f4
commit
5c15d37248
|
@ -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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <jpeglib.h>
|
||||
#include <png.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
#include "escl.h"
|
||||
|
||||
#include "../include/sane/sanei.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if(defined HAVE_LIBJPEG)
|
||||
# include <jpeglib.h>
|
||||
#endif
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#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
|
|
@ -54,7 +54,7 @@ static const char settings[] =
|
|||
" <pwg:YOffset>%d</pwg:YOffset>" \
|
||||
" </pwg:ScanRegion>" \
|
||||
" </pwg:ScanRegions>" \
|
||||
" <pwg:DocumentFormat>image/jpeg</pwg:DocumentFormat>" \
|
||||
" <pwg:DocumentFormat>%s</pwg:DocumentFormat>" \
|
||||
"%s" \
|
||||
" <scan:ColorMode>%s</scan:ColorMode>" \
|
||||
" <scan:XResolution>%d</scan:XResolution>" \
|
||||
|
@ -62,9 +62,12 @@ static const char settings[] =
|
|||
" <pwg:InputSource>Platen</pwg:InputSource>" \
|
||||
"</scan:ScanSettings>";
|
||||
|
||||
static const char formatExt[] =
|
||||
static char formatExtJPEG[] =
|
||||
" <scan:DocumentFormatExt>image/jpeg</scan:DocumentFormatExt>";
|
||||
|
||||
static char formatExtPNG[] =
|
||||
" <scan:DocumentFormatExt>image/png</scan:DocumentFormatExt>";
|
||||
|
||||
/**
|
||||
* \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);
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
#include "escl.h"
|
||||
|
||||
#include "../include/sane/sanei.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if(defined HAVE_LIBPNG)
|
||||
#include <png.h>
|
||||
#endif
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
#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
|
Ładowanie…
Reference in New Issue