5
|
1 /*
|
|
2 * SpanDSP - a series of DSP components for telephony
|
|
3 *
|
|
4 * t4.c - ITU T.4 FAX image processing
|
|
5 * This depends on libtiff (see <http://www.libtiff.org>)
|
|
6 *
|
|
7 * Written by Steve Underwood <steveu@coppice.org>
|
|
8 *
|
|
9 * Copyright (C) 2003 Steve Underwood
|
|
10 *
|
|
11 * All rights reserved.
|
|
12 *
|
|
13 * This program is free software; you can redistribute it and/or modify
|
|
14 * it under the terms of the GNU General Public License version 2, as
|
|
15 * published by the Free Software Foundation.
|
|
16 *
|
|
17 * This program is distributed in the hope that it will be useful,
|
|
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20 * GNU General Public License for more details.
|
|
21 *
|
|
22 * You should have received a copy of the GNU General Public License
|
|
23 * along with this program; if not, write to the Free Software
|
|
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
25 *
|
|
26 * $Id: t4.c,v 1.67 2006/12/01 18:00:48 steveu Exp $
|
|
27 */
|
|
28
|
|
29 /*
|
|
30 * Much of this file is based on the T.4 and T.6 support in libtiff, which requires
|
|
31 * the following notice in any derived source code:
|
|
32 *
|
|
33 * Copyright (c) 1990-1997 Sam Leffler
|
|
34 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
|
35 *
|
|
36 * Permission to use, copy, modify, distribute, and sell this software and
|
|
37 * its documentation for any purpose is hereby granted without fee, provided
|
|
38 * that (i) the above copyright notices and this permission notice appear in
|
|
39 * all copies of the software and related documentation, and (ii) the names of
|
|
40 * Sam Leffler and Silicon Graphics may not be used in any advertising or
|
|
41 * publicity relating to the software without the specific, prior written
|
|
42 * permission of Sam Leffler and Silicon Graphics.
|
|
43 *
|
|
44 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
45 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
46 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
47 *
|
|
48 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
|
|
49 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
|
|
50 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
51 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
|
|
52 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
53 * OF THIS SOFTWARE.
|
|
54 *
|
|
55 * Decoder support is derived from code in Frank Cringle's viewfax program;
|
|
56 * Copyright (C) 1990, 1995 Frank D. Cringle.
|
|
57 */
|
|
58
|
|
59 /*! \file */
|
|
60
|
|
61 #ifdef HAVE_CONFIG_H
|
|
62 #include <config.h>
|
|
63 #endif
|
|
64
|
|
65 #define _GNU_SOURCE
|
|
66
|
|
67 #include <stdio.h>
|
|
68 #include <inttypes.h>
|
|
69 #include <limits.h>
|
|
70 #include <unistd.h>
|
|
71 #include <fcntl.h>
|
|
72 #include <stdlib.h>
|
|
73 #include <time.h>
|
|
74 #include <memory.h>
|
|
75 #include <string.h>
|
|
76 #if defined(HAVE_TGMATH_H)
|
|
77 #include <tgmath.h>
|
|
78 #endif
|
|
79 #if defined(HAVE_MATH_H)
|
|
80 #include <math.h>
|
|
81 #endif
|
|
82 #include <tiffio.h>
|
|
83
|
|
84 #include "spandsp/telephony.h"
|
|
85 #include "spandsp/logging.h"
|
|
86 #include "spandsp/bit_operations.h"
|
|
87 #include "spandsp/async.h"
|
|
88 #include "spandsp/t4.h"
|
|
89
|
|
90 /* Finite state machine state codes */
|
|
91 #define S_Null 0
|
|
92 #define S_Pass 1
|
|
93 #define S_Horiz 2
|
|
94 #define S_V0 3
|
|
95 #define S_VR 4
|
|
96 #define S_VL 5
|
|
97 #define S_Ext 6
|
|
98 #define S_TermW 7
|
|
99 #define S_TermB 8
|
|
100 #define S_MakeUpW 9
|
|
101 #define S_MakeUpB 10
|
|
102 #define S_MakeUp 11
|
|
103 #define S_EOL 12
|
|
104
|
|
105 #include "faxfont.h"
|
|
106
|
|
107 #if 1
|
|
108 #define STATE_TRACE(...) /**/
|
|
109 #else
|
|
110 void STATE_TRACE(char *format, ...)
|
|
111 {
|
|
112 va_list arg_ptr;
|
|
113
|
|
114 va_start(arg_ptr, format);
|
|
115 vprintf(format, arg_ptr);
|
|
116 va_end(arg_ptr);
|
|
117 }
|
|
118 /*- End of function --------------------------------------------------------*/
|
|
119 #endif
|
|
120
|
|
121 /* Finite state machine state table entry */
|
|
122 typedef struct
|
|
123 {
|
|
124 uint8_t state; /* see above */
|
|
125 uint8_t width; /* width of code in bits */
|
|
126 uint32_t param; /* run length in bits */
|
|
127 } T4_tab_entry;
|
|
128
|
|
129 #include "t4states.h"
|
|
130
|
|
131 /* From the T.4 spec:
|
|
132
|
|
133 a0 The reference or starting changing element on the coding line. At
|
|
134 the start of the coding line, a0 is set on an imaginary white
|
|
135 changing element situated just before the first element on the
|
|
136 line. During the coding of the coding line, the position of a0
|
|
137 is defined by the previous coding mode. (See 4.2.1.3.2.)
|
|
138 a1 The next changing element to the right of a0 on the coding line.
|
|
139 a2 The next changing element to the right of a1 on the coding line.
|
|
140 b1 The first changing element on the reference line to the right of
|
|
141 a0 and of opposite colour to a0.
|
|
142 b2 The next changing element to the right of b1 on the reference line.
|
|
143 */
|
|
144
|
|
145 /*
|
|
146 * ITU T.4 1D Huffman run length codes and
|
|
147 * related definitions. Given the small sizes
|
|
148 * of these tables it does not seem
|
|
149 * worthwhile to make code & length 8 bits.
|
|
150 */
|
|
151 typedef struct
|
|
152 {
|
|
153 uint16_t length; /* length of T.4 code, in bits */
|
|
154 uint16_t code; /* T.4 code */
|
|
155 int16_t runlen; /* run length, in bits */
|
|
156 } T4_table_entry;
|
|
157
|
|
158 #define is_aligned(p,t) ((((intptr_t)(p)) & (sizeof(t) - 1)) == 0)
|
|
159
|
|
160 /* Status values returned instead of a run length */
|
|
161 #define T4CODE_EOL -1 /* NB: ACT_EOL - ACT_WRUNT */
|
|
162 #define T4CODE_INVALID -2 /* NB: ACT_INVALID - ACT_WRUNT */
|
|
163 #define T4CODE_EOF -3 /* end of input data */
|
|
164 #define T4CODE_INCOMP -4 /* incomplete run code */
|
|
165
|
|
166 /*
|
|
167 * Note that these tables are ordered such that the
|
|
168 * index into the table is known to be either the
|
|
169 * run length, or (run length / 64) + a fixed offset.
|
|
170 *
|
|
171 * NB: The T4CODE_INVALID entries are only used
|
|
172 * during state generation (see mkg3states.c).
|
|
173 */
|
|
174 const T4_table_entry t4_white_codes[] =
|
|
175 {
|
|
176 { 8, 0x35, 0 }, /* 0011 0101 */
|
|
177 { 6, 0x07, 1 }, /* 0001 11 */
|
|
178 { 4, 0x07, 2 }, /* 0111 */
|
|
179 { 4, 0x08, 3 }, /* 1000 */
|
|
180 { 4, 0x0B, 4 }, /* 1011 */
|
|
181 { 4, 0x0C, 5 }, /* 1100 */
|
|
182 { 4, 0x0E, 6 }, /* 1110 */
|
|
183 { 4, 0x0F, 7 }, /* 1111 */
|
|
184 { 5, 0x13, 8 }, /* 1001 1 */
|
|
185 { 5, 0x14, 9 }, /* 1010 0 */
|
|
186 { 5, 0x07, 10 }, /* 0011 1 */
|
|
187 { 5, 0x08, 11 }, /* 0100 0 */
|
|
188 { 6, 0x08, 12 }, /* 0010 00 */
|
|
189 { 6, 0x03, 13 }, /* 0000 11 */
|
|
190 { 6, 0x34, 14 }, /* 1101 00 */
|
|
191 { 6, 0x35, 15 }, /* 1101 01 */
|
|
192 { 6, 0x2A, 16 }, /* 1010 10 */
|
|
193 { 6, 0x2B, 17 }, /* 1010 11 */
|
|
194 { 7, 0x27, 18 }, /* 0100 111 */
|
|
195 { 7, 0x0C, 19 }, /* 0001 100 */
|
|
196 { 7, 0x08, 20 }, /* 0001 000 */
|
|
197 { 7, 0x17, 21 }, /* 0010 111 */
|
|
198 { 7, 0x03, 22 }, /* 0000 011 */
|
|
199 { 7, 0x04, 23 }, /* 0000 100 */
|
|
200 { 7, 0x28, 24 }, /* 0101 000 */
|
|
201 { 7, 0x2B, 25 }, /* 0101 011 */
|
|
202 { 7, 0x13, 26 }, /* 0010 011 */
|
|
203 { 7, 0x24, 27 }, /* 0100 100 */
|
|
204 { 7, 0x18, 28 }, /* 0011 000 */
|
|
205 { 8, 0x02, 29 }, /* 0000 0010 */
|
|
206 { 8, 0x03, 30 }, /* 0000 0011 */
|
|
207 { 8, 0x1A, 31 }, /* 0001 1010 */
|
|
208 { 8, 0x1B, 32 }, /* 0001 1011 */
|
|
209 { 8, 0x12, 33 }, /* 0001 0010 */
|
|
210 { 8, 0x13, 34 }, /* 0001 0011 */
|
|
211 { 8, 0x14, 35 }, /* 0001 0100 */
|
|
212 { 8, 0x15, 36 }, /* 0001 0101 */
|
|
213 { 8, 0x16, 37 }, /* 0001 0110 */
|
|
214 { 8, 0x17, 38 }, /* 0001 0111 */
|
|
215 { 8, 0x28, 39 }, /* 0010 1000 */
|
|
216 { 8, 0x29, 40 }, /* 0010 1001 */
|
|
217 { 8, 0x2A, 41 }, /* 0010 1010 */
|
|
218 { 8, 0x2B, 42 }, /* 0010 1011 */
|
|
219 { 8, 0x2C, 43 }, /* 0010 1100 */
|
|
220 { 8, 0x2D, 44 }, /* 0010 1101 */
|
|
221 { 8, 0x04, 45 }, /* 0000 0100 */
|
|
222 { 8, 0x05, 46 }, /* 0000 0101 */
|
|
223 { 8, 0x0A, 47 }, /* 0000 1010 */
|
|
224 { 8, 0x0B, 48 }, /* 0000 1011 */
|
|
225 { 8, 0x52, 49 }, /* 0101 0010 */
|
|
226 { 8, 0x53, 50 }, /* 0101 0011 */
|
|
227 { 8, 0x54, 51 }, /* 0101 0100 */
|
|
228 { 8, 0x55, 52 }, /* 0101 0101 */
|
|
229 { 8, 0x24, 53 }, /* 0010 0100 */
|
|
230 { 8, 0x25, 54 }, /* 0010 0101 */
|
|
231 { 8, 0x58, 55 }, /* 0101 1000 */
|
|
232 { 8, 0x59, 56 }, /* 0101 1001 */
|
|
233 { 8, 0x5A, 57 }, /* 0101 1010 */
|
|
234 { 8, 0x5B, 58 }, /* 0101 1011 */
|
|
235 { 8, 0x4A, 59 }, /* 0100 1010 */
|
|
236 { 8, 0x4B, 60 }, /* 0100 1011 */
|
|
237 { 8, 0x32, 61 }, /* 0011 0010 */
|
|
238 { 8, 0x33, 62 }, /* 0011 0011 */
|
|
239 { 8, 0x34, 63 }, /* 0011 0100 */
|
|
240 { 5, 0x1B, 64 }, /* 1101 1 */
|
|
241 { 5, 0x12, 128 }, /* 1001 0 */
|
|
242 { 6, 0x17, 192 }, /* 0101 11 */
|
|
243 { 7, 0x37, 256 }, /* 0110 111 */
|
|
244 { 8, 0x36, 320 }, /* 0011 0110 */
|
|
245 { 8, 0x37, 384 }, /* 0011 0111 */
|
|
246 { 8, 0x64, 448 }, /* 0110 0100 */
|
|
247 { 8, 0x65, 512 }, /* 0110 0101 */
|
|
248 { 8, 0x68, 576 }, /* 0110 1000 */
|
|
249 { 8, 0x67, 640 }, /* 0110 0111 */
|
|
250 { 9, 0xCC, 704 }, /* 0110 0110 0 */
|
|
251 { 9, 0xCD, 768 }, /* 0110 0110 1 */
|
|
252 { 9, 0xD2, 832 }, /* 0110 1001 0 */
|
|
253 { 9, 0xD3, 896 }, /* 0110 1001 1 */
|
|
254 { 9, 0xD4, 960 }, /* 0110 1010 0 */
|
|
255 { 9, 0xD5, 1024 }, /* 0110 1010 1 */
|
|
256 { 9, 0xD6, 1088 }, /* 0110 1011 0 */
|
|
257 { 9, 0xD7, 1152 }, /* 0110 1011 1 */
|
|
258 { 9, 0xD8, 1216 }, /* 0110 1100 0 */
|
|
259 { 9, 0xD9, 1280 }, /* 0110 1100 1 */
|
|
260 { 9, 0xDA, 1344 }, /* 0110 1101 0 */
|
|
261 { 9, 0xDB, 1408 }, /* 0110 1101 1 */
|
|
262 { 9, 0x98, 1472 }, /* 0100 1100 0 */
|
|
263 { 9, 0x99, 1536 }, /* 0100 1100 1 */
|
|
264 { 9, 0x9A, 1600 }, /* 0100 1101 0 */
|
|
265 { 6, 0x18, 1664 }, /* 0110 00 */
|
|
266 { 9, 0x9B, 1728 }, /* 0100 1101 1 */
|
|
267 { 11, 0x08, 1792 }, /* 0000 0001 000 */
|
|
268 { 11, 0x0C, 1856 }, /* 0000 0001 100 */
|
|
269 { 11, 0x0D, 1920 }, /* 0000 0001 101 */
|
|
270 { 12, 0x12, 1984 }, /* 0000 0001 0010 */
|
|
271 { 12, 0x13, 2048 }, /* 0000 0001 0011 */
|
|
272 { 12, 0x14, 2112 }, /* 0000 0001 0100 */
|
|
273 { 12, 0x15, 2176 }, /* 0000 0001 0101 */
|
|
274 { 12, 0x16, 2240 }, /* 0000 0001 0110 */
|
|
275 { 12, 0x17, 2304 }, /* 0000 0001 0111 */
|
|
276 { 12, 0x1C, 2368 }, /* 0000 0001 1100 */
|
|
277 { 12, 0x1D, 2432 }, /* 0000 0001 1101 */
|
|
278 { 12, 0x1E, 2496 }, /* 0000 0001 1110 */
|
|
279 { 12, 0x1F, 2560 }, /* 0000 0001 1111 */
|
|
280 { 12, 0x01, T4CODE_EOL }, /* 0000 0000 0001 */
|
|
281 { 9, 0x01, T4CODE_INVALID }, /* 0000 0000 1 */
|
|
282 { 10, 0x01, T4CODE_INVALID }, /* 0000 0000 01 */
|
|
283 { 11, 0x01, T4CODE_INVALID }, /* 0000 0000 001 */
|
|
284 { 12, 0x00, T4CODE_INVALID }, /* 0000 0000 0000 */
|
|
285 };
|
|
286
|
|
287 const T4_table_entry t4_black_codes[] =
|
|
288 {
|
|
289 { 10, 0x37, 0 }, /* 0000 1101 11 */
|
|
290 { 3, 0x02, 1 }, /* 010 */
|
|
291 { 2, 0x03, 2 }, /* 11 */
|
|
292 { 2, 0x02, 3 }, /* 10 */
|
|
293 { 3, 0x03, 4 }, /* 011 */
|
|
294 { 4, 0x03, 5 }, /* 0011 */
|
|
295 { 4, 0x02, 6 }, /* 0010 */
|
|
296 { 5, 0x03, 7 }, /* 0001 1 */
|
|
297 { 6, 0x05, 8 }, /* 0001 01 */
|
|
298 { 6, 0x04, 9 }, /* 0001 00 */
|
|
299 { 7, 0x04, 10 }, /* 0000 100 */
|
|
300 { 7, 0x05, 11 }, /* 0000 101 */
|
|
301 { 7, 0x07, 12 }, /* 0000 111 */
|
|
302 { 8, 0x04, 13 }, /* 0000 0100 */
|
|
303 { 8, 0x07, 14 }, /* 0000 0111 */
|
|
304 { 9, 0x18, 15 }, /* 0000 1100 0 */
|
|
305 { 10, 0x17, 16 }, /* 0000 0101 11 */
|
|
306 { 10, 0x18, 17 }, /* 0000 0110 00 */
|
|
307 { 10, 0x08, 18 }, /* 0000 0010 00 */
|
|
308 { 11, 0x67, 19 }, /* 0000 1100 111 */
|
|
309 { 11, 0x68, 20 }, /* 0000 1101 000 */
|
|
310 { 11, 0x6C, 21 }, /* 0000 1101 100 */
|
|
311 { 11, 0x37, 22 }, /* 0000 0110 111 */
|
|
312 { 11, 0x28, 23 }, /* 0000 0101 000 */
|
|
313 { 11, 0x17, 24 }, /* 0000 0010 111 */
|
|
314 { 11, 0x18, 25 }, /* 0000 0011 000 */
|
|
315 { 12, 0xCA, 26 }, /* 0000 1100 1010 */
|
|
316 { 12, 0xCB, 27 }, /* 0000 1100 1011 */
|
|
317 { 12, 0xCC, 28 }, /* 0000 1100 1100 */
|
|
318 { 12, 0xCD, 29 }, /* 0000 1100 1101 */
|
|
319 { 12, 0x68, 30 }, /* 0000 0110 1000 */
|
|
320 { 12, 0x69, 31 }, /* 0000 0110 1001 */
|
|
321 { 12, 0x6A, 32 }, /* 0000 0110 1010 */
|
|
322 { 12, 0x6B, 33 }, /* 0000 0110 1011 */
|
|
323 { 12, 0xD2, 34 }, /* 0000 1101 0010 */
|
|
324 { 12, 0xD3, 35 }, /* 0000 1101 0011 */
|
|
325 { 12, 0xD4, 36 }, /* 0000 1101 0100 */
|
|
326 { 12, 0xD5, 37 }, /* 0000 1101 0101 */
|
|
327 { 12, 0xD6, 38 }, /* 0000 1101 0110 */
|
|
328 { 12, 0xD7, 39 }, /* 0000 1101 0111 */
|
|
329 { 12, 0x6C, 40 }, /* 0000 0110 1100 */
|
|
330 { 12, 0x6D, 41 }, /* 0000 0110 1101 */
|
|
331 { 12, 0xDA, 42 }, /* 0000 1101 1010 */
|
|
332 { 12, 0xDB, 43 }, /* 0000 1101 1011 */
|
|
333 { 12, 0x54, 44 }, /* 0000 0101 0100 */
|
|
334 { 12, 0x55, 45 }, /* 0000 0101 0101 */
|
|
335 { 12, 0x56, 46 }, /* 0000 0101 0110 */
|
|
336 { 12, 0x57, 47 }, /* 0000 0101 0111 */
|
|
337 { 12, 0x64, 48 }, /* 0000 0110 0100 */
|
|
338 { 12, 0x65, 49 }, /* 0000 0110 0101 */
|
|
339 { 12, 0x52, 50 }, /* 0000 0101 0010 */
|
|
340 { 12, 0x53, 51 }, /* 0000 0101 0011 */
|
|
341 { 12, 0x24, 52 }, /* 0000 0010 0100 */
|
|
342 { 12, 0x37, 53 }, /* 0000 0011 0111 */
|
|
343 { 12, 0x38, 54 }, /* 0000 0011 1000 */
|
|
344 { 12, 0x27, 55 }, /* 0000 0010 0111 */
|
|
345 { 12, 0x28, 56 }, /* 0000 0010 1000 */
|
|
346 { 12, 0x58, 57 }, /* 0000 0101 1000 */
|
|
347 { 12, 0x59, 58 }, /* 0000 0101 1001 */
|
|
348 { 12, 0x2B, 59 }, /* 0000 0010 1011 */
|
|
349 { 12, 0x2C, 60 }, /* 0000 0010 1100 */
|
|
350 { 12, 0x5A, 61 }, /* 0000 0101 1010 */
|
|
351 { 12, 0x66, 62 }, /* 0000 0110 0110 */
|
|
352 { 12, 0x67, 63 }, /* 0000 0110 0111 */
|
|
353 { 10, 0x0F, 64 }, /* 0000 0011 11 */
|
|
354 { 12, 0xC8, 128 }, /* 0000 1100 1000 */
|
|
355 { 12, 0xC9, 192 }, /* 0000 1100 1001 */
|
|
356 { 12, 0x5B, 256 }, /* 0000 0101 1011 */
|
|
357 { 12, 0x33, 320 }, /* 0000 0011 0011 */
|
|
358 { 12, 0x34, 384 }, /* 0000 0011 0100 */
|
|
359 { 12, 0x35, 448 }, /* 0000 0011 0101 */
|
|
360 { 13, 0x6C, 512 }, /* 0000 0011 0110 0 */
|
|
361 { 13, 0x6D, 576 }, /* 0000 0011 0110 1 */
|
|
362 { 13, 0x4A, 640 }, /* 0000 0010 0101 0 */
|
|
363 { 13, 0x4B, 704 }, /* 0000 0010 0101 1 */
|
|
364 { 13, 0x4C, 768 }, /* 0000 0010 0110 0 */
|
|
365 { 13, 0x4D, 832 }, /* 0000 0010 0110 1 */
|
|
366 { 13, 0x72, 896 }, /* 0000 0011 1001 0 */
|
|
367 { 13, 0x73, 960 }, /* 0000 0011 1001 1 */
|
|
368 { 13, 0x74, 1024 }, /* 0000 0011 1010 0 */
|
|
369 { 13, 0x75, 1088 }, /* 0000 0011 1010 1 */
|
|
370 { 13, 0x76, 1152 }, /* 0000 0011 1011 0 */
|
|
371 { 13, 0x77, 1216 }, /* 0000 0011 1011 1 */
|
|
372 { 13, 0x52, 1280 }, /* 0000 0010 1001 0 */
|
|
373 { 13, 0x53, 1344 }, /* 0000 0010 1001 1 */
|
|
374 { 13, 0x54, 1408 }, /* 0000 0010 1010 0 */
|
|
375 { 13, 0x55, 1472 }, /* 0000 0010 1010 1 */
|
|
376 { 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */
|
|
377 { 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */
|
|
378 { 13, 0x64, 1664 }, /* 0000 0011 0010 0 */
|
|
379 { 13, 0x65, 1728 }, /* 0000 0011 0010 1 */
|
|
380 { 11, 0x08, 1792 }, /* 0000 0001 000 */
|
|
381 { 11, 0x0C, 1856 }, /* 0000 0001 100 */
|
|
382 { 11, 0x0D, 1920 }, /* 0000 0001 101 */
|
|
383 { 12, 0x12, 1984 }, /* 0000 0001 0010 */
|
|
384 { 12, 0x13, 2048 }, /* 0000 0001 0011 */
|
|
385 { 12, 0x14, 2112 }, /* 0000 0001 0100 */
|
|
386 { 12, 0x15, 2176 }, /* 0000 0001 0101 */
|
|
387 { 12, 0x16, 2240 }, /* 0000 0001 0110 */
|
|
388 { 12, 0x17, 2304 }, /* 0000 0001 0111 */
|
|
389 { 12, 0x1C, 2368 }, /* 0000 0001 1100 */
|
|
390 { 12, 0x1D, 2432 }, /* 0000 0001 1101 */
|
|
391 { 12, 0x1E, 2496 }, /* 0000 0001 1110 */
|
|
392 { 12, 0x1F, 2560 }, /* 0000 0001 1111 */
|
|
393 { 12, 0x01, T4CODE_EOL }, /* 0000 0000 0001 */
|
|
394 { 9, 0x01, T4CODE_INVALID }, /* 0000 0000 1 */
|
|
395 { 10, 0x01, T4CODE_INVALID }, /* 0000 0000 01 */
|
|
396 { 11, 0x01, T4CODE_INVALID }, /* 0000 0000 001 */
|
|
397 { 12, 0x00, T4CODE_INVALID }, /* 0000 0000 0000 */
|
|
398 };
|
|
399
|
|
400 #if defined(__i386__) || defined(__x86_64__)
|
|
401 static __inline__ int run_length(unsigned int bits)
|
|
402 {
|
|
403 return 7 - top_bit(bits);
|
|
404 }
|
|
405 /*- End of function --------------------------------------------------------*/
|
|
406 #else
|
|
407 static __inline__ int run_length(unsigned int bits)
|
|
408 {
|
|
409 static const uint8_t run_len[256] =
|
|
410 {
|
|
411 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */
|
|
412 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */
|
|
413 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */
|
|
414 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */
|
|
415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */
|
|
416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */
|
|
417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */
|
|
418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */
|
|
419 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
|
|
420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
|
|
421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
|
|
422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
|
|
423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
|
|
424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
|
|
425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
|
|
426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */
|
|
427 };
|
|
428
|
|
429 return run_len[bits];
|
|
430 }
|
|
431 /*- End of function --------------------------------------------------------*/
|
|
432 #endif
|
|
433
|
|
434 static __inline__ int flush_bits_to_image_buffer(t4_state_t *s)
|
|
435 {
|
|
436 uint8_t *t;
|
|
437
|
|
438 s->bit = 8;
|
|
439 if (s->image_size >= s->image_buffer_size)
|
|
440 {
|
|
441 if ((t = realloc(s->image_buffer, s->image_buffer_size + 10000)) == NULL)
|
|
442 return -1;
|
|
443 s->image_buffer_size += 10000;
|
|
444 s->image_buffer = t;
|
|
445 }
|
|
446 s->image_buffer[s->image_size++] = (uint8_t) s->data;
|
|
447 s->data = 0;
|
|
448 return 0;
|
|
449 }
|
|
450 /*- End of function --------------------------------------------------------*/
|
|
451
|
|
452 static __inline__ void put_run(t4_state_t *s, int black)
|
|
453 {
|
|
454 int i;
|
|
455
|
|
456 s->row_len += s->run_length;
|
|
457 /* Ignore anything before the first EOL */
|
|
458 /* Don't allow rows to grow too long, and overflow the buffers */
|
|
459 if (s->row_len <= s->image_width)
|
|
460 {
|
|
461 *s->pa++ = s->run_length;
|
|
462 for (i = 0; i < s->run_length; i++)
|
|
463 {
|
|
464 s->data = (s->data << 1) | black;
|
|
465 if (--s->bit == 0)
|
|
466 flush_bits_to_image_buffer(s);
|
|
467 }
|
|
468 }
|
|
469 s->run_length = 0;
|
|
470 }
|
|
471 /*- End of function --------------------------------------------------------*/
|
|
472
|
|
473 static __inline__ void put_eol(t4_state_t *s)
|
|
474 {
|
|
475 uint32_t *x;
|
|
476 uint8_t *t;
|
|
477
|
|
478 if (s->run_length)
|
|
479 put_run(s, 0);
|
|
480 if (s->row_len != s->image_width)
|
|
481 {
|
|
482 STATE_TRACE("%d Bad row - %d %d\n", s->row, s->row_len, s->row_is_2d);
|
|
483 /* Clean up the bad runs */
|
|
484 while (s->a0 > s->image_width && s->pa > s->cur_runs)
|
|
485 s->a0 -= *--s->pa;
|
|
486 if (s->a0 < s->image_width)
|
|
487 {
|
|
488 if (s->a0 < 0)
|
|
489 s->a0 = 0;
|
|
490 if ((s->pa - s->cur_runs) & 1)
|
|
491 put_run(s, 0);
|
|
492 s->run_length = s->image_width - s->a0;
|
|
493 put_run(s, 0);
|
|
494 }
|
|
495 else if (s->a0 > s->image_width)
|
|
496 {
|
|
497 s->run_length = s->image_width;
|
|
498 put_run(s, 0);
|
|
499 s->run_length = 0;
|
|
500 put_run(s, 0);
|
|
501 }
|
|
502 if (s->row_starts_at != s->last_row_starts_at)
|
|
503 {
|
|
504 /* Copy the previous row over this one */
|
|
505 if (s->row_starts_at + s->bytes_per_row >= s->image_buffer_size)
|
|
506 {
|
|
507 if ((t = realloc(s->image_buffer, s->image_buffer_size + 10000)) == NULL)
|
|
508 {
|
|
509 /* TODO: take some action to report the allocation failure */
|
|
510 return;
|
|
511 }
|
|
512 s->image_buffer_size += 10000;
|
|
513 s->image_buffer = t;
|
|
514 }
|
|
515 memcpy(s->image_buffer + s->row_starts_at, s->image_buffer + s->last_row_starts_at, s->bytes_per_row);
|
|
516 s->image_size = s->row_starts_at + s->bytes_per_row;
|
|
517 }
|
|
518 s->bad_rows++;
|
|
519 s->curr_bad_row_run++;
|
|
520 }
|
|
521 else
|
|
522 {
|
|
523 if (s->curr_bad_row_run)
|
|
524 {
|
|
525 if (s->curr_bad_row_run > s->longest_bad_row_run)
|
|
526 s->longest_bad_row_run = s->curr_bad_row_run;
|
|
527 s->curr_bad_row_run = 0;
|
|
528 }
|
|
529 STATE_TRACE("%d Good row - %d %d\n", s->row, s->row_len, s->row_is_2d);
|
|
530 }
|
|
531
|
|
532 #if 0
|
|
533 /* Dump the runs of black and white for analysis */
|
|
534 {
|
|
535 int total;
|
|
536
|
|
537 span_log(&s->logging, SPAN_LOG_DEBUG_2, "Ref ");
|
|
538 total = 0;
|
|
539 for (x = s->ref_runs; x < s->pb; x++)
|
|
540 {
|
|
541 total += *x;
|
|
542 span_log(&s->logging, SPAN_LOG_DEBUG_2, "%d ", *x);
|
|
543 }
|
|
544 span_log(&s->logging, SPAN_LOG_DEBUG_2, " total = %d\n", total);
|
|
545 span_log(&s->logging, SPAN_LOG_DEBUG_2, "Cur ");
|
|
546 total = 0;
|
|
547 for (x = s->cur_runs; x < s->pa; x++)
|
|
548 {
|
|
549 total += *x;
|
|
550 span_log(&s->logging, SPAN_LOG_DEBUG_2, "%d ", *x);
|
|
551 }
|
|
552 span_log(&s->logging, SPAN_LOG_DEBUG_2, "total = %d\n", total);
|
|
553 }
|
|
554 #endif
|
|
555
|
|
556 /* Prepare the buffers for the next row. */
|
|
557 s->image_length++;
|
|
558 s->last_row_starts_at = s->row_starts_at;
|
|
559 s->row_starts_at = s->image_size;
|
|
560 x = s->cur_runs;
|
|
561 s->cur_runs = s->ref_runs;
|
|
562 s->ref_runs = x;
|
|
563
|
|
564 s->pa = s->cur_runs;
|
|
565 s->pb = s->ref_runs;
|
|
566
|
|
567 s->a0 = 0;
|
|
568 s->b1 = *s->pb++;
|
|
569 }
|
|
570 /*- End of function --------------------------------------------------------*/
|
|
571
|
|
572 int t4_rx_end_page(t4_state_t *s)
|
|
573 {
|
|
574 int row;
|
|
575 int i;
|
|
576 time_t now;
|
|
577 struct tm *tm;
|
|
578 char buf[256 + 1];
|
|
579 uint16_t resunit;
|
|
580 float x_resolution;
|
|
581 float y_resolution;
|
|
582
|
|
583 if (s->line_encoding == T4_COMPRESSION_ITU_T6)
|
|
584 {
|
|
585 /* Push enough zeros through the decoder to flush out any remaining codes */
|
|
586 for (i = 0; i < 13; i++)
|
|
587 t4_rx_put_bit(s, 0);
|
|
588 }
|
|
589 if (s->curr_bad_row_run)
|
|
590 {
|
|
591 if (s->curr_bad_row_run > s->longest_bad_row_run)
|
|
592 s->longest_bad_row_run = s->curr_bad_row_run;
|
|
593 s->curr_bad_row_run = 0;
|
|
594 }
|
|
595
|
|
596 if (s->image_size == 0)
|
|
597 return -1;
|
|
598
|
|
599 /* Prepare the directory entry fully before writing the image, or libtiff complains */
|
|
600 TIFFSetField(s->tiff_file, TIFFTAG_COMPRESSION, s->output_compression);
|
|
601 if (s->output_compression == COMPRESSION_CCITT_T4)
|
|
602 {
|
|
603 TIFFSetField(s->tiff_file, TIFFTAG_T4OPTIONS, s->output_t4_options);
|
|
604 TIFFSetField(s->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF);
|
|
605 }
|
|
606 TIFFSetField(s->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width);
|
|
607 TIFFSetField(s->tiff_file, TIFFTAG_BITSPERSAMPLE, 1);
|
|
608 TIFFSetField(s->tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
|
609 TIFFSetField(s->tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1);
|
|
610 if (s->output_compression == COMPRESSION_CCITT_T4
|
|
611 ||
|
|
612 s->output_compression == COMPRESSION_CCITT_T6)
|
|
613 {
|
|
614 TIFFSetField(s->tiff_file, TIFFTAG_ROWSPERSTRIP, -1L);
|
|
615 }
|
|
616 else
|
|
617 {
|
|
618 TIFFSetField(s->tiff_file,
|
|
619 TIFFTAG_ROWSPERSTRIP,
|
|
620 TIFFDefaultStripSize(s->tiff_file, 0));
|
|
621 }
|
|
622 TIFFSetField(s->tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
|
623 TIFFSetField(s->tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
|
|
624 TIFFSetField(s->tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
|
|
625
|
|
626 x_resolution = s->x_resolution/100.0f;
|
|
627 y_resolution = s->y_resolution/100.0f;
|
|
628 /* Metric seems the sane things to use in the 21st century, but a lot of lousy software
|
|
629 gets FAX resolutions wrong, and more get it wrong using metric than using inches. */
|
|
630 #if 0
|
|
631 TIFFSetField(s->tiff_file, TIFFTAG_XRESOLUTION, x_resolution);
|
|
632 TIFFSetField(s->tiff_file, TIFFTAG_YRESOLUTION, y_resolution);
|
|
633 resunit = RESUNIT_CENTIMETER;
|
|
634 TIFFSetField(s->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit);
|
|
635 #else
|
|
636 TIFFSetField(s->tiff_file, TIFFTAG_XRESOLUTION, floorf(x_resolution*2.54f + 0.5f));
|
|
637 TIFFSetField(s->tiff_file, TIFFTAG_YRESOLUTION, floorf(y_resolution*2.54f + 0.5f));
|
|
638 resunit = RESUNIT_INCH;
|
|
639 TIFFSetField(s->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit);
|
|
640 #endif
|
|
641
|
|
642 /* TODO: add the version of spandsp */
|
|
643 TIFFSetField(s->tiff_file, TIFFTAG_SOFTWARE, "spandsp");
|
|
644 if (gethostname(buf, sizeof(buf)) == 0)
|
|
645 TIFFSetField(s->tiff_file, TIFFTAG_HOSTCOMPUTER, buf);
|
|
646
|
|
647 //TIFFSetField(s->tiff_file, TIFFTAG_FAXRECVPARAMS, ???);
|
|
648 //TIFFSetField(s->tiff_file, TIFFTAG_FAXMODE, ???);
|
|
649 if (s->sub_address)
|
|
650 TIFFSetField(s->tiff_file, TIFFTAG_FAXSUBADDRESS, s->sub_address);
|
|
651 if (s->far_ident)
|
|
652 TIFFSetField(s->tiff_file, TIFFTAG_IMAGEDESCRIPTION, s->far_ident);
|
|
653 if (s->vendor)
|
|
654 TIFFSetField(s->tiff_file, TIFFTAG_MAKE, s->vendor);
|
|
655 if (s->model)
|
|
656 TIFFSetField(s->tiff_file, TIFFTAG_MODEL, s->model);
|
|
657
|
|
658 time(&now);
|
|
659 tm = localtime(&now);
|
|
660 sprintf(buf,
|
|
661 "%4d/%02d/%02d %02d:%02d:%02d",
|
|
662 tm->tm_year + 1900,
|
|
663 tm->tm_mon + 1,
|
|
664 tm->tm_mday,
|
|
665 tm->tm_hour,
|
|
666 tm->tm_min,
|
|
667 tm->tm_sec);
|
|
668 TIFFSetField(s->tiff_file, TIFFTAG_DATETIME, buf);
|
|
669 TIFFSetField(s->tiff_file, TIFFTAG_FAXRECVTIME, now - s->page_start_time);
|
|
670
|
|
671 TIFFSetField(s->tiff_file, TIFFTAG_IMAGELENGTH, s->image_length);
|
|
672 /* Set the total pages to 1. For any one page document we will get this
|
|
673 right. For multi-page documents we will need to come back and fill in
|
|
674 the right answer when we know it. */
|
|
675 TIFFSetField(s->tiff_file, TIFFTAG_PAGENUMBER, s->pages_transferred++, 1);
|
|
676 if (s->output_compression == COMPRESSION_CCITT_T4)
|
|
677 {
|
|
678 if (s->bad_rows)
|
|
679 {
|
|
680 TIFFSetField(s->tiff_file, TIFFTAG_BADFAXLINES, s->bad_rows);
|
|
681 TIFFSetField(s->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_REGENERATED);
|
|
682 TIFFSetField(s->tiff_file, TIFFTAG_CONSECUTIVEBADFAXLINES, s->longest_bad_row_run);
|
|
683 }
|
|
684 else
|
|
685 {
|
|
686 TIFFSetField(s->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN);
|
|
687 }
|
|
688 }
|
|
689 TIFFSetField(s->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width);
|
|
690
|
|
691 /* Write the image first.... */
|
|
692 for (row = 0; row < s->image_length; row++)
|
|
693 {
|
|
694 if (TIFFWriteScanline(s->tiff_file, s->image_buffer + row*s->bytes_per_row, row, 0) < 0)
|
|
695 {
|
|
696 span_log(&s->logging, SPAN_LOG_WARNING, "%s: Write error at row %d.\n", s->file, row);
|
|
697 break;
|
|
698 }
|
|
699 }
|
|
700 /* ....then the directory entry, and libtiff is happy. */
|
|
701 TIFFWriteDirectory(s->tiff_file);
|
|
702
|
|
703 s->bits = 0;
|
|
704 s->bits_to_date = 0;
|
|
705 s->consecutive_eols = 0;
|
|
706
|
|
707 s->image_size = 0;
|
|
708 return 0;
|
|
709 }
|
|
710 /*- End of function --------------------------------------------------------*/
|
|
711
|
|
712 int t4_rx_put_bit(t4_state_t *s, int bit)
|
|
713 {
|
|
714 int bits;
|
|
715
|
|
716 /* We decompress bit by bit, as the data stream is received. We need to
|
|
717 scan continuously for EOLs, so we might as well work this way. */
|
|
718 s->bits_to_date = (s->bits_to_date >> 1) | ((bit & 1) << 12);
|
|
719 if (++s->bits < 13)
|
|
720 return FALSE;
|
|
721 if (!s->first_eol_seen)
|
|
722 {
|
|
723 /* Do not let anything through to the decoder, until an EOL arrives. */
|
|
724 if ((s->bits_to_date & 0xFFF) != 0x800)
|
|
725 return FALSE;
|
|
726 s->bits = (s->line_encoding == T4_COMPRESSION_ITU_T4_1D) ? 1 : 0;
|
|
727 s->first_eol_seen = TRUE;
|
|
728 return FALSE;
|
|
729 }
|
|
730 /* Check if the image has already terminated */
|
|
731 if (s->consecutive_eols >= 5)
|
|
732 return TRUE;
|
|
733 if (s->row_is_2d && s->black_white == 0)
|
|
734 {
|
|
735 switch (T4_black_table[s->bits_to_date & 0x1FFF].state)
|
|
736 {
|
|
737 case S_EOL:
|
|
738 STATE_TRACE("EOL\n");
|
|
739 put_eol(s);
|
|
740 s->row_is_2d = !(s->bits_to_date & 0x1000);
|
|
741 s->bits -= (T4_black_table[s->bits_to_date & 0x1FFF].width + 1);
|
|
742 s->its_black = FALSE;
|
|
743 s->row_len = 0;
|
|
744 break;
|
|
745 default:
|
|
746 bits = s->bits_to_date & 0x7F;
|
|
747 STATE_TRACE("State %d, %d\n",
|
|
748 T4_common_table[bits].state,
|
|
749 T4_common_table[bits].width);
|
|
750 switch (T4_common_table[bits].state)
|
|
751 {
|
|
752 case S_Pass:
|
|
753 STATE_TRACE("Pass\n");
|
|
754 if (s->row_len < s->image_width)
|
|
755 {
|
|
756 if (s->pa != s->cur_runs)
|
|
757 {
|
|
758 while (s->b1 <= s->a0 && s->b1 < s->image_width)
|
|
759 {
|
|
760 s->b1 += s->pb[0] + s->pb[1];
|
|
761 s->pb += 2;
|
|
762 }
|
|
763 }
|
|
764 s->b1 += *s->pb++;
|
|
765 s->run_length += (s->b1 - s->a0);
|
|
766 s->a0 = s->b1;
|
|
767 s->b1 += *s->pb++;
|
|
768 }
|
|
769 break;
|
|
770 case S_Horiz:
|
|
771 STATE_TRACE("Horiz\n");
|
|
772 s->its_black = ((int) (s->pa - s->cur_runs)) & 1;
|
|
773 s->black_white = 2;
|
|
774 break;
|
|
775 case S_V0:
|
|
776 STATE_TRACE("V0 %d %d %d %d\n",
|
|
777 s->a0,
|
|
778 s->b1,
|
|
779 s->image_width,
|
|
780 s->run_length);
|
|
781 if (s->row_len < s->image_width)
|
|
782 {
|
|
783 if (s->pa != s->cur_runs)
|
|
784 {
|
|
785 while (s->b1 <= s->a0 && s->b1 < s->image_width)
|
|
786 {
|
|
787 s->b1 += s->pb[0] + s->pb[1];
|
|
788 s->pb += 2;
|
|
789 }
|
|
790 }
|
|
791 s->run_length += (s->b1 - s->a0);
|
|
792 s->a0 = s->b1;
|
|
793 put_run(s, ((int) (s->pa - s->cur_runs)) & 1);
|
|
794 s->b1 += *s->pb++;
|
|
795 }
|
|
796 break;
|
|
797 case S_VR:
|
|
798 STATE_TRACE("VR[%d] %d %d %d %d\n",
|
|
799 T4_common_table[bits].param,
|
|
800 s->a0,
|
|
801 s->b1,
|
|
802 s->image_width,
|
|
803 s->run_length);
|
|
804 if (s->row_len < s->image_width)
|
|
805 {
|
|
806 if (s->pa != s->cur_runs)
|
|
807 {
|
|
808 while (s->b1 <= s->a0 && s->b1 < s->image_width)
|
|
809 {
|
|
810 s->b1 += s->pb[0] + s->pb[1];
|
|
811 s->pb += 2;
|
|
812 }
|
|
813 }
|
|
814 s->run_length += (s->b1 + T4_common_table[bits].param - s->a0);
|
|
815 s->a0 = s->b1 + T4_common_table[bits].param;
|
|
816 put_run(s, ((int) (s->pa - s->cur_runs)) & 1);
|
|
817 s->b1 += *s->pb++;
|
|
818 }
|
|
819 break;
|
|
820 case S_VL:
|
|
821 STATE_TRACE("VL[%d] %d %d %d %d\n",
|
|
822 T4_common_table[bits].param,
|
|
823 s->a0,
|
|
824 s->b1,
|
|
825 s->image_width,
|
|
826 s->run_length);
|
|
827 if (s->row_len < s->image_width)
|
|
828 {
|
|
829 if (s->pa != s->cur_runs)
|
|
830 {
|
|
831 while (s->b1 <= s->a0 && s->b1 < s->image_width)
|
|
832 {
|
|
833 s->b1 += s->pb[0] + s->pb[1];
|
|
834 s->pb += 2;
|
|
835 }
|
|
836 }
|
|
837 s->run_length += (s->b1 - T4_common_table[bits].param - s->a0);
|
|
838 s->a0 = s->b1 - T4_common_table[bits].param;
|
|
839 put_run(s, ((int) (s->pa - s->cur_runs)) & 1);
|
|
840 s->b1 -= *--s->pb;
|
|
841 }
|
|
842 break;
|
|
843 case S_Ext:
|
|
844 STATE_TRACE("Ext %d 0x%x\n",
|
|
845 ((s->bits_to_date >> T4_common_table[bits].width) & 0x7),
|
|
846 s->bits_to_date);
|
|
847 if (s->row_len < s->image_width)
|
|
848 *s->pa++ = s->image_width - s->a0;
|
|
849 break;
|
|
850 case S_Null:
|
|
851 break;
|
|
852 default:
|
|
853 span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected T.4 state %d\n", T4_common_table[bits].state);
|
|
854 break;
|
|
855 }
|
|
856 s->bits -= T4_common_table[bits].width;
|
|
857 break;
|
|
858 }
|
|
859 }
|
|
860 else
|
|
861 {
|
|
862 if (s->its_black)
|
|
863 {
|
|
864 bits = s->bits_to_date & 0x1FFF;
|
|
865 STATE_TRACE("Black state %d %d\n", T4_black_table[bits].state, T4_black_table[bits].param);
|
|
866 switch (T4_black_table[bits].state)
|
|
867 {
|
|
868 case S_MakeUpB:
|
|
869 case S_MakeUp:
|
|
870 if (s->row_len < s->image_width)
|
|
871 {
|
|
872 s->run_length += T4_black_table[bits].param;
|
|
873 s->a0 += T4_black_table[bits].param;
|
|
874 }
|
|
875 break;
|
|
876 case S_TermB:
|
|
877 if (s->row_len < s->image_width)
|
|
878 {
|
|
879 s->run_length += T4_black_table[bits].param;
|
|
880 s->a0 += T4_black_table[bits].param;
|
|
881 put_run(s, 1);
|
|
882 if (s->black_white)
|
|
883 {
|
|
884 if (s->black_white == 1)
|
|
885 {
|
|
886 if (s->pa != s->cur_runs)
|
|
887 {
|
|
888 while (s->b1 <= s->a0 && s->b1 < s->image_width)
|
|
889 {
|
|
890 s->b1 += s->pb[0] + s->pb[1];
|
|
891 s->pb += 2;
|
|
892 }
|
|
893 }
|
|
894 }
|
|
895 s->black_white--;
|
|
896 }
|
|
897 }
|
|
898 s->its_black = FALSE;
|
|
899 break;
|
|
900 case S_EOL:
|
|
901 STATE_TRACE("EOL\n");
|
|
902 if (s->row_len == 0)
|
|
903 {
|
|
904 if (++s->consecutive_eols >= 5)
|
|
905 return TRUE;
|
|
906 }
|
|
907 else
|
|
908 {
|
|
909 s->consecutive_eols = 0;
|
|
910 put_eol(s);
|
|
911 }
|
|
912 if (s->line_encoding != T4_COMPRESSION_ITU_T4_1D)
|
|
913 {
|
|
914 s->row_is_2d = !(s->bits_to_date & 0x1000);
|
|
915 s->bits--;
|
|
916 }
|
|
917 s->its_black = FALSE;
|
|
918 s->row_len = 0;
|
|
919 break;
|
|
920 default:
|
|
921 /* Bad black */
|
|
922 s->black_white = 0;
|
|
923 break;
|
|
924 }
|
|
925 s->bits -= T4_black_table[bits].width;
|
|
926 }
|
|
927 else
|
|
928 {
|
|
929 bits = s->bits_to_date & 0xFFF;
|
|
930 STATE_TRACE("White state %d %d\n", T4_white_table[bits].state, T4_white_table[bits].param);
|
|
931 switch (T4_white_table[bits].state)
|
|
932 {
|
|
933 case S_MakeUpW:
|
|
934 case S_MakeUp:
|
|
935 if (s->row_len < s->image_width)
|
|
936 {
|
|
937 s->run_length += T4_white_table[bits].param;
|
|
938 s->a0 += T4_white_table[bits].param;
|
|
939 }
|
|
940 break;
|
|
941 case S_TermW:
|
|
942 if (s->row_len < s->image_width)
|
|
943 {
|
|
944 s->run_length += T4_white_table[bits].param;
|
|
945 s->a0 += T4_white_table[bits].param;
|
|
946 put_run(s, 0);
|
|
947 if (s->black_white)
|
|
948 {
|
|
949 if (s->black_white == 1)
|
|
950 {
|
|
951 if (s->pa != s->cur_runs)
|
|
952 {
|
|
953 while (s->b1 <= s->a0 && s->b1 < s->image_width)
|
|
954 {
|
|
955 s->b1 += s->pb[0] + s->pb[1];
|
|
956 s->pb += 2;
|
|
957 }
|
|
958 }
|
|
959 }
|
|
960 s->black_white--;
|
|
961 }
|
|
962 }
|
|
963 s->its_black = TRUE;
|
|
964 break;
|
|
965 case S_EOL:
|
|
966 STATE_TRACE("EOL\n");
|
|
967 if (s->row_len == 0)
|
|
968 {
|
|
969 if (++s->consecutive_eols >= 5)
|
|
970 return TRUE;
|
|
971 }
|
|
972 else
|
|
973 {
|
|
974 s->consecutive_eols = 0;
|
|
975 put_eol(s);
|
|
976 }
|
|
977 if (s->line_encoding != T4_COMPRESSION_ITU_T4_1D)
|
|
978 {
|
|
979 s->row_is_2d = !(s->bits_to_date & 0x1000);
|
|
980 s->bits--;
|
|
981 }
|
|
982 s->its_black = FALSE;
|
|
983 s->row_len = 0;
|
|
984 break;
|
|
985 default:
|
|
986 /* Bad white */
|
|
987 s->black_white = 0;
|
|
988 break;
|
|
989 }
|
|
990 s->bits -= T4_white_table[bits].width;
|
|
991 }
|
|
992 }
|
|
993
|
|
994 if (s->line_encoding == T4_COMPRESSION_ITU_T6 && s->row_len >= s->image_width)
|
|
995 {
|
|
996 /* T.6 has no EOL markers. We sense the end of a line by its length alone. */
|
|
997 STATE_TRACE("EOL T.6\n");
|
|
998 put_eol(s);
|
|
999 s->its_black = FALSE;
|
|
1000 s->row_len = 0;
|
|
1001 }
|
|
1002 return FALSE;
|
|
1003 }
|
|
1004 /*- End of function --------------------------------------------------------*/
|
|
1005
|
|
1006 t4_state_t *t4_rx_create(const char *file, int output_encoding)
|
|
1007 {
|
|
1008 t4_state_t *s;
|
|
1009
|
|
1010 if ((s = (t4_state_t *) malloc(sizeof(t4_state_t *))))
|
|
1011 {
|
|
1012 if (t4_rx_init(s, file, output_encoding))
|
|
1013 {
|
|
1014 free(s);
|
|
1015 return NULL;
|
|
1016 }
|
|
1017 }
|
|
1018 return s;
|
|
1019 }
|
|
1020 /*- End of function --------------------------------------------------------*/
|
|
1021
|
|
1022 int t4_rx_init(t4_state_t *s, const char *file, int output_encoding)
|
|
1023 {
|
|
1024 memset(s, 0, sizeof(*s));
|
|
1025 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
|
|
1026 span_log_set_protocol(&s->logging, "T.4");
|
|
1027
|
|
1028 span_log(&s->logging, SPAN_LOG_FLOW, "Start rx document\n");
|
|
1029
|
|
1030 if ((s->tiff_file = TIFFOpen(file, "w")) == NULL)
|
|
1031 return -1;
|
|
1032
|
|
1033 /* Save the file name for logging reports. */
|
|
1034 s->file = strdup(file);
|
|
1035 /* Only provide for one form of coding throughout the file, even though the
|
|
1036 coding on the wire could change between pages. */
|
|
1037 switch (output_encoding)
|
|
1038 {
|
|
1039 case T4_COMPRESSION_ITU_T4_1D:
|
|
1040 s->output_compression = COMPRESSION_CCITT_T4;
|
|
1041 s->output_t4_options = GROUP3OPT_FILLBITS;
|
|
1042 break;
|
|
1043 case T4_COMPRESSION_ITU_T4_2D:
|
|
1044 s->output_compression = COMPRESSION_CCITT_T4;
|
|
1045 s->output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING;
|
|
1046 break;
|
|
1047 case T4_COMPRESSION_ITU_T6:
|
|
1048 s->output_compression = COMPRESSION_CCITT_T6;
|
|
1049 s->output_t4_options = 0;
|
|
1050 break;
|
|
1051 }
|
|
1052
|
|
1053 /* Until we have a valid figure for the bytes per row, we need it to be set to a suitable
|
|
1054 value to ensure it will be seen as changing when the real value is used. */
|
|
1055 s->bytes_per_row = 0;
|
|
1056
|
|
1057 s->pages_transferred = 0;
|
|
1058
|
|
1059 s->image_buffer = NULL;
|
|
1060 s->image_buffer_size = 0;
|
|
1061
|
|
1062 /* Set some default values */
|
|
1063 s->x_resolution = T4_X_RESOLUTION_R8;
|
|
1064 s->y_resolution = T4_Y_RESOLUTION_FINE;
|
|
1065 s->image_width = 1728;
|
|
1066
|
|
1067 return 0;
|
|
1068 }
|
|
1069 /*- End of function --------------------------------------------------------*/
|
|
1070
|
|
1071 int t4_rx_start_page(t4_state_t *s)
|
|
1072 {
|
|
1073 int bytes_per_row;
|
|
1074 int run_space;
|
|
1075 uint32_t *bufptr;
|
|
1076
|
|
1077 span_log(&s->logging, SPAN_LOG_FLOW, "Start rx page - compression %d\n", s->line_encoding);
|
|
1078 if (s->tiff_file == NULL)
|
|
1079 return -1;
|
|
1080
|
|
1081 /* Calculate the scanline/tile width. */
|
|
1082 bytes_per_row = s->image_width/8;
|
|
1083 run_space = 2*((s->image_width + 31) & ~31);
|
|
1084 run_space = (run_space + 3)*sizeof(uint32_t);
|
|
1085 if (bytes_per_row != s->bytes_per_row)
|
|
1086 {
|
|
1087 /* Allocate the space required for decoding the new row length. */
|
|
1088 s->bytes_per_row = bytes_per_row;
|
|
1089 if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL)
|
|
1090 return -1;
|
|
1091 s->cur_runs = bufptr;
|
|
1092 if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL)
|
|
1093 return -1;
|
|
1094 s->ref_runs = bufptr;
|
|
1095 }
|
|
1096 memset(s->cur_runs, 0, run_space);
|
|
1097 memset(s->ref_runs, 0, run_space);
|
|
1098
|
|
1099 s->bits = 0;
|
|
1100 s->bits_to_date = 0;
|
|
1101
|
|
1102 s->row_is_2d = (s->line_encoding == T4_COMPRESSION_ITU_T6);
|
|
1103 s->first_eol_seen = (s->line_encoding == T4_COMPRESSION_ITU_T6);
|
|
1104
|
|
1105 s->bad_rows = 0;
|
|
1106 s->longest_bad_row_run = 0;
|
|
1107 s->curr_bad_row_run = 0;
|
|
1108 s->image_length = 0;
|
|
1109 s->consecutive_eols = 0;
|
|
1110 s->data = 0;
|
|
1111 s->bit = 8;
|
|
1112 s->image_size = 0;
|
|
1113 s->row_starts_at = 0;
|
|
1114 s->last_row_starts_at = 0;
|
|
1115
|
|
1116 s->row_len = 0;
|
|
1117 s->its_black = FALSE;
|
|
1118 s->black_white = 0;
|
|
1119
|
|
1120 s->pa = s->cur_runs;
|
|
1121 s->pb = s->ref_runs;
|
|
1122
|
|
1123 /* Initialise the reference line to all white */
|
|
1124 s->ref_runs[0] = s->image_width;
|
|
1125 s->ref_runs[1] = 0;
|
|
1126 s->a0 = 0;
|
|
1127 s->b1 = s->image_width;
|
|
1128 s->run_length = 0;
|
|
1129
|
|
1130 time (&s->page_start_time);
|
|
1131
|
|
1132 return 0;
|
|
1133 }
|
|
1134 /*- End of function --------------------------------------------------------*/
|
|
1135
|
|
1136 int t4_rx_delete(t4_state_t *s)
|
|
1137 {
|
|
1138 if (t4_rx_end(s))
|
|
1139 return -1;
|
|
1140 free(s);
|
|
1141 return 0;
|
|
1142 }
|
|
1143 /*- End of function --------------------------------------------------------*/
|
|
1144
|
|
1145 int t4_rx_end(t4_state_t *s)
|
|
1146 {
|
|
1147 int i;
|
|
1148
|
|
1149 if (s->tiff_file)
|
|
1150 {
|
|
1151 if (s->pages_transferred > 1)
|
|
1152 {
|
|
1153 /* We need to edit the TIFF directories. Until now we did not know
|
|
1154 the total page count, so the TIFF file currently says one. Now we
|
|
1155 need to set the correct total page count associated with each page. */
|
|
1156 for (i = 0; i < s->pages_transferred; i++)
|
|
1157 {
|
|
1158 TIFFSetDirectory(s->tiff_file, (tdir_t) i);
|
|
1159 TIFFSetField(s->tiff_file, TIFFTAG_PAGENUMBER, i, s->pages_transferred);
|
|
1160 TIFFWriteDirectory(s->tiff_file);
|
|
1161 }
|
|
1162 }
|
|
1163 TIFFClose(s->tiff_file);
|
|
1164 s->tiff_file = NULL;
|
|
1165 if (s->file)
|
|
1166 free((char *) s->file);
|
|
1167 s->file = NULL;
|
|
1168 }
|
|
1169 if (s->image_buffer)
|
|
1170 {
|
|
1171 free(s->image_buffer);
|
|
1172 s->image_buffer = NULL;
|
|
1173 s->image_buffer_size = 0;
|
|
1174 }
|
|
1175 if (s->cur_runs)
|
|
1176 {
|
|
1177 free(s->cur_runs);
|
|
1178 s->cur_runs = NULL;
|
|
1179 }
|
|
1180 if (s->ref_runs)
|
|
1181 {
|
|
1182 free(s->ref_runs);
|
|
1183 s->ref_runs = NULL;
|
|
1184 }
|
|
1185 return 0;
|
|
1186 }
|
|
1187 /*- End of function --------------------------------------------------------*/
|
|
1188
|
|
1189 void t4_rx_set_rx_encoding(t4_state_t *s, int encoding)
|
|
1190 {
|
|
1191 s->line_encoding = encoding;
|
|
1192 }
|
|
1193 /*- End of function --------------------------------------------------------*/
|
|
1194
|
|
1195 void t4_rx_set_image_width(t4_state_t *s, int width)
|
|
1196 {
|
|
1197 s->image_width = width;
|
|
1198 }
|
|
1199 /*- End of function --------------------------------------------------------*/
|
|
1200
|
|
1201 void t4_rx_set_y_resolution(t4_state_t *s, int resolution)
|
|
1202 {
|
|
1203 s->y_resolution = resolution;
|
|
1204 }
|
|
1205 /*- End of function --------------------------------------------------------*/
|
|
1206
|
|
1207 void t4_rx_set_x_resolution(t4_state_t *s, int resolution)
|
|
1208 {
|
|
1209 s->x_resolution = resolution;
|
|
1210 }
|
|
1211 /*- End of function --------------------------------------------------------*/
|
|
1212
|
|
1213 void t4_rx_set_sub_address(t4_state_t *s, const char *sub_address)
|
|
1214 {
|
|
1215 s->sub_address = (sub_address && sub_address[0]) ? sub_address : NULL;
|
|
1216 }
|
|
1217 /*- End of function --------------------------------------------------------*/
|
|
1218
|
|
1219 void t4_rx_set_far_ident(t4_state_t *s, const char *ident)
|
|
1220 {
|
|
1221 s->far_ident = (ident && ident[0]) ? ident : NULL;
|
|
1222 }
|
|
1223 /*- End of function --------------------------------------------------------*/
|
|
1224
|
|
1225 void t4_rx_set_vendor(t4_state_t *s, const char *vendor)
|
|
1226 {
|
|
1227 s->vendor = vendor;
|
|
1228 }
|
|
1229 /*- End of function --------------------------------------------------------*/
|
|
1230
|
|
1231 void t4_rx_set_model(t4_state_t *s, const char *model)
|
|
1232 {
|
|
1233 s->model = model;
|
|
1234 }
|
|
1235 /*- End of function --------------------------------------------------------*/
|
|
1236
|
|
1237 static __inline__ void put_bits(t4_state_t *s, int bits, int length)
|
|
1238 {
|
|
1239 static const int msbmask[9] =
|
|
1240 {
|
|
1241 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
|
|
1242 };
|
|
1243
|
|
1244 s->row_bits += length;
|
|
1245 while (length > s->bit)
|
|
1246 {
|
|
1247 s->data |= (bits >> (length - s->bit));
|
|
1248 length -= s->bit;
|
|
1249 flush_bits_to_image_buffer(s);
|
|
1250 }
|
|
1251 s->data |= ((bits & msbmask[length]) << (s->bit - length));
|
|
1252 s->bit -= length;
|
|
1253 if (s->bit == 0)
|
|
1254 flush_bits_to_image_buffer(s);
|
|
1255 }
|
|
1256 /*- End of function --------------------------------------------------------*/
|
|
1257
|
|
1258 /*
|
|
1259 * Write the sequence of codes that describes
|
|
1260 * the specified span of zero's or one's. The
|
|
1261 * appropriate table that holds the make-up and
|
|
1262 * terminating codes is supplied.
|
|
1263 */
|
|
1264 static __inline__ void put_span(t4_state_t *s, int32_t span, const T4_table_entry *tab)
|
|
1265 {
|
|
1266 const T4_table_entry *te;
|
|
1267
|
|
1268 te = &tab[63 + (2560 >> 6)];
|
|
1269 while (span >= 2560 + 64)
|
|
1270 {
|
|
1271 put_bits(s, te->code, te->length);
|
|
1272 span -= te->runlen;
|
|
1273 }
|
|
1274 te = &tab[63 + (span >> 6)];
|
|
1275 if (span >= 64)
|
|
1276 {
|
|
1277 put_bits(s, te->code, te->length);
|
|
1278 span -= te->runlen;
|
|
1279 }
|
|
1280 put_bits(s, tab[span].code, tab[span].length);
|
|
1281 }
|
|
1282 /*- End of function --------------------------------------------------------*/
|
|
1283
|
|
1284 /*
|
|
1285 * Find a span of ones or zeros using the supplied
|
|
1286 * table. The 'base' of the bit string is supplied
|
|
1287 * along with the start and end bit indices.
|
|
1288 */
|
|
1289 static __inline__ int find0span(uint8_t *bp, int bs, int be)
|
|
1290 {
|
|
1291 int bits;
|
|
1292 int n;
|
|
1293 int span;
|
|
1294 unsigned int *lp;
|
|
1295
|
|
1296 bits = be - bs;
|
|
1297 bp += bs >> 3;
|
|
1298 /* Check partial byte on LHS. */
|
|
1299 if (bits > 0 && (n = (bs & 7)))
|
|
1300 {
|
|
1301 span = run_length((*bp << n) & 0xFF);
|
|
1302 if (span > 8 - n) /* Value too generous */
|
|
1303 span = 8 - n;
|
|
1304 if (span > bits) /* Constrain span to bit range */
|
|
1305 span = bits;
|
|
1306 if (n + span < 8) /* Doesn't extend to edge of byte */
|
|
1307 return span;
|
|
1308 bits -= span;
|
|
1309 bp++;
|
|
1310 }
|
|
1311 else
|
|
1312 {
|
|
1313 span = 0;
|
|
1314 }
|
|
1315 if (bits >= (int) (2*8*sizeof(unsigned int)))
|
|
1316 {
|
|
1317 /* Align to natural integer boundary and check integers. */
|
|
1318 while (!is_aligned(bp, unsigned int))
|
|
1319 {
|
|
1320 if (*bp)
|
|
1321 return span + run_length(*bp);
|
|
1322 span += 8;
|
|
1323 bits -= 8;
|
|
1324 bp++;
|
|
1325 }
|
|
1326 lp = (unsigned int *) bp;
|
|
1327 while (bits >= (int) (8*sizeof(unsigned int)) && *lp == 0)
|
|
1328 {
|
|
1329 span += 8*sizeof(unsigned int);
|
|
1330 bits -= 8*sizeof(unsigned int);
|
|
1331 lp++;
|
|
1332 }
|
|
1333 bp = (uint8_t *) lp;
|
|
1334 }
|
|
1335 /* Scan full bytes for all 0's. */
|
|
1336 while (bits >= 8)
|
|
1337 {
|
|
1338 if (*bp)
|
|
1339 return span + run_length(*bp);
|
|
1340 span += 8;
|
|
1341 bits -= 8;
|
|
1342 bp++;
|
|
1343 }
|
|
1344 /* Check partial byte on RHS. */
|
|
1345 if (bits > 0)
|
|
1346 {
|
|
1347 n = run_length(*bp);
|
|
1348 span += ((n > bits) ? bits : n);
|
|
1349 }
|
|
1350 return span;
|
|
1351 }
|
|
1352 /*- End of function --------------------------------------------------------*/
|
|
1353
|
|
1354 static __inline__ int find1span(uint8_t *bp, int bs, int be)
|
|
1355 {
|
|
1356 int bits;
|
|
1357 int n;
|
|
1358 int span;
|
|
1359 unsigned int *lp;
|
|
1360
|
|
1361 bits = be - bs;
|
|
1362 bp += bs >> 3;
|
|
1363 /* Check partial byte on LHS. */
|
|
1364 if (bits > 0 && (n = (bs & 7)))
|
|
1365 {
|
|
1366 span = run_length(((*bp << n) & 0xFF) ^ 0xFF);
|
|
1367 if (span > 8 - n) /* Value too generous */
|
|
1368 span = 8 - n;
|
|
1369 if (span > bits) /* Constrain span to bit range */
|
|
1370 span = bits;
|
|
1371 if (n + span < 8) /* Doesn't extend to edge of byte */
|
|
1372 return span;
|
|
1373 bits -= span;
|
|
1374 bp++;
|
|
1375 }
|
|
1376 else
|
|
1377 {
|
|
1378 span = 0;
|
|
1379 }
|
|
1380 if (bits >= (int) (2*8*sizeof(unsigned int)))
|
|
1381 {
|
|
1382 /* Align to natural integer boundary and check integers. */
|
|
1383 while (!is_aligned(bp, unsigned int))
|
|
1384 {
|
|
1385 if (*bp != 0xFF)
|
|
1386 return span + run_length(*bp ^ 0xFF);
|
|
1387 span += 8;
|
|
1388 bits -= 8;
|
|
1389 bp++;
|
|
1390 }
|
|
1391 lp = (unsigned int *) bp;
|
|
1392 while (bits >= (int) (8*sizeof(unsigned int)) && *lp == (unsigned int) ~0)
|
|
1393 {
|
|
1394 span += 8*sizeof(unsigned int);
|
|
1395 bits -= 8*sizeof(unsigned int);
|
|
1396 lp++;
|
|
1397 }
|
|
1398 bp = (uint8_t *) lp;
|
|
1399 }
|
|
1400 /* Scan full bytes for all 1's. */
|
|
1401 while (bits >= 8)
|
|
1402 {
|
|
1403 if (*bp != 0xFF)
|
|
1404 return span + run_length(*bp ^ 0xFF);
|
|
1405 span += 8;
|
|
1406 bits -= 8;
|
|
1407 bp++;
|
|
1408 }
|
|
1409 /* Check partial byte on RHS. */
|
|
1410 if (bits > 0)
|
|
1411 {
|
|
1412 n = run_length(*bp ^ 0xFF);
|
|
1413 span += ((n > bits) ? bits : n);
|
|
1414 }
|
|
1415 return span;
|
|
1416 }
|
|
1417 /*- End of function --------------------------------------------------------*/
|
|
1418
|
|
1419 /*
|
|
1420 * Write an EOL code to the output stream. We also handle writing the tag
|
|
1421 * bit for the next scanline when doing 2D encoding.
|
|
1422 */
|
|
1423 static void t4_encode_eol(t4_state_t *s)
|
|
1424 {
|
|
1425 unsigned int code;
|
|
1426 int length;
|
|
1427
|
|
1428 if (s->line_encoding == T4_COMPRESSION_ITU_T4_1D)
|
|
1429 {
|
|
1430 code = 0x001;
|
|
1431 length = 12;
|
|
1432 }
|
|
1433 else
|
|
1434 {
|
|
1435 code = 0x0002 | (!s->row_is_2d);
|
|
1436 length = 13;
|
|
1437 }
|
|
1438 /* We may need to pad the row to a minimum length. */
|
|
1439 if (s->row_bits + length < s->min_row_bits)
|
|
1440 put_bits(s, 0, s->min_row_bits - (s->row_bits + length));
|
|
1441 put_bits(s, code, length);
|
|
1442 s->row_bits = 0;
|
|
1443 }
|
|
1444 /*- End of function --------------------------------------------------------*/
|
|
1445
|
|
1446 /*
|
|
1447 * 2D-encode a row of pixels. Consult ITU specification T.4 for the algorithm.
|
|
1448 */
|
|
1449 static void t4_encode_2d_row(t4_state_t *s, uint8_t *bp)
|
|
1450 {
|
|
1451 int a0;
|
|
1452 int a1;
|
|
1453 int b1;
|
|
1454 int a2;
|
|
1455 int b2;
|
|
1456 int d;
|
|
1457 static const T4_table_entry codes[] =
|
|
1458 {
|
|
1459 { 7, 0x03, 0 }, /* VR3 0000 011 */
|
|
1460 { 6, 0x03, 0 }, /* VR2 0000 11 */
|
|
1461 { 3, 0x03, 0 }, /* VR1 011 */
|
|
1462 { 1, 0x01, 0 }, /* V0 1 */
|
|
1463 { 3, 0x02, 0 }, /* VL1 010 */
|
|
1464 { 6, 0x02, 0 }, /* VL2 0000 10 */
|
|
1465 { 7, 0x02, 0 }, /* VL3 0000 010 */
|
|
1466 { 3, 0x01, 0 }, /* horizontal 001 */
|
|
1467 { 4, 0x01, 0 } /* pass 0001 */
|
|
1468 };
|
|
1469
|
|
1470 a0 = 0;
|
|
1471 a1 = (bp[0] & 0x80) ? 0 : find0span(bp, 0, s->image_width);
|
|
1472 b1 = (s->ref_row_buf[0] & 0x80) ? 0 : find0span(s->ref_row_buf, 0, s->image_width);
|
|
1473 for (;;)
|
|
1474 {
|
|
1475 b2 = (b1 < s->image_width) ? (b1 + (((s->ref_row_buf[b1 >> 3] << (b1 & 7)) & 0x80) ? find1span(s->ref_row_buf, b1, s->image_width) : find0span(s->ref_row_buf, b1, s->image_width))) : s->image_width;
|
|
1476 if (b2 >= a1)
|
|
1477 {
|
|
1478 d = b1 - a1;
|
|
1479 if (-3 <= d && d <= 3)
|
|
1480 {
|
|
1481 /* Vertical mode */
|
|
1482 put_bits(s, codes[d + 3].code, codes[d + 3].length);
|
|
1483 a0 = a1;
|
|
1484 }
|
|
1485 else
|
|
1486 {
|
|
1487 /* Horizontal mode */
|
|
1488 a2 = (a1 < s->image_width) ? (a1 + (((bp[a1 >> 3] << (a1 & 7)) & 0x80) ? find1span(bp, a1, s->image_width) : find0span(bp, a1, s->image_width))) : s->image_width;
|
|
1489 put_bits(s, codes[7].code, codes[7].length);
|
|
1490 if (a0 + a1 == 0 || ((bp[a0 >> 3] << (a0 & 7)) & 0x80) == 0)
|
|
1491 {
|
|
1492 put_span(s, a1 - a0, t4_white_codes);
|
|
1493 put_span(s, a2 - a1, t4_black_codes);
|
|
1494 }
|
|
1495 else
|
|
1496 {
|
|
1497 put_span(s, a1 - a0, t4_black_codes);
|
|
1498 put_span(s, a2 - a1, t4_white_codes);
|
|
1499 }
|
|
1500 a0 = a2;
|
|
1501 }
|
|
1502 }
|
|
1503 else
|
|
1504 {
|
|
1505 /* Pass mode */
|
|
1506 put_bits(s, codes[8].code, codes[8].length);
|
|
1507 a0 = b2;
|
|
1508 }
|
|
1509 if (a0 >= s->image_width)
|
|
1510 break;
|
|
1511 a1 = a0 + (((bp[a0 >> 3] << (a0 & 7)) & 0x80) ? find1span(bp, a0, s->image_width) : find0span(bp, a0, s->image_width));
|
|
1512 b1 = a0 + (((bp[a0 >> 3] << (a0 & 7)) & 0x80) ? find0span(s->ref_row_buf, a0, s->image_width) : find1span(s->ref_row_buf, a0, s->image_width));
|
|
1513 b1 = b1 + (((bp[a0 >> 3] << (a0 & 7)) & 0x80) ? find1span(s->ref_row_buf, b1, s->image_width) : find0span(s->ref_row_buf, b1, s->image_width));
|
|
1514 }
|
|
1515 }
|
|
1516 /*- End of function --------------------------------------------------------*/
|
|
1517
|
|
1518 /*
|
|
1519 * 1D-encode a row of pixels. The encoding is
|
|
1520 * a sequence of all-white or all-black spans
|
|
1521 * of pixels encoded with Huffman codes.
|
|
1522 */
|
|
1523 static void t4_encode_1d_row(t4_state_t *s, uint8_t *bp)
|
|
1524 {
|
|
1525 int span;
|
|
1526 int bs;
|
|
1527
|
|
1528 bs = 0;
|
|
1529 for (;;)
|
|
1530 {
|
|
1531 span = find0span(bp, bs, s->image_width); /* white span */
|
|
1532 put_span(s, span, t4_white_codes);
|
|
1533 bs += span;
|
|
1534 if (bs >= s->image_width)
|
|
1535 break;
|
|
1536 span = find1span(bp, bs, s->image_width); /* black span */
|
|
1537 put_span(s, span, t4_black_codes);
|
|
1538 bs += span;
|
|
1539 if (bs >= s->image_width)
|
|
1540 break;
|
|
1541 }
|
|
1542 }
|
|
1543 /*- End of function --------------------------------------------------------*/
|
|
1544
|
|
1545 static int t4_encode_row(t4_state_t *s, uint8_t *bp)
|
|
1546 {
|
|
1547 switch (s->line_encoding)
|
|
1548 {
|
|
1549 case T4_COMPRESSION_ITU_T6:
|
|
1550 /* T.6 compression is a trivial step up from T.4 2D, so we just
|
|
1551 throw it in here. T.6 is only used with error correction,
|
|
1552 so it does not need independantly compressed (i.e. 1D) lines
|
|
1553 to recover from data errors. It doesn't need EOLs, either. */
|
|
1554 t4_encode_2d_row(s, bp);
|
|
1555 memcpy(s->ref_row_buf, bp, s->bytes_per_row);
|
|
1556 break;
|
|
1557 case T4_COMPRESSION_ITU_T4_2D:
|
|
1558 t4_encode_eol(s);
|
|
1559 if (s->row_is_2d)
|
|
1560 {
|
|
1561 t4_encode_2d_row(s, bp);
|
|
1562 s->rows_to_next_1d_row--;
|
|
1563 }
|
|
1564 else
|
|
1565 {
|
|
1566 t4_encode_1d_row(s, bp);
|
|
1567 s->row_is_2d = TRUE;
|
|
1568 }
|
|
1569 if (s->rows_to_next_1d_row <= 0)
|
|
1570 {
|
|
1571 /* Insert a row of 1D encoding */
|
|
1572 s->row_is_2d = FALSE;
|
|
1573 s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1;
|
|
1574 }
|
|
1575 else
|
|
1576 {
|
|
1577 memcpy(s->ref_row_buf, bp, s->bytes_per_row);
|
|
1578 }
|
|
1579 break;
|
|
1580 default:
|
|
1581 case T4_COMPRESSION_ITU_T4_1D:
|
|
1582 t4_encode_eol(s);
|
|
1583 t4_encode_1d_row(s, bp);
|
|
1584 break;
|
|
1585 }
|
|
1586 bp += s->bytes_per_row;
|
|
1587 s->row++;
|
|
1588 return 1;
|
|
1589 }
|
|
1590 /*- End of function --------------------------------------------------------*/
|
|
1591
|
|
1592 t4_state_t *t4_tx_create(const char *file, int start_page, int stop_page)
|
|
1593 {
|
|
1594 t4_state_t *s;
|
|
1595
|
|
1596 if ((s = (t4_state_t *) malloc(sizeof(t4_state_t *))))
|
|
1597 {
|
|
1598 if (t4_tx_init(s, file, start_page, stop_page))
|
|
1599 {
|
|
1600 free(s);
|
|
1601 return NULL;
|
|
1602 }
|
|
1603 }
|
|
1604 return s;
|
|
1605 }
|
|
1606 /*- End of function --------------------------------------------------------*/
|
|
1607
|
|
1608 int t4_tx_init(t4_state_t *s, const char *file, int start_page, int stop_page)
|
|
1609 {
|
|
1610 float x_resolution;
|
|
1611 float y_resolution;
|
|
1612 uint16_t res_unit;
|
|
1613 uint32_t parm;
|
|
1614
|
|
1615 memset(s, 0, sizeof(*s));
|
|
1616 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
|
|
1617 span_log_set_protocol(&s->logging, "T.4");
|
|
1618
|
|
1619 span_log(&s->logging, SPAN_LOG_FLOW, "Start tx document\n");
|
|
1620
|
|
1621 if ((s->tiff_file = TIFFOpen(file, "r")) == NULL)
|
|
1622 return -1;
|
|
1623
|
|
1624 s->file = strdup(file);
|
|
1625 s->start_page = (start_page >= 0) ? start_page : 0;
|
|
1626 s->stop_page = (stop_page >= 0) ? stop_page : INT_MAX;
|
|
1627 TIFFGetField(s->tiff_file, TIFFTAG_IMAGEWIDTH, &parm);
|
|
1628 s->image_width = parm;
|
|
1629 s->bytes_per_row = (s->image_width + 7)/8;
|
|
1630 TIFFGetField(s->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution);
|
|
1631 TIFFGetField(s->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution);
|
|
1632 TIFFGetField(s->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit);
|
|
1633
|
|
1634 /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the
|
|
1635 precise value. The other value should be exact. */
|
|
1636 if ((res_unit == RESUNIT_CENTIMETER && fabsf(x_resolution - 160.74f) < 2.0f)
|
|
1637 ||
|
|
1638 (res_unit == RESUNIT_INCH && fabs(x_resolution - 408.0f) < 2.0f))
|
|
1639 {
|
|
1640 s->x_resolution = T4_X_RESOLUTION_R16;
|
|
1641 }
|
|
1642 else if ((res_unit == RESUNIT_CENTIMETER && fabsf(x_resolution - 40.19f) < 2.0f)
|
|
1643 ||
|
|
1644 (res_unit == RESUNIT_INCH && fabs(x_resolution - 102.0f) < 2.0f))
|
|
1645 {
|
|
1646 s->x_resolution = T4_X_RESOLUTION_R4;
|
|
1647 }
|
|
1648 else
|
|
1649 {
|
|
1650 /* Treat everything else as R8. Most FAXes are this resolution anyway. */
|
|
1651 s->x_resolution = T4_X_RESOLUTION_R8;
|
|
1652 }
|
|
1653
|
|
1654 if ((res_unit == RESUNIT_CENTIMETER && fabsf(y_resolution - 154.0f) < 2.0f)
|
|
1655 ||
|
|
1656 (res_unit == RESUNIT_INCH && fabsf(y_resolution - 392.0f) < 2.0f))
|
|
1657 {
|
|
1658 s->y_resolution = T4_Y_RESOLUTION_SUPERFINE;
|
|
1659 s->max_rows_to_next_1d_row = 8;
|
|
1660 }
|
|
1661 else if ((res_unit == RESUNIT_CENTIMETER && fabsf(y_resolution - 77.0f) < 2.0f)
|
|
1662 ||
|
|
1663 (res_unit == RESUNIT_INCH && fabsf(y_resolution - 196.0f) < 2.0f))
|
|
1664 {
|
|
1665 s->y_resolution = T4_Y_RESOLUTION_FINE;
|
|
1666 s->max_rows_to_next_1d_row = 4;
|
|
1667 }
|
|
1668 else
|
|
1669 {
|
|
1670 s->y_resolution = T4_Y_RESOLUTION_STANDARD;
|
|
1671 s->max_rows_to_next_1d_row = 2;
|
|
1672 }
|
|
1673 s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1;
|
|
1674
|
|
1675 s->pages_transferred = s->start_page;
|
|
1676 if ((s->row_buf = malloc(s->bytes_per_row)) == NULL)
|
|
1677 return -1;
|
|
1678 if ((s->ref_row_buf = malloc(s->bytes_per_row)) == NULL)
|
|
1679 {
|
|
1680 free(s->row_buf);
|
|
1681 s->row_buf = NULL;
|
|
1682 return -1;
|
|
1683 }
|
|
1684 s->image_buffer_size = 0;
|
|
1685 return 0;
|
|
1686 }
|
|
1687 /*- End of function --------------------------------------------------------*/
|
|
1688
|
|
1689 static void make_header(t4_state_t *s, char *header)
|
|
1690 {
|
|
1691 time_t now;
|
|
1692 struct tm tm;
|
|
1693 static const char *months[] =
|
|
1694 {
|
|
1695 "Jan",
|
|
1696 "Feb",
|
|
1697 "Mar",
|
|
1698 "Apr",
|
|
1699 "May",
|
|
1700 "Jun",
|
|
1701 "Jul",
|
|
1702 "Aug",
|
|
1703 "Sep",
|
|
1704 "Oct",
|
|
1705 "Nov",
|
|
1706 "Dec"
|
|
1707 };
|
|
1708
|
|
1709 time(&now);
|
|
1710 tm = *localtime(&now);
|
|
1711 snprintf(header,
|
|
1712 132,
|
|
1713 " %2d-%s-%d %02d:%02d %-50s %-21s p.%d",
|
|
1714 tm.tm_mday,
|
|
1715 months[tm.tm_mon],
|
|
1716 tm.tm_year + 1900,
|
|
1717 tm.tm_hour,
|
|
1718 tm.tm_min,
|
|
1719 s->header_info,
|
|
1720 s->local_ident,
|
|
1721 s->pages_transferred + 1);
|
|
1722 }
|
|
1723 /*- End of function --------------------------------------------------------*/
|
|
1724
|
|
1725 int t4_tx_start_page(t4_state_t *s)
|
|
1726 {
|
|
1727 int row;
|
|
1728 int ok;
|
|
1729 int i;
|
|
1730 int pattern;
|
|
1731 int row_bufptr;
|
|
1732 int parm;
|
|
1733 char *t;
|
|
1734 char header[132 + 1];
|
|
1735
|
|
1736 span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d\n", s->pages_transferred);
|
|
1737 if (s->pages_transferred > s->stop_page)
|
|
1738 return -1;
|
|
1739 if (s->tiff_file == NULL)
|
|
1740 return -1;
|
|
1741 if (!TIFFSetDirectory(s->tiff_file, (tdir_t) s->pages_transferred))
|
|
1742 return -1;
|
|
1743 s->image_size = 0;
|
|
1744 s->bit = 8;
|
|
1745 s->row_is_2d = (s->line_encoding == T4_COMPRESSION_ITU_T6);
|
|
1746 s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1;
|
|
1747
|
|
1748 /* Allow for pages being of different width */
|
|
1749 TIFFGetField(s->tiff_file, TIFFTAG_IMAGEWIDTH, &parm);
|
|
1750 if (parm != s->image_width)
|
|
1751 {
|
|
1752 s->image_width = parm;
|
|
1753 s->bytes_per_row = (s->image_width + 7)/8;
|
|
1754 if ((s->row_buf = realloc(s->row_buf, s->bytes_per_row)) == NULL)
|
|
1755 return -1;
|
|
1756 if ((s->ref_row_buf = realloc(s->ref_row_buf, s->bytes_per_row)) == NULL)
|
|
1757 {
|
|
1758 free(s->row_buf);
|
|
1759 s->row_buf = NULL;
|
|
1760 return -1;
|
|
1761 }
|
|
1762 }
|
|
1763 memset(s->ref_row_buf, 0, s->bytes_per_row);
|
|
1764
|
|
1765 if (s->header_info && s->header_info[0])
|
|
1766 {
|
|
1767 /* Modify the resulting image to include a header line, typical of hardware FAX machines */
|
|
1768 make_header(s, header);
|
|
1769 for (row = 0; row < 16; row++)
|
|
1770 {
|
|
1771 t = header;
|
|
1772 row_bufptr = 0;
|
|
1773 for (t = header; *t && row_bufptr <= s->bytes_per_row - 2; t++)
|
|
1774 {
|
|
1775 pattern = header_font[(uint8_t) *t][row];
|
|
1776 s->row_buf[row_bufptr++] = (uint8_t) (pattern >> 8);
|
|
1777 s->row_buf[row_bufptr++] = (uint8_t) (pattern & 0xFF);
|
|
1778 }
|
|
1779 for ( ; row_bufptr <= s->bytes_per_row; )
|
|
1780 s->row_buf[row_bufptr++] = 0;
|
|
1781 switch (s->y_resolution)
|
|
1782 {
|
|
1783 case T4_Y_RESOLUTION_SUPERFINE:
|
|
1784 if ((ok = t4_encode_row(s, s->row_buf)) <= 0)
|
|
1785 return -1;
|
|
1786 if ((ok = t4_encode_row(s, s->row_buf)) <= 0)
|
|
1787 return -1;
|
|
1788 /* Fall through */
|
|
1789 case T4_Y_RESOLUTION_FINE:
|
|
1790 if ((ok = t4_encode_row(s, s->row_buf)) <= 0)
|
|
1791 return -1;
|
|
1792 /* Fall through */
|
|
1793 default:
|
|
1794 if ((ok = t4_encode_row(s, s->row_buf)) <= 0)
|
|
1795 return -1;
|
|
1796 break;
|
|
1797 }
|
|
1798 }
|
|
1799 }
|
|
1800 TIFFGetField(s->tiff_file, TIFFTAG_IMAGELENGTH, &s->image_length);
|
|
1801 for (row = 0; row < s->image_length; row++)
|
|
1802 {
|
|
1803 if ((ok = TIFFReadScanline(s->tiff_file, s->row_buf, row, 0)) <= 0)
|
|
1804 {
|
|
1805 span_log(&s->logging, SPAN_LOG_WARNING, "%s: Write error at row %d.\n", s->file, row);
|
|
1806 break;
|
|
1807 }
|
|
1808 if ((ok = t4_encode_row(s, s->row_buf)) <= 0)
|
|
1809 return -1;
|
|
1810 }
|
|
1811
|
|
1812 if (s->line_encoding != T4_COMPRESSION_ITU_T6)
|
|
1813 {
|
|
1814 /* Attach a return to control (RTC == 6 x EOLs) to the end of the page */
|
|
1815 s->row_is_2d = FALSE;
|
|
1816 for (i = 0; i < 6; i++)
|
|
1817 {
|
|
1818 t4_encode_eol(s);
|
|
1819 /* Suppress row padding between these EOLs */
|
|
1820 s->row_bits = INT_MAX - 1000;
|
|
1821 }
|
|
1822 }
|
|
1823 put_bits(s, 0, 7);
|
|
1824 s->bit_pos = 7;
|
|
1825 s->bit_ptr = 0;
|
|
1826 s->row_bits = 0;
|
|
1827
|
|
1828 return 0;
|
|
1829 }
|
|
1830 /*- End of function --------------------------------------------------------*/
|
|
1831
|
|
1832 int t4_tx_more_pages(t4_state_t *s)
|
|
1833 {
|
|
1834 span_log(&s->logging, SPAN_LOG_FLOW, "Checking for the existance of page %d\n", s->pages_transferred + 1);
|
|
1835 if (s->pages_transferred > s->stop_page)
|
|
1836 return -1;
|
|
1837 if (s->tiff_file == NULL)
|
|
1838 return -1;
|
|
1839 if (!TIFFSetDirectory(s->tiff_file, (tdir_t) s->pages_transferred + 1))
|
|
1840 return -1;
|
|
1841 return 0;
|
|
1842 }
|
|
1843 /*- End of function --------------------------------------------------------*/
|
|
1844
|
|
1845 int t4_tx_restart_page(t4_state_t *s)
|
|
1846 {
|
|
1847 s->bit_pos = 7;
|
|
1848 s->bit_ptr = 0;
|
|
1849 s->row_bits = 0;
|
|
1850 return 0;
|
|
1851 }
|
|
1852 /*- End of function --------------------------------------------------------*/
|
|
1853
|
|
1854 int t4_tx_end_page(t4_state_t *s)
|
|
1855 {
|
|
1856 s->pages_transferred++;
|
|
1857 return 0;
|
|
1858 }
|
|
1859 /*- End of function --------------------------------------------------------*/
|
|
1860
|
|
1861 int t4_tx_get_bit(t4_state_t *s)
|
|
1862 {
|
|
1863 int bit;
|
|
1864
|
|
1865 if (s->bit_ptr >= s->image_size)
|
|
1866 return PUTBIT_END_OF_DATA;
|
|
1867 bit = (s->image_buffer[s->bit_ptr] >> s->bit_pos) & 1;
|
|
1868 if (--s->bit_pos < 0)
|
|
1869 {
|
|
1870 s->bit_pos = 7;
|
|
1871 s->bit_ptr++;
|
|
1872 }
|
|
1873 return bit;
|
|
1874 }
|
|
1875 /*- End of function --------------------------------------------------------*/
|
|
1876
|
|
1877 int t4_tx_check_bit(t4_state_t *s)
|
|
1878 {
|
|
1879 int bit;
|
|
1880
|
|
1881 if (s->bit_ptr >= s->image_size)
|
|
1882 return PUTBIT_END_OF_DATA;
|
|
1883 bit = (s->image_buffer[s->bit_ptr] >> s->bit_pos) & 1;
|
|
1884 return bit;
|
|
1885 }
|
|
1886 /*- End of function --------------------------------------------------------*/
|
|
1887
|
|
1888 int t4_tx_delete(t4_state_t *s)
|
|
1889 {
|
|
1890 if (t4_tx_end(s))
|
|
1891 return -1;
|
|
1892 free(s);
|
|
1893 return 0;
|
|
1894 }
|
|
1895 /*- End of function --------------------------------------------------------*/
|
|
1896
|
|
1897 int t4_tx_end(t4_state_t *s)
|
|
1898 {
|
|
1899 if (s->tiff_file)
|
|
1900 {
|
|
1901 TIFFClose(s->tiff_file);
|
|
1902 s->tiff_file = NULL;
|
|
1903 if (s->file)
|
|
1904 free((char *) s->file);
|
|
1905 s->file = NULL;
|
|
1906 }
|
|
1907 if (s->image_buffer)
|
|
1908 {
|
|
1909 free(s->image_buffer);
|
|
1910 s->image_buffer = NULL;
|
|
1911 s->image_buffer_size = 0;
|
|
1912 }
|
|
1913 if (s->row_buf)
|
|
1914 {
|
|
1915 free(s->row_buf);
|
|
1916 s->row_buf = NULL;
|
|
1917 }
|
|
1918 if (s->ref_row_buf)
|
|
1919 {
|
|
1920 free(s->ref_row_buf);
|
|
1921 s->ref_row_buf = NULL;
|
|
1922 }
|
|
1923 return 0;
|
|
1924 }
|
|
1925 /*- End of function --------------------------------------------------------*/
|
|
1926
|
|
1927 void t4_tx_set_tx_encoding(t4_state_t *s, int encoding)
|
|
1928 {
|
|
1929 s->line_encoding = encoding;
|
|
1930 s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1;
|
|
1931 s->row_is_2d = FALSE;
|
|
1932 }
|
|
1933 /*- End of function --------------------------------------------------------*/
|
|
1934
|
|
1935 void t4_tx_set_min_row_bits(t4_state_t *s, int bits)
|
|
1936 {
|
|
1937 s->min_row_bits = bits;
|
|
1938 }
|
|
1939 /*- End of function --------------------------------------------------------*/
|
|
1940
|
|
1941 void t4_tx_set_local_ident(t4_state_t *s, const char *ident)
|
|
1942 {
|
|
1943 s->local_ident = (ident && ident[0]) ? ident : NULL;
|
|
1944 }
|
|
1945 /*- End of function --------------------------------------------------------*/
|
|
1946
|
|
1947 void t4_tx_set_header_info(t4_state_t *s, const char *info)
|
|
1948 {
|
|
1949 s->header_info = (info && info[0]) ? info : NULL;
|
|
1950 }
|
|
1951 /*- End of function --------------------------------------------------------*/
|
|
1952
|
|
1953 int t4_tx_get_y_resolution(t4_state_t *s)
|
|
1954 {
|
|
1955 return s->y_resolution;
|
|
1956 }
|
|
1957 /*- End of function --------------------------------------------------------*/
|
|
1958
|
|
1959 int t4_tx_get_x_resolution(t4_state_t *s)
|
|
1960 {
|
|
1961 return s->x_resolution;
|
|
1962 }
|
|
1963 /*- End of function --------------------------------------------------------*/
|
|
1964
|
|
1965 int t4_tx_get_image_width(t4_state_t *s)
|
|
1966 {
|
|
1967 return s->image_width;
|
|
1968 }
|
|
1969 /*- End of function --------------------------------------------------------*/
|
|
1970
|
|
1971 void t4_get_transfer_statistics(t4_state_t *s, t4_stats_t *t)
|
|
1972 {
|
|
1973 t->pages_transferred = s->pages_transferred;
|
|
1974 t->width = s->image_width;
|
|
1975 t->length = s->image_length;
|
|
1976 t->bad_rows = s->bad_rows;
|
|
1977 t->longest_bad_row_run = s->longest_bad_row_run;
|
|
1978 t->x_resolution = s->x_resolution;
|
|
1979 t->y_resolution = s->y_resolution;
|
|
1980 t->encoding = s->line_encoding;
|
|
1981 t->image_size = s->image_size;
|
|
1982 }
|
|
1983 /*- End of function --------------------------------------------------------*/
|
|
1984
|
|
1985 const char *t4_encoding_to_str(int encoding)
|
|
1986 {
|
|
1987 switch (encoding)
|
|
1988 {
|
|
1989 case T4_COMPRESSION_ITU_T4_1D:
|
|
1990 return "T.4 1-D";
|
|
1991 case T4_COMPRESSION_ITU_T4_2D:
|
|
1992 return "T.4 2-D";
|
|
1993 case T4_COMPRESSION_ITU_T6:
|
|
1994 return "T.6";
|
|
1995 }
|
|
1996 return "???";
|
|
1997 }
|
|
1998 /*- End of function --------------------------------------------------------*/
|
|
1999 /*- End of file ------------------------------------------------------------*/
|