1 /*
2 * epsonds-jpeg.c - Epson ESC/I-2 driver, JPEG support.
3 *
4 * Copyright (C) 2015 Tower Technologies
5 * Author: Alessandro Zummo <a.zummo@towertech.it>
6 *
7 * This file is part of the SANE package.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2.
12 */
13
14 #define DEBUG_DECLARE_ONLY
15
16 #include "sane/config.h"
17
18 #include <math.h>
19
20 #include "epsonds.h"
21 #include "epsonds-jpeg.h"
22 #include "epsonds-ops.h"
23 #include <setjmp.h>
24
25 struct my_error_mgr {
26 struct jpeg_error_mgr pub;
27 jmp_buf setjmp_buffer;
28 };
29
30 typedef struct my_error_mgr * my_error_ptr;
31
32
my_error_exit(j_common_ptr cinfo)33 METHODDEF(void) my_error_exit (j_common_ptr cinfo)
34 {
35
36 char buffer[JMSG_LENGTH_MAX];
37 (*cinfo->err->format_message) (cinfo, buffer);
38
39 DBG(10,"Jpeg decode error [%s]", buffer);
40 }
41
jpeg_custom_error(struct my_error_mgr * err)42 LOCAL(struct jpeg_error_mgr *) jpeg_custom_error (struct my_error_mgr * err)
43 {
44
45 struct jpeg_error_mgr* pRet = jpeg_std_error(&(err->pub));
46 err->pub.error_exit = my_error_exit;
47
48 return pRet;
49 }
50
51 typedef struct
52 {
53 struct jpeg_source_mgr pub;
54 JOCTET *buffer;
55 int length;
56 }
57 epsonds_src_mgr;
58
59 METHODDEF(void)
jpeg_init_source(j_decompress_ptr __sane_unused__ cinfo)60 jpeg_init_source(j_decompress_ptr __sane_unused__ cinfo)
61 {
62 }
63
64 METHODDEF(void)
jpeg_term_source(j_decompress_ptr __sane_unused__ cinfo)65 jpeg_term_source(j_decompress_ptr __sane_unused__ cinfo)
66 {
67 }
68
69 METHODDEF(boolean)
jpeg_fill_input_buffer(j_decompress_ptr cinfo)70 jpeg_fill_input_buffer(j_decompress_ptr cinfo)
71 {
72 epsonds_src_mgr *src = (epsonds_src_mgr *)cinfo->src;
73 /* read from scanner if no data? */
74
75 src->pub.next_input_byte = src->buffer;
76 src->pub.bytes_in_buffer = src->length;
77 DBG(18, "reading from ring buffer, %d left\n", src->length);
78
79 return TRUE;
80 }
81
82 METHODDEF (void)
jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes)83 jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
84 {
85 epsonds_src_mgr *src = (epsonds_src_mgr *)cinfo->src;
86
87 if (num_bytes > 0) {
88
89 while (num_bytes > (long)src->pub.bytes_in_buffer) {
90 num_bytes -= (long)src->pub.bytes_in_buffer;
91 jpeg_fill_input_buffer(cinfo);
92 }
93
94 src->pub.next_input_byte += (size_t) num_bytes;
95 src->pub.bytes_in_buffer -= (size_t) num_bytes;
96 }
97 }
98
99
eds_decode_jpeg(epsonds_scanner * s,SANE_Byte * data,SANE_Int size,ring_buffer * ringBuffer,SANE_Int isBackSide,SANE_Int needToConvertBW)100 void eds_decode_jpeg(epsonds_scanner*s, SANE_Byte *data, SANE_Int size, ring_buffer* ringBuffer, SANE_Int isBackSide, SANE_Int needToConvertBW)
101 {
102 struct jpeg_decompress_struct jpeg_cinfo;
103 struct my_error_mgr jpeg_err;
104
105 {
106 epsonds_src_mgr *src;
107
108 jpeg_cinfo.err = jpeg_custom_error(&jpeg_err);
109
110 jpeg_create_decompress(&jpeg_cinfo);
111
112 jpeg_cinfo.src = (struct jpeg_source_mgr *)(*jpeg_cinfo.mem->alloc_small)((j_common_ptr)&jpeg_cinfo,
113 JPOOL_PERMANENT, sizeof(epsonds_src_mgr));
114
115 memset(jpeg_cinfo.src, 0x00, sizeof(epsonds_src_mgr));
116 ;
117 src = (epsonds_src_mgr *)jpeg_cinfo.src;
118 src->pub.init_source = jpeg_init_source;
119 src->pub.fill_input_buffer = jpeg_fill_input_buffer;
120 src->pub.skip_input_data = jpeg_skip_input_data;
121 src->pub.resync_to_restart = jpeg_resync_to_restart;
122 src->pub.term_source = jpeg_term_source;
123 src->pub.bytes_in_buffer = 0;
124 src->pub.next_input_byte = NULL;
125 src->buffer = (JOCTET*)data;
126 src->length = size;
127 }
128 {
129 if (jpeg_read_header(&jpeg_cinfo, TRUE)) {
130
131 if (jpeg_start_decompress(&jpeg_cinfo)) {
132
133 DBG(10,"%s: w: %d, h: %d, components: %d\n",
134 __func__,
135 jpeg_cinfo.output_width, jpeg_cinfo.output_height,
136 jpeg_cinfo.output_components);
137 }
138 }
139 }
140 {
141 int sum = 0;
142 int bufSize = jpeg_cinfo.output_width * jpeg_cinfo.output_components;
143
144 int monoBufSize = (jpeg_cinfo.output_width + 7)/8;
145
146 JSAMPARRAY scanlines = (jpeg_cinfo.mem->alloc_sarray)((j_common_ptr)&jpeg_cinfo, JPOOL_IMAGE, bufSize, 1);
147 while (jpeg_cinfo.output_scanline < jpeg_cinfo.output_height) {
148 int l = jpeg_read_scanlines(&jpeg_cinfo, scanlines, 1);
149 if (l == 0) {
150 break;
151 }
152 sum += l;
153
154 if (needToConvertBW)
155 {
156 SANE_Byte* bytes = scanlines[0];
157
158 SANE_Int imgPos = 0;
159
160 for (int i = 0; i < monoBufSize; i++)
161 {
162 SANE_Byte outByte = 0;
163
164 for(SANE_Int bitIndex = 0; bitIndex < 8 && imgPos < bufSize; bitIndex++) {
165 //DBG(10,"bytes[imgPos] = %d\n", bytes[imgPos]);
166
167 if(bytes[imgPos] >= 110) {
168 SANE_Byte bit = 7 - (bitIndex % 8);
169 outByte |= (1<< bit);
170 }
171 imgPos += 1;
172 }
173 //DBG(10,"outByte = %d\n", outByte);
174 eds_ring_write(ringBuffer, &outByte, 1);
175 }
176 }
177 else
178 {
179 eds_ring_write(ringBuffer, scanlines[0], bufSize);
180 }
181
182 // decode until valida data
183 if (isBackSide)
184 {
185 if (sum >= s->height_back)
186 {
187 break;
188 }
189 }else
190 {
191 if (sum >= s->height_front)
192 {
193 break;
194 }
195 }
196 }
197 DBG(10,"decodded lines = %d\n", sum);
198
199 // abandon unncessary data
200 if ((JDIMENSION)sum < jpeg_cinfo.output_height)
201 {
202 // unncessary data
203 while(1)
204 {
205 int l = jpeg_read_scanlines(&jpeg_cinfo, scanlines, 1);
206 if (l == 0)
207 {
208 break;
209 }
210 }
211 }
212
213 // if not auto crop mode padding to lines
214 if (s->val[OPT_ADF_CRP].w == 0)
215 {
216 unsigned char* padding = malloc(s->params.bytes_per_line);
217 memset(padding, 255, s->params.bytes_per_line);
218 DBG(10,"padding data lines = %d to %d pa \n", sum, s->params.lines);
219
220 while(sum < s->params.lines)
221 {
222 eds_ring_write(ringBuffer, padding, bufSize);
223 sum++;
224 }
225
226 free(padding);
227 padding = NULL;
228 }
229 }
230 {
231 jpeg_finish_decompress(&jpeg_cinfo);
232 jpeg_destroy_decompress(&jpeg_cinfo);
233 }
234 return;
235 }
236