1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2019 Touboul Nathane 4141cc406Sopenharmony_ci Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com> 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This file is part of the SANE package. 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci SANE is free software; you can redistribute it and/or modify it under 9141cc406Sopenharmony_ci the terms of the GNU General Public License as published by the Free 10141cc406Sopenharmony_ci Software Foundation; either version 3 of the License, or (at your 11141cc406Sopenharmony_ci option) any later version. 12141cc406Sopenharmony_ci 13141cc406Sopenharmony_ci SANE is distributed in the hope that it will be useful, but WITHOUT 14141cc406Sopenharmony_ci ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15141cc406Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16141cc406Sopenharmony_ci for more details. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 19141cc406Sopenharmony_ci along with sane; see the file COPYING. 20141cc406Sopenharmony_ci If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci This file implements a SANE backend for eSCL scanners. */ 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 25141cc406Sopenharmony_ci#include "../include/sane/config.h" 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci#include "escl.h" 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci#include <stdio.h> 32141cc406Sopenharmony_ci#include <stdlib.h> 33141cc406Sopenharmony_ci#include <string.h> 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci#if(defined HAVE_LIBJPEG) 36141cc406Sopenharmony_ci# include <jpeglib.h> 37141cc406Sopenharmony_ci#endif 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci#include <setjmp.h> 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci#define INPUT_BUFFER_SIZE 4096 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci#if(defined HAVE_LIBJPEG) 44141cc406Sopenharmony_cistruct my_error_mgr 45141cc406Sopenharmony_ci{ 46141cc406Sopenharmony_ci struct jpeg_error_mgr errmgr; 47141cc406Sopenharmony_ci jmp_buf escape; 48141cc406Sopenharmony_ci}; 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_citypedef struct 51141cc406Sopenharmony_ci{ 52141cc406Sopenharmony_ci struct jpeg_source_mgr pub; 53141cc406Sopenharmony_ci FILE *ctx; 54141cc406Sopenharmony_ci unsigned char buffer[INPUT_BUFFER_SIZE]; 55141cc406Sopenharmony_ci} my_source_mgr; 56141cc406Sopenharmony_ci 57141cc406Sopenharmony_ci/** 58141cc406Sopenharmony_ci * \fn static boolean fill_input_buffer(j_decompress_ptr cinfo) 59141cc406Sopenharmony_ci * \brief Called in the "skip_input_data" function. 60141cc406Sopenharmony_ci * 61141cc406Sopenharmony_ci * \return TRUE (everything is OK) 62141cc406Sopenharmony_ci */ 63141cc406Sopenharmony_cistatic boolean 64141cc406Sopenharmony_cifill_input_buffer(j_decompress_ptr cinfo) 65141cc406Sopenharmony_ci{ 66141cc406Sopenharmony_ci my_source_mgr *src = (my_source_mgr *) cinfo->src; 67141cc406Sopenharmony_ci int nbytes = 0; 68141cc406Sopenharmony_ci 69141cc406Sopenharmony_ci nbytes = fread(src->buffer, 1, INPUT_BUFFER_SIZE, src->ctx); 70141cc406Sopenharmony_ci if (nbytes <= 0) { 71141cc406Sopenharmony_ci src->buffer[0] = (unsigned char) 0xFF; 72141cc406Sopenharmony_ci src->buffer[1] = (unsigned char) JPEG_EOI; 73141cc406Sopenharmony_ci nbytes = 2; 74141cc406Sopenharmony_ci } 75141cc406Sopenharmony_ci src->pub.next_input_byte = src->buffer; 76141cc406Sopenharmony_ci src->pub.bytes_in_buffer = nbytes; 77141cc406Sopenharmony_ci return (TRUE); 78141cc406Sopenharmony_ci} 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci/** 81141cc406Sopenharmony_ci * \fn static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) 82141cc406Sopenharmony_ci * \brief Called in the "jpeg_RW_src" function. 83141cc406Sopenharmony_ci */ 84141cc406Sopenharmony_cistatic void 85141cc406Sopenharmony_ciskip_input_data(j_decompress_ptr cinfo, long num_bytes) 86141cc406Sopenharmony_ci{ 87141cc406Sopenharmony_ci my_source_mgr *src = (my_source_mgr *) cinfo->src; 88141cc406Sopenharmony_ci 89141cc406Sopenharmony_ci if (num_bytes > 0) { 90141cc406Sopenharmony_ci while (num_bytes > (long) src->pub.bytes_in_buffer) { 91141cc406Sopenharmony_ci num_bytes -= (long) src->pub.bytes_in_buffer; 92141cc406Sopenharmony_ci (void) src->pub.fill_input_buffer(cinfo); 93141cc406Sopenharmony_ci } 94141cc406Sopenharmony_ci src->pub.next_input_byte += (size_t) num_bytes; 95141cc406Sopenharmony_ci src->pub.bytes_in_buffer -= (size_t) num_bytes; 96141cc406Sopenharmony_ci } 97141cc406Sopenharmony_ci} 98141cc406Sopenharmony_ci 99141cc406Sopenharmony_cistatic void 100141cc406Sopenharmony_citerm_source(j_decompress_ptr __sane_unused__ cinfo) 101141cc406Sopenharmony_ci{ 102141cc406Sopenharmony_ci return; 103141cc406Sopenharmony_ci} 104141cc406Sopenharmony_ci 105141cc406Sopenharmony_cistatic void 106141cc406Sopenharmony_ciinit_source(j_decompress_ptr __sane_unused__ cinfo) 107141cc406Sopenharmony_ci{ 108141cc406Sopenharmony_ci return; 109141cc406Sopenharmony_ci} 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci/** 112141cc406Sopenharmony_ci * \fn static void jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) 113141cc406Sopenharmony_ci * \brief Called in the "escl_sane_decompressor" function. 114141cc406Sopenharmony_ci */ 115141cc406Sopenharmony_cistatic void 116141cc406Sopenharmony_cijpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) 117141cc406Sopenharmony_ci{ 118141cc406Sopenharmony_ci my_source_mgr *src; 119141cc406Sopenharmony_ci 120141cc406Sopenharmony_ci if (cinfo->src == NULL) { 121141cc406Sopenharmony_ci cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) 122141cc406Sopenharmony_ci ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); 123141cc406Sopenharmony_ci } 124141cc406Sopenharmony_ci src = (my_source_mgr *) cinfo->src; 125141cc406Sopenharmony_ci src->pub.init_source = init_source; 126141cc406Sopenharmony_ci src->pub.fill_input_buffer = fill_input_buffer; 127141cc406Sopenharmony_ci src->pub.skip_input_data = skip_input_data; 128141cc406Sopenharmony_ci src->pub.resync_to_restart = jpeg_resync_to_restart; 129141cc406Sopenharmony_ci src->pub.term_source = term_source; 130141cc406Sopenharmony_ci src->ctx = ctx; 131141cc406Sopenharmony_ci src->pub.bytes_in_buffer = 0; 132141cc406Sopenharmony_ci src->pub.next_input_byte = NULL; 133141cc406Sopenharmony_ci} 134141cc406Sopenharmony_ci 135141cc406Sopenharmony_cistatic void 136141cc406Sopenharmony_cimy_error_exit(j_common_ptr cinfo) 137141cc406Sopenharmony_ci{ 138141cc406Sopenharmony_ci struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err; 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci longjmp(err->escape, 1); 141141cc406Sopenharmony_ci} 142141cc406Sopenharmony_ci 143141cc406Sopenharmony_cistatic void 144141cc406Sopenharmony_cioutput_no_message(j_common_ptr __sane_unused__ cinfo) 145141cc406Sopenharmony_ci{ 146141cc406Sopenharmony_ci} 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci/** 149141cc406Sopenharmony_ci * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) 150141cc406Sopenharmony_ci * \brief Function that aims to decompress the jpeg image to SANE be able to read the image. 151141cc406Sopenharmony_ci * This function is called in the "sane_read" function. 152141cc406Sopenharmony_ci * 153141cc406Sopenharmony_ci * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) 154141cc406Sopenharmony_ci */ 155141cc406Sopenharmony_ciSANE_Status 156141cc406Sopenharmony_ciget_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps) 157141cc406Sopenharmony_ci{ 158141cc406Sopenharmony_ci int start = 0; 159141cc406Sopenharmony_ci struct jpeg_decompress_struct cinfo; 160141cc406Sopenharmony_ci JSAMPROW rowptr[1]; 161141cc406Sopenharmony_ci unsigned char *surface = NULL; 162141cc406Sopenharmony_ci struct my_error_mgr jerr; 163141cc406Sopenharmony_ci int lineSize = 0; 164141cc406Sopenharmony_ci JDIMENSION x_off = 0; 165141cc406Sopenharmony_ci JDIMENSION y_off = 0; 166141cc406Sopenharmony_ci JDIMENSION w = 0; 167141cc406Sopenharmony_ci JDIMENSION h = 0; 168141cc406Sopenharmony_ci int pos = 0; 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_ci if (scanner->tmp == NULL) 171141cc406Sopenharmony_ci return (SANE_STATUS_INVAL); 172141cc406Sopenharmony_ci fseek(scanner->tmp, SEEK_SET, 0); 173141cc406Sopenharmony_ci start = ftell(scanner->tmp); 174141cc406Sopenharmony_ci cinfo.err = jpeg_std_error(&jerr.errmgr); 175141cc406Sopenharmony_ci jerr.errmgr.error_exit = my_error_exit; 176141cc406Sopenharmony_ci jerr.errmgr.output_message = output_no_message; 177141cc406Sopenharmony_ci if (setjmp(jerr.escape)) { 178141cc406Sopenharmony_ci jpeg_destroy_decompress(&cinfo); 179141cc406Sopenharmony_ci if (surface != NULL) 180141cc406Sopenharmony_ci free(surface); 181141cc406Sopenharmony_ci fseek(scanner->tmp, start, SEEK_SET); 182141cc406Sopenharmony_ci DBG( 1, "Escl Jpeg : Error reading jpeg\n"); 183141cc406Sopenharmony_ci if (scanner->tmp) { 184141cc406Sopenharmony_ci fclose(scanner->tmp); 185141cc406Sopenharmony_ci scanner->tmp = NULL; 186141cc406Sopenharmony_ci } 187141cc406Sopenharmony_ci return (SANE_STATUS_INVAL); 188141cc406Sopenharmony_ci } 189141cc406Sopenharmony_ci jpeg_create_decompress(&cinfo); 190141cc406Sopenharmony_ci jpeg_RW_src(&cinfo, scanner->tmp); 191141cc406Sopenharmony_ci jpeg_read_header(&cinfo, TRUE); 192141cc406Sopenharmony_ci cinfo.out_color_space = JCS_RGB; 193141cc406Sopenharmony_ci cinfo.quantize_colors = FALSE; 194141cc406Sopenharmony_ci jpeg_calc_output_dimensions(&cinfo); 195141cc406Sopenharmony_ci double ratio = (double)cinfo.output_width / (double)scanner->caps[scanner->source].width; 196141cc406Sopenharmony_ci int rw = (int)((double)scanner->caps[scanner->source].width * ratio); 197141cc406Sopenharmony_ci int rh = (int)((double)scanner->caps[scanner->source].height * ratio); 198141cc406Sopenharmony_ci int rx = (int)((double)scanner->caps[scanner->source].pos_x * ratio); 199141cc406Sopenharmony_ci int ry = (int)((double)scanner->caps[scanner->source].pos_y * ratio); 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci 202141cc406Sopenharmony_ci if (cinfo.output_width < (unsigned int)rw) 203141cc406Sopenharmony_ci rw = cinfo.output_width; 204141cc406Sopenharmony_ci if (rx < 0) 205141cc406Sopenharmony_ci rx = 0; 206141cc406Sopenharmony_ci 207141cc406Sopenharmony_ci if (cinfo.output_height < (unsigned int)rh) 208141cc406Sopenharmony_ci rh = cinfo.output_height; 209141cc406Sopenharmony_ci if (ry < 0) 210141cc406Sopenharmony_ci ry = 0; 211141cc406Sopenharmony_ci DBG(10, "1-JPEF Geometry [%dx%d|%dx%d]\n", 212141cc406Sopenharmony_ci rx, 213141cc406Sopenharmony_ci ry, 214141cc406Sopenharmony_ci rw, 215141cc406Sopenharmony_ci rh); 216141cc406Sopenharmony_ci x_off = rx; 217141cc406Sopenharmony_ci if (x_off > (unsigned int)rw) { 218141cc406Sopenharmony_ci w = rw; 219141cc406Sopenharmony_ci x_off = 0; 220141cc406Sopenharmony_ci } 221141cc406Sopenharmony_ci else 222141cc406Sopenharmony_ci w = rw - x_off; 223141cc406Sopenharmony_ci y_off = ry; 224141cc406Sopenharmony_ci if(y_off > (unsigned int)rh) { 225141cc406Sopenharmony_ci h = rh; 226141cc406Sopenharmony_ci y_off = 0; 227141cc406Sopenharmony_ci } 228141cc406Sopenharmony_ci else 229141cc406Sopenharmony_ci h = rh - y_off; 230141cc406Sopenharmony_ci DBG(10, "2-JPEF Geometry [%dx%d|%dx%d]\n", 231141cc406Sopenharmony_ci x_off, 232141cc406Sopenharmony_ci y_off, 233141cc406Sopenharmony_ci w, 234141cc406Sopenharmony_ci h); 235141cc406Sopenharmony_ci surface = malloc(w * h * cinfo.output_components); 236141cc406Sopenharmony_ci if (surface == NULL) { 237141cc406Sopenharmony_ci jpeg_destroy_decompress(&cinfo); 238141cc406Sopenharmony_ci DBG( 1, "Escl Jpeg : Memory allocation problem\n"); 239141cc406Sopenharmony_ci if (scanner->tmp) { 240141cc406Sopenharmony_ci fclose(scanner->tmp); 241141cc406Sopenharmony_ci scanner->tmp = NULL; 242141cc406Sopenharmony_ci } 243141cc406Sopenharmony_ci return (SANE_STATUS_NO_MEM); 244141cc406Sopenharmony_ci } 245141cc406Sopenharmony_ci jpeg_start_decompress(&cinfo); 246141cc406Sopenharmony_ci if (x_off > 0 || w < cinfo.output_width) 247141cc406Sopenharmony_ci jpeg_crop_scanline(&cinfo, &x_off, &w); 248141cc406Sopenharmony_ci lineSize = w * cinfo.output_components; 249141cc406Sopenharmony_ci if (y_off > 0) 250141cc406Sopenharmony_ci jpeg_skip_scanlines(&cinfo, y_off); 251141cc406Sopenharmony_ci pos = 0; 252141cc406Sopenharmony_ci while (cinfo.output_scanline < (unsigned int)rh) { 253141cc406Sopenharmony_ci rowptr[0] = (JSAMPROW)surface + (lineSize * pos); // ..cinfo.output_scanline); 254141cc406Sopenharmony_ci jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); 255141cc406Sopenharmony_ci pos++; 256141cc406Sopenharmony_ci } 257141cc406Sopenharmony_ci scanner->img_data = surface; 258141cc406Sopenharmony_ci scanner->img_size = lineSize * h; 259141cc406Sopenharmony_ci scanner->img_read = 0; 260141cc406Sopenharmony_ci *width = w; 261141cc406Sopenharmony_ci *height = h; 262141cc406Sopenharmony_ci *bps = cinfo.output_components; 263141cc406Sopenharmony_ci // jpeg_finish_decompress(&cinfo); 264141cc406Sopenharmony_ci jpeg_destroy_decompress(&cinfo); 265141cc406Sopenharmony_ci fclose(scanner->tmp); 266141cc406Sopenharmony_ci scanner->tmp = NULL; 267141cc406Sopenharmony_ci return (SANE_STATUS_GOOD); 268141cc406Sopenharmony_ci} 269141cc406Sopenharmony_ci#else 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ciSANE_Status 272141cc406Sopenharmony_ciget_JPEG_data(capabilities_t __sane_unused__ *scanner, 273141cc406Sopenharmony_ci int __sane_unused__ *width, 274141cc406Sopenharmony_ci int __sane_unused__ *height, 275141cc406Sopenharmony_ci int __sane_unused__ *bps) 276141cc406Sopenharmony_ci{ 277141cc406Sopenharmony_ci return (SANE_STATUS_INVAL); 278141cc406Sopenharmony_ci} 279141cc406Sopenharmony_ci 280141cc406Sopenharmony_ci#endif 281