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