Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/t4_rx.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
1 //#define T4_STATE_DEBUGGING | |
2 /* | |
3 * SpanDSP - a series of DSP components for telephony | |
4 * | |
5 * t4_rx.c - ITU T.4 FAX receive processing | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2003, 2007 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 Lesser General Public License version 2.1, | |
15 * as 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 Lesser General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU Lesser General Public | |
23 * License 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_rx.c,v 1.12.2.8 2009/12/21 17:18:39 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 #if defined(HAVE_CONFIG_H) | |
62 #include "config.h" | |
63 #endif | |
64 | |
65 #include <stdlib.h> | |
66 #include <inttypes.h> | |
67 #include <limits.h> | |
68 #include <stdio.h> | |
69 #include <fcntl.h> | |
70 #include <unistd.h> | |
71 #include <time.h> | |
72 #include <memory.h> | |
73 #include <string.h> | |
74 #if defined(HAVE_TGMATH_H) | |
75 #include <tgmath.h> | |
76 #endif | |
77 #if defined(HAVE_MATH_H) | |
78 #include <math.h> | |
79 #endif | |
80 #include "floating_fudge.h" | |
81 #include <tiffio.h> | |
82 | |
83 #include "spandsp/telephony.h" | |
84 #include "spandsp/logging.h" | |
85 #include "spandsp/bit_operations.h" | |
86 #include "spandsp/async.h" | |
87 #include "spandsp/t4_rx.h" | |
88 #include "spandsp/t4_tx.h" | |
89 #include "spandsp/version.h" | |
90 | |
91 #include "spandsp/private/logging.h" | |
92 #include "spandsp/private/t4_rx.h" | |
93 #include "spandsp/private/t4_tx.h" | |
94 | |
95 /*! The number of centimetres in one inch */ | |
96 #define CM_PER_INCH 2.54f | |
97 | |
98 /*! The number of EOLs to expect at the end of a T.4 page */ | |
99 #define EOLS_TO_END_ANY_RX_PAGE 6 | |
100 /*! The number of EOLs to check at the end of a T.4 page */ | |
101 #define EOLS_TO_END_T4_RX_PAGE 5 | |
102 /*! The number of EOLs to check at the end of a T.6 page */ | |
103 #define EOLS_TO_END_T6_RX_PAGE 2 | |
104 | |
105 #if defined(T4_STATE_DEBUGGING) | |
106 static void STATE_TRACE(const char *format, ...) | |
107 { | |
108 va_list arg_ptr; | |
109 | |
110 va_start(arg_ptr, format); | |
111 vprintf(format, arg_ptr); | |
112 va_end(arg_ptr); | |
113 } | |
114 /*- End of function --------------------------------------------------------*/ | |
115 #else | |
116 #define STATE_TRACE(...) /**/ | |
117 #endif | |
118 | |
119 /*! T.4 run length table entry */ | |
120 typedef struct | |
121 { | |
122 /*! Length of T.4 code, in bits */ | |
123 uint16_t length; | |
124 /*! T.4 code */ | |
125 uint16_t code; | |
126 /*! Run length, in bits */ | |
127 int16_t run_length; | |
128 } t4_run_table_entry_t; | |
129 | |
130 #include "t4_t6_decode_states.h" | |
131 | |
132 #if defined(HAVE_LIBTIFF) | |
133 static int set_tiff_directory_info(t4_state_t *s) | |
134 { | |
135 time_t now; | |
136 struct tm *tm; | |
137 char buf[256 + 1]; | |
138 uint16_t resunit; | |
139 float x_resolution; | |
140 float y_resolution; | |
141 t4_tiff_state_t *t; | |
142 | |
143 t = &s->tiff; | |
144 /* Prepare the directory entry fully before writing the image, or libtiff complains */ | |
145 TIFFSetField(t->tiff_file, TIFFTAG_COMPRESSION, t->output_compression); | |
146 if (t->output_compression == COMPRESSION_CCITT_T4) | |
147 { | |
148 TIFFSetField(t->tiff_file, TIFFTAG_T4OPTIONS, t->output_t4_options); | |
149 TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); | |
150 } | |
151 TIFFSetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width); | |
152 TIFFSetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, 1); | |
153 TIFFSetField(t->tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); | |
154 TIFFSetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1); | |
155 if (t->output_compression == COMPRESSION_CCITT_T4 | |
156 || | |
157 t->output_compression == COMPRESSION_CCITT_T6) | |
158 { | |
159 TIFFSetField(t->tiff_file, TIFFTAG_ROWSPERSTRIP, -1L); | |
160 } | |
161 else | |
162 { | |
163 TIFFSetField(t->tiff_file, | |
164 TIFFTAG_ROWSPERSTRIP, | |
165 TIFFDefaultStripSize(t->tiff_file, 0)); | |
166 } | |
167 TIFFSetField(t->tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); | |
168 TIFFSetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); | |
169 TIFFSetField(t->tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); | |
170 | |
171 x_resolution = s->x_resolution/100.0f; | |
172 y_resolution = s->y_resolution/100.0f; | |
173 /* Metric seems the sane thing to use in the 21st century, but a lot of lousy software | |
174 gets FAX resolutions wrong, and more get it wrong using metric than using inches. */ | |
175 #if 0 | |
176 TIFFSetField(t->tiff_file, TIFFTAG_XRESOLUTION, x_resolution); | |
177 TIFFSetField(t->tiff_file, TIFFTAG_YRESOLUTION, y_resolution); | |
178 resunit = RESUNIT_CENTIMETER; | |
179 TIFFSetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); | |
180 #else | |
181 TIFFSetField(t->tiff_file, TIFFTAG_XRESOLUTION, floorf(x_resolution*CM_PER_INCH + 0.5f)); | |
182 TIFFSetField(t->tiff_file, TIFFTAG_YRESOLUTION, floorf(y_resolution*CM_PER_INCH + 0.5f)); | |
183 resunit = RESUNIT_INCH; | |
184 TIFFSetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); | |
185 #endif | |
186 /* TODO: add the version of spandsp */ | |
187 TIFFSetField(t->tiff_file, TIFFTAG_SOFTWARE, "Spandsp " SPANDSP_RELEASE_DATETIME_STRING); | |
188 if (gethostname(buf, sizeof(buf)) == 0) | |
189 TIFFSetField(t->tiff_file, TIFFTAG_HOSTCOMPUTER, buf); | |
190 | |
191 #if defined(TIFFTAG_FAXDCS) | |
192 if (t->dcs) | |
193 TIFFSetField(t->tiff_file, TIFFTAG_FAXDCS, t->dcs); | |
194 #endif | |
195 if (t->sub_address) | |
196 TIFFSetField(t->tiff_file, TIFFTAG_FAXSUBADDRESS, t->sub_address); | |
197 if (t->far_ident) | |
198 TIFFSetField(t->tiff_file, TIFFTAG_IMAGEDESCRIPTION, t->far_ident); | |
199 if (t->vendor) | |
200 TIFFSetField(t->tiff_file, TIFFTAG_MAKE, t->vendor); | |
201 if (t->model) | |
202 TIFFSetField(t->tiff_file, TIFFTAG_MODEL, t->model); | |
203 | |
204 time(&now); | |
205 tm = localtime(&now); | |
206 sprintf(buf, | |
207 "%4d/%02d/%02d %02d:%02d:%02d", | |
208 tm->tm_year + 1900, | |
209 tm->tm_mon + 1, | |
210 tm->tm_mday, | |
211 tm->tm_hour, | |
212 tm->tm_min, | |
213 tm->tm_sec); | |
214 TIFFSetField(t->tiff_file, TIFFTAG_DATETIME, buf); | |
215 TIFFSetField(t->tiff_file, TIFFTAG_FAXRECVTIME, now - s->page_start_time); | |
216 | |
217 TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, s->image_length); | |
218 /* Set the total pages to 1. For any one page document we will get this | |
219 right. For multi-page documents we will need to come back and fill in | |
220 the right answer when we know it. */ | |
221 TIFFSetField(t->tiff_file, TIFFTAG_PAGENUMBER, s->current_page++, 1); | |
222 s->tiff.pages_in_file = s->current_page; | |
223 if (t->output_compression == COMPRESSION_CCITT_T4) | |
224 { | |
225 if (s->t4_t6_rx.bad_rows) | |
226 { | |
227 TIFFSetField(t->tiff_file, TIFFTAG_BADFAXLINES, s->t4_t6_rx.bad_rows); | |
228 TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_REGENERATED); | |
229 TIFFSetField(t->tiff_file, TIFFTAG_CONSECUTIVEBADFAXLINES, s->t4_t6_rx.longest_bad_row_run); | |
230 } | |
231 else | |
232 { | |
233 TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); | |
234 } | |
235 } | |
236 TIFFSetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width); | |
237 return 0; | |
238 } | |
239 /*- End of function --------------------------------------------------------*/ | |
240 | |
241 static int open_tiff_output_file(t4_state_t *s, const char *file) | |
242 { | |
243 if ((s->tiff.tiff_file = TIFFOpen(file, "w")) == NULL) | |
244 return -1; | |
245 return 0; | |
246 } | |
247 /*- End of function --------------------------------------------------------*/ | |
248 | |
249 static void write_tiff_image(t4_state_t *s) | |
250 { | |
251 /* Set up the TIFF directory info... */ | |
252 set_tiff_directory_info(s); | |
253 /* ..and then write the image... */ | |
254 if (TIFFWriteEncodedStrip(s->tiff.tiff_file, 0, s->image_buffer, s->image_length*s->bytes_per_row) < 0) | |
255 span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); | |
256 /* ...then the directory entry, and libtiff is happy. */ | |
257 TIFFWriteDirectory(s->tiff.tiff_file); | |
258 } | |
259 /*- End of function --------------------------------------------------------*/ | |
260 | |
261 static int close_tiff_output_file(t4_state_t *s) | |
262 { | |
263 int i; | |
264 t4_tiff_state_t *t; | |
265 | |
266 t = &s->tiff; | |
267 /* Perform any operations needed to tidy up a written TIFF file before | |
268 closure. */ | |
269 if (s->current_page > 1) | |
270 { | |
271 /* We need to edit the TIFF directories. Until now we did not know | |
272 the total page count, so the TIFF file currently says one. Now we | |
273 need to set the correct total page count associated with each page. */ | |
274 for (i = 0; i < s->current_page; i++) | |
275 { | |
276 TIFFSetDirectory(t->tiff_file, (tdir_t) i); | |
277 TIFFSetField(t->tiff_file, TIFFTAG_PAGENUMBER, i, s->current_page); | |
278 TIFFWriteDirectory(t->tiff_file); | |
279 } | |
280 } | |
281 TIFFClose(t->tiff_file); | |
282 t->tiff_file = NULL; | |
283 if (t->file) | |
284 { | |
285 /* Try not to leave a file behind, if we didn't receive any pages to | |
286 put in it. */ | |
287 if (s->current_page == 0) | |
288 remove(t->file); | |
289 free((char *) t->file); | |
290 t->file = NULL; | |
291 } | |
292 return 0; | |
293 } | |
294 /*- End of function --------------------------------------------------------*/ | |
295 | |
296 #else | |
297 | |
298 static int set_tiff_directory_info(t4_state_t *s) | |
299 { | |
300 return 0; | |
301 } | |
302 /*- End of function --------------------------------------------------------*/ | |
303 | |
304 static int get_tiff_directory_info(t4_state_t *s) | |
305 { | |
306 return 0; | |
307 } | |
308 /*- End of function --------------------------------------------------------*/ | |
309 | |
310 static int test_tiff_directory_info(t4_state_t *s) | |
311 { | |
312 return 0; | |
313 } | |
314 /*- End of function --------------------------------------------------------*/ | |
315 | |
316 static int open_tiff_input_file(t4_state_t *s, const char *file) | |
317 { | |
318 return 0; | |
319 } | |
320 /*- End of function --------------------------------------------------------*/ | |
321 | |
322 static int read_tiff_image(t4_state_t *s) | |
323 { | |
324 return 0; | |
325 } | |
326 /*- End of function --------------------------------------------------------*/ | |
327 | |
328 static int close_tiff_input_file(t4_state_t *s) | |
329 { | |
330 return 0; | |
331 } | |
332 /*- End of function --------------------------------------------------------*/ | |
333 | |
334 static int open_tiff_output_file(t4_state_t *s, const char *file) | |
335 { | |
336 return 0; | |
337 } | |
338 /*- End of function --------------------------------------------------------*/ | |
339 | |
340 static void write_tiff_image(t4_state_t *s) | |
341 { | |
342 return 0; | |
343 } | |
344 /*- End of function --------------------------------------------------------*/ | |
345 | |
346 static int close_tiff_output_file(t4_state_t *s) | |
347 { | |
348 return 0; | |
349 } | |
350 /*- End of function --------------------------------------------------------*/ | |
351 #endif | |
352 | |
353 static void update_row_bit_info(t4_state_t *s) | |
354 { | |
355 if (s->row_bits > s->max_row_bits) | |
356 s->max_row_bits = s->row_bits; | |
357 if (s->row_bits < s->min_row_bits) | |
358 s->min_row_bits = s->row_bits; | |
359 s->row_bits = 0; | |
360 } | |
361 /*- End of function --------------------------------------------------------*/ | |
362 | |
363 #if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) | |
364 static __inline__ int run_length(unsigned int bits) | |
365 { | |
366 return 7 - top_bit(bits); | |
367 } | |
368 /*- End of function --------------------------------------------------------*/ | |
369 #else | |
370 static __inline__ int run_length(unsigned int bits) | |
371 { | |
372 static const uint8_t run_len[256] = | |
373 { | |
374 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0F */ | |
375 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1F */ | |
376 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2F */ | |
377 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3F */ | |
378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */ | |
379 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5F */ | |
380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */ | |
381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7F */ | |
382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ | |
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */ | |
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */ | |
385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */ | |
386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */ | |
387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */ | |
388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */ | |
389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 - 0xFF */ | |
390 }; | |
391 | |
392 return run_len[bits]; | |
393 } | |
394 /*- End of function --------------------------------------------------------*/ | |
395 #endif | |
396 | |
397 static int free_buffers(t4_state_t *s) | |
398 { | |
399 if (s->image_buffer) | |
400 { | |
401 free(s->image_buffer); | |
402 s->image_buffer = NULL; | |
403 s->image_buffer_size = 0; | |
404 } | |
405 if (s->cur_runs) | |
406 { | |
407 free(s->cur_runs); | |
408 s->cur_runs = NULL; | |
409 } | |
410 if (s->ref_runs) | |
411 { | |
412 free(s->ref_runs); | |
413 s->ref_runs = NULL; | |
414 } | |
415 if (s->row_buf) | |
416 { | |
417 free(s->row_buf); | |
418 s->row_buf = NULL; | |
419 } | |
420 return 0; | |
421 } | |
422 /*- End of function --------------------------------------------------------*/ | |
423 | |
424 static __inline__ void add_run_to_row(t4_state_t *s) | |
425 { | |
426 if (s->t4_t6_rx.run_length >= 0) | |
427 { | |
428 s->row_len += s->t4_t6_rx.run_length; | |
429 /* Don't allow rows to grow too long, and overflow the buffers */ | |
430 if (s->row_len <= s->image_width) | |
431 s->cur_runs[s->t4_t6_rx.a_cursor++] = s->t4_t6_rx.run_length; | |
432 } | |
433 s->t4_t6_rx.run_length = 0; | |
434 } | |
435 /*- End of function --------------------------------------------------------*/ | |
436 | |
437 static int put_decoded_row(t4_state_t *s) | |
438 { | |
439 static const int msbmask[9] = | |
440 { | |
441 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff | |
442 }; | |
443 uint8_t *t; | |
444 uint32_t i; | |
445 uint32_t *p; | |
446 int fudge; | |
447 int row_starts_at; | |
448 int x; | |
449 int j; | |
450 | |
451 if (s->t4_t6_rx.run_length) | |
452 add_run_to_row(s); | |
453 #if defined(T4_STATE_DEBUGGING) | |
454 /* Dump the runs of black and white for analysis */ | |
455 { | |
456 int total; | |
457 | |
458 total = 0; | |
459 for (x = 0; x < s->t4_t6_rx.b_cursor; x++) | |
460 total += s->ref_runs[x]; | |
461 printf("Ref (%d)", total); | |
462 for (x = 0; x < s->t4_t6_rx.b_cursor; x++) | |
463 printf(" %" PRIu32, s->ref_runs[x]); | |
464 printf("\n"); | |
465 total = 0; | |
466 for (x = 0; x < s->t4_t6_rx.a_cursor; x++) | |
467 total += s->cur_runs[x]; | |
468 printf("Cur (%d)", total); | |
469 for (x = 0; x < s->t4_t6_rx.a_cursor; x++) | |
470 printf(" %" PRIu32, s->cur_runs[x]); | |
471 printf("\n"); | |
472 } | |
473 #endif | |
474 row_starts_at = s->image_size; | |
475 /* Make sure there is enough room for another row */ | |
476 if (s->image_size + s->bytes_per_row >= s->image_buffer_size) | |
477 { | |
478 if ((t = realloc(s->image_buffer, s->image_buffer_size + 100*s->bytes_per_row)) == NULL) | |
479 return -1; | |
480 s->image_buffer_size += 100*s->bytes_per_row; | |
481 s->image_buffer = t; | |
482 } | |
483 if (s->row_len == s->image_width) | |
484 { | |
485 STATE_TRACE("%d Good row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D"); | |
486 if (s->t4_t6_rx.curr_bad_row_run) | |
487 { | |
488 if (s->t4_t6_rx.curr_bad_row_run > s->t4_t6_rx.longest_bad_row_run) | |
489 s->t4_t6_rx.longest_bad_row_run = s->t4_t6_rx.curr_bad_row_run; | |
490 s->t4_t6_rx.curr_bad_row_run = 0; | |
491 } | |
492 /* Convert the runs to a bit image of the row */ | |
493 /* White/black/white... runs, always starting with white. That means the first run could be | |
494 zero length. */ | |
495 for (x = 0, fudge = 0; x < s->t4_t6_rx.a_cursor; x++, fudge ^= 0xFF) | |
496 { | |
497 i = s->cur_runs[x]; | |
498 if ((int) i >= s->tx_bits) | |
499 { | |
500 s->tx_bitstream = (s->tx_bitstream << s->tx_bits) | (msbmask[s->tx_bits] & fudge); | |
501 for (i += (8 - s->tx_bits); i >= 8; i -= 8) | |
502 { | |
503 s->tx_bits = 8; | |
504 s->image_buffer[s->image_size++] = (uint8_t) s->tx_bitstream; | |
505 s->tx_bitstream = fudge; | |
506 } | |
507 } | |
508 s->tx_bitstream = (s->tx_bitstream << i) | (msbmask[i] & fudge); | |
509 s->tx_bits -= i; | |
510 } | |
511 s->image_length++; | |
512 } | |
513 else | |
514 { | |
515 STATE_TRACE("%d Bad row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D"); | |
516 /* Try to clean up the bad runs, and produce something reasonable as the reference | |
517 row for the next row. Use a copy of the previous good row as the actual current | |
518 row. If the row only fell apart near the end, reusing it might be the best | |
519 solution. */ | |
520 for (j = 0, fudge = 0; j < s->t4_t6_rx.a_cursor && fudge < s->image_width; j++) | |
521 fudge += s->cur_runs[j]; | |
522 if (fudge < s->image_width) | |
523 { | |
524 /* Try to pad with white, and avoid black, to minimise mess on the image. */ | |
525 if ((s->t4_t6_rx.a_cursor & 1)) | |
526 { | |
527 /* We currently finish in white. We could extend that, but it is probably of | |
528 the right length. Changing it would only further mess up what happens in the | |
529 next row. It seems better to add a black spot, and an extra white run. */ | |
530 s->cur_runs[s->t4_t6_rx.a_cursor++] = 1; | |
531 fudge++; | |
532 if (fudge < s->image_width) | |
533 s->cur_runs[s->t4_t6_rx.a_cursor++] = s->image_width - fudge; | |
534 } | |
535 else | |
536 { | |
537 /* We currently finish on black, so we add an extra white run to fill out the line. */ | |
538 s->cur_runs[s->t4_t6_rx.a_cursor++] = s->image_width - fudge; | |
539 } | |
540 } | |
541 else | |
542 { | |
543 /* Trim the last element to align with the proper image width */ | |
544 s->cur_runs[s->t4_t6_rx.a_cursor] += (s->image_width - fudge); | |
545 } | |
546 /* Ensure there is a previous line to copy from. */ | |
547 if (s->image_size != s->t4_t6_rx.last_row_starts_at) | |
548 { | |
549 /* Copy the previous row over this one */ | |
550 memcpy(s->image_buffer + s->image_size, s->image_buffer + s->t4_t6_rx.last_row_starts_at, s->bytes_per_row); | |
551 s->image_size += s->bytes_per_row; | |
552 s->image_length++; | |
553 } | |
554 s->t4_t6_rx.bad_rows++; | |
555 s->t4_t6_rx.curr_bad_row_run++; | |
556 } | |
557 | |
558 /* Pad the row as it becomes the reference row, so there are no odd runs to pick up if we | |
559 step off the end of the list. */ | |
560 s->cur_runs[s->t4_t6_rx.a_cursor] = 0; | |
561 s->cur_runs[s->t4_t6_rx.a_cursor + 1] = 0; | |
562 | |
563 /* Prepare the buffers for the next row. */ | |
564 s->t4_t6_rx.last_row_starts_at = row_starts_at; | |
565 /* Swap the buffers */ | |
566 p = s->cur_runs; | |
567 s->cur_runs = s->ref_runs; | |
568 s->ref_runs = p; | |
569 | |
570 s->t4_t6_rx.b_cursor = 1; | |
571 s->t4_t6_rx.a_cursor = 0; | |
572 s->t4_t6_rx.b1 = s->ref_runs[0]; | |
573 s->t4_t6_rx.a0 = 0; | |
574 | |
575 s->t4_t6_rx.run_length = 0; | |
576 | |
577 return 0; | |
578 } | |
579 /*- End of function --------------------------------------------------------*/ | |
580 | |
581 SPAN_DECLARE(int) t4_rx_end_page(t4_state_t *s) | |
582 { | |
583 int row; | |
584 int i; | |
585 | |
586 if (s->line_encoding == T4_COMPRESSION_ITU_T6) | |
587 { | |
588 /* Push enough zeros through the decoder to flush out any remaining codes */ | |
589 for (i = 0; i < 13; i++) | |
590 t4_rx_put_bit(s, 0); | |
591 } | |
592 if (s->t4_t6_rx.curr_bad_row_run) | |
593 { | |
594 if (s->t4_t6_rx.curr_bad_row_run > s->t4_t6_rx.longest_bad_row_run) | |
595 s->t4_t6_rx.longest_bad_row_run = s->t4_t6_rx.curr_bad_row_run; | |
596 s->t4_t6_rx.curr_bad_row_run = 0; | |
597 } | |
598 | |
599 if (s->image_size == 0) | |
600 return -1; | |
601 | |
602 if (s->t4_t6_rx.row_write_handler) | |
603 { | |
604 for (row = 0; row < s->image_length; row++) | |
605 { | |
606 if (s->t4_t6_rx.row_write_handler(s->t4_t6_rx.row_write_user_data, s->image_buffer + row*s->bytes_per_row, s->bytes_per_row) < 0) | |
607 { | |
608 span_log(&s->logging, SPAN_LOG_WARNING, "Write error at row %d.\n", row); | |
609 break; | |
610 } | |
611 } | |
612 /* Write a blank row to indicate the end of the image. */ | |
613 if (s->t4_t6_rx.row_write_handler(s->t4_t6_rx.row_write_user_data, NULL, 0) < 0) | |
614 span_log(&s->logging, SPAN_LOG_WARNING, "Write error at row %d.\n", row); | |
615 } | |
616 else | |
617 { | |
618 write_tiff_image(s); | |
619 } | |
620 s->t4_t6_rx.rx_bits = 0; | |
621 s->t4_t6_rx.rx_skip_bits = 0; | |
622 s->t4_t6_rx.rx_bitstream = 0; | |
623 s->t4_t6_rx.consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; | |
624 | |
625 s->image_size = 0; | |
626 return 0; | |
627 } | |
628 /*- End of function --------------------------------------------------------*/ | |
629 | |
630 static __inline__ void drop_rx_bits(t4_state_t *s, int bits) | |
631 { | |
632 /* Only remove one bit right now. The rest need to be removed step by step, | |
633 checking for a misaligned EOL along the way. This is time consuming, but | |
634 if we don't do it a single bit error can severely damage an image. */ | |
635 s->row_bits += bits; | |
636 s->t4_t6_rx.rx_skip_bits += (bits - 1); | |
637 s->t4_t6_rx.rx_bits--; | |
638 s->t4_t6_rx.rx_bitstream >>= 1; | |
639 } | |
640 /*- End of function --------------------------------------------------------*/ | |
641 | |
642 static __inline__ void force_drop_rx_bits(t4_state_t *s, int bits) | |
643 { | |
644 /* This should only be called to drop the bits of an EOL, as that is the | |
645 only place where it is safe to drop them all at once. */ | |
646 s->row_bits += bits; | |
647 s->t4_t6_rx.rx_skip_bits = 0; | |
648 s->t4_t6_rx.rx_bits -= bits; | |
649 s->t4_t6_rx.rx_bitstream >>= bits; | |
650 } | |
651 /*- End of function --------------------------------------------------------*/ | |
652 | |
653 static int rx_put_bits(t4_state_t *s, uint32_t bit_string, int quantity) | |
654 { | |
655 int bits; | |
656 | |
657 /* We decompress bit by bit, as the data stream is received. We need to | |
658 scan continuously for EOLs, so we might as well work this way. */ | |
659 s->line_image_size += quantity; | |
660 s->t4_t6_rx.rx_bitstream |= (bit_string << s->t4_t6_rx.rx_bits); | |
661 /* The longest item we need to scan for is 13 bits long (a 2D EOL), so we | |
662 need a minimum of 13 bits in the buffer to proceed with any bit stream | |
663 analysis. */ | |
664 if ((s->t4_t6_rx.rx_bits += quantity) < 13) | |
665 return FALSE; | |
666 if (s->t4_t6_rx.consecutive_eols) | |
667 { | |
668 /* Check if the image has already terminated. */ | |
669 if (s->t4_t6_rx.consecutive_eols >= EOLS_TO_END_ANY_RX_PAGE) | |
670 return TRUE; | |
671 /* Check if the image hasn't even started. */ | |
672 if (s->t4_t6_rx.consecutive_eols < 0) | |
673 { | |
674 /* We are waiting for the very first EOL (1D or 2D only). */ | |
675 /* We need to take this bit by bit, as the EOL could be anywhere, | |
676 and any junk could preceed it. */ | |
677 while ((s->t4_t6_rx.rx_bitstream & 0xFFF) != 0x800) | |
678 { | |
679 s->t4_t6_rx.rx_bitstream >>= 1; | |
680 if (--s->t4_t6_rx.rx_bits < 13) | |
681 return FALSE; | |
682 } | |
683 /* We have an EOL, so now the page begins and we can proceed to | |
684 process the bit stream as image data. */ | |
685 s->t4_t6_rx.consecutive_eols = 0; | |
686 if (s->line_encoding == T4_COMPRESSION_ITU_T4_1D) | |
687 { | |
688 s->row_is_2d = FALSE; | |
689 force_drop_rx_bits(s, 12); | |
690 } | |
691 else | |
692 { | |
693 s->row_is_2d = !(s->t4_t6_rx.rx_bitstream & 0x1000); | |
694 force_drop_rx_bits(s, 13); | |
695 } | |
696 } | |
697 } | |
698 | |
699 while (s->t4_t6_rx.rx_bits >= 13) | |
700 { | |
701 /* We need to check for EOLs bit by bit through the whole stream. If | |
702 we just try looking between code words, we will miss an EOL when a bit | |
703 error has throw the code words completely out of step. The can mean | |
704 recovery takes many lines, and the image gets really messed up. */ | |
705 /* Although EOLs are not inserted at the end of each row of a T.6 image, | |
706 they are still perfectly valid, and can terminate an image. */ | |
707 if ((s->t4_t6_rx.rx_bitstream & 0x0FFF) == 0x0800) | |
708 { | |
709 STATE_TRACE("EOL\n"); | |
710 if (s->row_len == 0) | |
711 { | |
712 /* A zero length row - i.e. 2 consecutive EOLs - is distinctly | |
713 the end of page condition. That's all we actually get on a | |
714 T.6 page. However, there are a minimum of 6 EOLs at the end of | |
715 any T.4 page. We can look for more than 2 EOLs in case bit | |
716 errors simulate the end of page condition at the wrong point. | |
717 Such robust checking is irrelevant for a T.6 page, as it should | |
718 be error free. */ | |
719 /* Note that for a T.6 page we should get here on the very first | |
720 EOL, as the row length should be zero at that point. Therefore | |
721 we should count up both EOLs, unless there is some bogus partial | |
722 row ahead of them. */ | |
723 s->t4_t6_rx.consecutive_eols++; | |
724 if (s->line_encoding == T4_COMPRESSION_ITU_T6) | |
725 { | |
726 if (s->t4_t6_rx.consecutive_eols >= EOLS_TO_END_T6_RX_PAGE) | |
727 { | |
728 s->t4_t6_rx.consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; | |
729 return TRUE; | |
730 } | |
731 } | |
732 else | |
733 { | |
734 if (s->t4_t6_rx.consecutive_eols >= EOLS_TO_END_T4_RX_PAGE) | |
735 { | |
736 s->t4_t6_rx.consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; | |
737 return TRUE; | |
738 } | |
739 } | |
740 } | |
741 else | |
742 { | |
743 /* The EOLs are not back-to-back, so they are not part of the | |
744 end of page condition. */ | |
745 if (s->t4_t6_rx.run_length > 0) | |
746 add_run_to_row(s); | |
747 s->t4_t6_rx.consecutive_eols = 0; | |
748 if (put_decoded_row(s)) | |
749 return TRUE; | |
750 update_row_bit_info(s); | |
751 } | |
752 if (s->line_encoding == T4_COMPRESSION_ITU_T4_2D) | |
753 { | |
754 s->row_is_2d = !(s->t4_t6_rx.rx_bitstream & 0x1000); | |
755 force_drop_rx_bits(s, 13); | |
756 } | |
757 else | |
758 { | |
759 force_drop_rx_bits(s, 12); | |
760 } | |
761 s->t4_t6_rx.its_black = FALSE; | |
762 s->t4_t6_rx.black_white = 0; | |
763 s->t4_t6_rx.run_length = 0; | |
764 s->row_len = 0; | |
765 continue; | |
766 } | |
767 if (s->t4_t6_rx.rx_skip_bits) | |
768 { | |
769 /* We are clearing out the remaining bits of the last code word we | |
770 absorbed. */ | |
771 s->t4_t6_rx.rx_skip_bits--; | |
772 s->t4_t6_rx.rx_bits--; | |
773 s->t4_t6_rx.rx_bitstream >>= 1; | |
774 continue; | |
775 } | |
776 if (s->row_is_2d && s->t4_t6_rx.black_white == 0) | |
777 { | |
778 bits = s->t4_t6_rx.rx_bitstream & 0x7F; | |
779 STATE_TRACE("State %d, %d - ", | |
780 t4_2d_table[bits].state, | |
781 t4_2d_table[bits].width); | |
782 if (s->row_len >= s->image_width) | |
783 { | |
784 drop_rx_bits(s, t4_2d_table[bits].width); | |
785 continue; | |
786 } | |
787 if (s->t4_t6_rx.a_cursor) | |
788 { | |
789 /* Move past a0, always staying on the current colour */ | |
790 for ( ; s->t4_t6_rx.b1 <= s->t4_t6_rx.a0; s->t4_t6_rx.b_cursor += 2) | |
791 s->t4_t6_rx.b1 += (s->ref_runs[s->t4_t6_rx.b_cursor] + s->ref_runs[s->t4_t6_rx.b_cursor + 1]); | |
792 } | |
793 switch (t4_2d_table[bits].state) | |
794 { | |
795 case S_Horiz: | |
796 STATE_TRACE("Horiz %d %d %d\n", | |
797 s->image_width, | |
798 s->t4_t6_rx.a0, | |
799 s->t4_t6_rx.a_cursor); | |
800 /* We now need to extract a white/black or black/white pair of runs, using the 1D | |
801 method. If the first of the pair takes us exactly to the end of the row, there | |
802 should still be a zero length element for the second of the pair. */ | |
803 s->t4_t6_rx.its_black = s->t4_t6_rx.a_cursor & 1; | |
804 s->t4_t6_rx.black_white = 2; | |
805 break; | |
806 case S_Vert: | |
807 STATE_TRACE("Vert[%d] %d %d %d %d\n", | |
808 t4_2d_table[bits].param, | |
809 s->image_width, | |
810 s->t4_t6_rx.a0, | |
811 s->t4_t6_rx.b1, | |
812 s->t4_t6_rx.run_length); | |
813 s->t4_t6_rx.run_length += (s->t4_t6_rx.b1 - s->t4_t6_rx.a0 + t4_2d_table[bits].param); | |
814 s->t4_t6_rx.a0 = s->t4_t6_rx.b1 + t4_2d_table[bits].param; | |
815 add_run_to_row(s); | |
816 /* We need to move one step in one direction or the other, to change to the | |
817 opposite colour */ | |
818 if (t4_2d_table[bits].param >= 0) | |
819 { | |
820 s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; | |
821 } | |
822 else | |
823 { | |
824 if (s->t4_t6_rx.b_cursor) | |
825 s->t4_t6_rx.b1 -= s->ref_runs[--s->t4_t6_rx.b_cursor]; | |
826 } | |
827 break; | |
828 case S_Pass: | |
829 STATE_TRACE("Pass %d %d %d %d %d\n", | |
830 s->image_width, | |
831 s->t4_t6_rx.a0, | |
832 s->t4_t6_rx.b1, | |
833 s->ref_runs[s->t4_t6_rx.b_cursor], | |
834 s->ref_runs[s->t4_t6_rx.b_cursor + 1]); | |
835 s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; | |
836 s->t4_t6_rx.run_length += (s->t4_t6_rx.b1 - s->t4_t6_rx.a0); | |
837 s->t4_t6_rx.a0 = s->t4_t6_rx.b1; | |
838 s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; | |
839 break; | |
840 case S_Ext: | |
841 /* We do not currently handle any kind of extension */ | |
842 STATE_TRACE("Ext %d %d %d 0x%x\n", | |
843 s->image_width, | |
844 s->t4_t6_rx.a0, | |
845 ((s->t4_t6_rx.rx_bitstream >> t4_2d_table[bits].width) & 0x7), | |
846 s->t4_t6_rx.rx_bitstream); | |
847 /* TODO: The uncompressed option should be implemented. */ | |
848 break; | |
849 case S_Null: | |
850 STATE_TRACE("Null\n"); | |
851 break; | |
852 default: | |
853 STATE_TRACE("Unexpected T.4 state\n"); | |
854 span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected T.4 state %d\n", t4_2d_table[bits].state); | |
855 break; | |
856 } | |
857 drop_rx_bits(s, t4_2d_table[bits].width); | |
858 } | |
859 else | |
860 { | |
861 if (s->t4_t6_rx.its_black) | |
862 { | |
863 bits = s->t4_t6_rx.rx_bitstream & 0x1FFF; | |
864 STATE_TRACE("State %d, %d - Black %d %d %d\n", | |
865 t4_1d_black_table[bits].state, | |
866 t4_1d_black_table[bits].width, | |
867 s->image_width, | |
868 s->t4_t6_rx.a0, | |
869 t4_1d_black_table[bits].param); | |
870 switch (t4_1d_black_table[bits].state) | |
871 { | |
872 case S_MakeUpB: | |
873 case S_MakeUp: | |
874 s->t4_t6_rx.run_length += t4_1d_black_table[bits].param; | |
875 s->t4_t6_rx.a0 += t4_1d_black_table[bits].param; | |
876 break; | |
877 case S_TermB: | |
878 s->t4_t6_rx.its_black = FALSE; | |
879 if (s->row_len < s->image_width) | |
880 { | |
881 s->t4_t6_rx.run_length += t4_1d_black_table[bits].param; | |
882 s->t4_t6_rx.a0 += t4_1d_black_table[bits].param; | |
883 add_run_to_row(s); | |
884 } | |
885 if (s->t4_t6_rx.black_white) | |
886 s->t4_t6_rx.black_white--; | |
887 break; | |
888 default: | |
889 /* Bad black */ | |
890 s->t4_t6_rx.black_white = 0; | |
891 break; | |
892 } | |
893 drop_rx_bits(s, t4_1d_black_table[bits].width); | |
894 } | |
895 else | |
896 { | |
897 bits = s->t4_t6_rx.rx_bitstream & 0xFFF; | |
898 STATE_TRACE("State %d, %d - White %d %d %d\n", | |
899 t4_1d_white_table[bits].state, | |
900 t4_1d_white_table[bits].width, | |
901 s->image_width, | |
902 s->t4_t6_rx.a0, | |
903 t4_1d_white_table[bits].param); | |
904 switch (t4_1d_white_table[bits].state) | |
905 { | |
906 case S_MakeUpW: | |
907 case S_MakeUp: | |
908 s->t4_t6_rx.run_length += t4_1d_white_table[bits].param; | |
909 s->t4_t6_rx.a0 += t4_1d_white_table[bits].param; | |
910 break; | |
911 case S_TermW: | |
912 s->t4_t6_rx.its_black = TRUE; | |
913 if (s->row_len < s->image_width) | |
914 { | |
915 s->t4_t6_rx.run_length += t4_1d_white_table[bits].param; | |
916 s->t4_t6_rx.a0 += t4_1d_white_table[bits].param; | |
917 add_run_to_row(s); | |
918 } | |
919 if (s->t4_t6_rx.black_white) | |
920 s->t4_t6_rx.black_white--; | |
921 break; | |
922 default: | |
923 /* Bad white */ | |
924 s->t4_t6_rx.black_white = 0; | |
925 break; | |
926 } | |
927 drop_rx_bits(s, t4_1d_white_table[bits].width); | |
928 } | |
929 } | |
930 if (s->t4_t6_rx.a0 >= s->image_width) | |
931 s->t4_t6_rx.a0 = s->image_width - 1; | |
932 | |
933 if (s->line_encoding == T4_COMPRESSION_ITU_T6) | |
934 { | |
935 /* T.6 has no EOL markers. We sense the end of a line by its length alone. */ | |
936 /* The last test here is a backstop protection, so a corrupt image cannot | |
937 cause us to do bad things. Bad encoders have actually been seen, which | |
938 demand such protection. */ | |
939 if (s->t4_t6_rx.black_white == 0 && s->row_len >= s->image_width) | |
940 { | |
941 STATE_TRACE("EOL T.6\n"); | |
942 if (s->t4_t6_rx.run_length > 0) | |
943 add_run_to_row(s); | |
944 update_row_bit_info(s); | |
945 if (put_decoded_row(s)) | |
946 return TRUE; | |
947 s->t4_t6_rx.its_black = FALSE; | |
948 s->t4_t6_rx.black_white = 0; | |
949 s->t4_t6_rx.run_length = 0; | |
950 s->row_len = 0; | |
951 } | |
952 } | |
953 } | |
954 return FALSE; | |
955 } | |
956 /*- End of function --------------------------------------------------------*/ | |
957 | |
958 SPAN_DECLARE(int) t4_rx_put_bit(t4_state_t *s, int bit) | |
959 { | |
960 return rx_put_bits(s, bit & 1, 1); | |
961 } | |
962 /*- End of function --------------------------------------------------------*/ | |
963 | |
964 SPAN_DECLARE(int) t4_rx_put_byte(t4_state_t *s, uint8_t byte) | |
965 { | |
966 return rx_put_bits(s, byte & 0xFF, 8); | |
967 } | |
968 /*- End of function --------------------------------------------------------*/ | |
969 | |
970 SPAN_DECLARE(int) t4_rx_put_chunk(t4_state_t *s, const uint8_t buf[], int len) | |
971 { | |
972 int i; | |
973 uint8_t byte; | |
974 | |
975 for (i = 0; i < len; i++) | |
976 { | |
977 byte = buf[i]; | |
978 if (rx_put_bits(s, byte & 0xFF, 8)) | |
979 return TRUE; | |
980 } | |
981 return FALSE; | |
982 } | |
983 /*- End of function --------------------------------------------------------*/ | |
984 | |
985 SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_state_t *s, t4_row_write_handler_t handler, void *user_data) | |
986 { | |
987 s->t4_t6_rx.row_write_handler = handler; | |
988 s->t4_t6_rx.row_write_user_data = user_data; | |
989 return 0; | |
990 } | |
991 /*- End of function --------------------------------------------------------*/ | |
992 | |
993 SPAN_DECLARE(t4_state_t *) t4_rx_init(t4_state_t *s, const char *file, int output_encoding) | |
994 { | |
995 if (s == NULL) | |
996 { | |
997 if ((s = (t4_state_t *) malloc(sizeof(*s))) == NULL) | |
998 return NULL; | |
999 } | |
1000 memset(s, 0, sizeof(*s)); | |
1001 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
1002 span_log_set_protocol(&s->logging, "T.4"); | |
1003 s->rx = TRUE; | |
1004 | |
1005 span_log(&s->logging, SPAN_LOG_FLOW, "Start rx document\n"); | |
1006 | |
1007 if (open_tiff_output_file(s, file) < 0) | |
1008 return NULL; | |
1009 | |
1010 /* Save the file name for logging reports. */ | |
1011 s->tiff.file = strdup(file); | |
1012 /* Only provide for one form of coding throughout the file, even though the | |
1013 coding on the wire could change between pages. */ | |
1014 switch (output_encoding) | |
1015 { | |
1016 case T4_COMPRESSION_ITU_T4_1D: | |
1017 s->tiff.output_compression = COMPRESSION_CCITT_T4; | |
1018 s->tiff.output_t4_options = GROUP3OPT_FILLBITS; | |
1019 break; | |
1020 case T4_COMPRESSION_ITU_T4_2D: | |
1021 s->tiff.output_compression = COMPRESSION_CCITT_T4; | |
1022 s->tiff.output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; | |
1023 break; | |
1024 case T4_COMPRESSION_ITU_T6: | |
1025 s->tiff.output_compression = COMPRESSION_CCITT_T6; | |
1026 s->tiff.output_t4_options = 0; | |
1027 break; | |
1028 } | |
1029 | |
1030 /* Until we have a valid figure for the bytes per row, we need it to be set to a suitable | |
1031 value to ensure it will be seen as changing when the real value is used. */ | |
1032 s->bytes_per_row = 0; | |
1033 | |
1034 s->current_page = 0; | |
1035 s->tiff.pages_in_file = 0; | |
1036 s->tiff.start_page = 0; | |
1037 s->tiff.stop_page = INT_MAX; | |
1038 | |
1039 s->image_buffer = NULL; | |
1040 s->image_buffer_size = 0; | |
1041 | |
1042 /* Set some default values */ | |
1043 s->x_resolution = T4_X_RESOLUTION_R8; | |
1044 s->y_resolution = T4_Y_RESOLUTION_FINE; | |
1045 s->image_width = T4_WIDTH_R8_A4; | |
1046 | |
1047 return s; | |
1048 } | |
1049 /*- End of function --------------------------------------------------------*/ | |
1050 | |
1051 SPAN_DECLARE(int) t4_rx_start_page(t4_state_t *s) | |
1052 { | |
1053 int bytes_per_row; | |
1054 int run_space; | |
1055 uint32_t *bufptr; | |
1056 | |
1057 span_log(&s->logging, SPAN_LOG_FLOW, "Start rx page - compression %d\n", s->line_encoding); | |
1058 if (s->tiff.tiff_file == NULL) | |
1059 return -1; | |
1060 | |
1061 /* Calculate the scanline/tile width. */ | |
1062 bytes_per_row = (s->image_width + 7)/8; | |
1063 run_space = (s->image_width + 4)*sizeof(uint32_t); | |
1064 if (bytes_per_row != s->bytes_per_row) | |
1065 { | |
1066 /* Allocate the space required for decoding the new row length. */ | |
1067 s->bytes_per_row = bytes_per_row; | |
1068 if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL) | |
1069 return -1; | |
1070 s->cur_runs = bufptr; | |
1071 if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL) | |
1072 return -1; | |
1073 s->ref_runs = bufptr; | |
1074 } | |
1075 memset(s->cur_runs, 0, run_space); | |
1076 memset(s->ref_runs, 0, run_space); | |
1077 | |
1078 s->t4_t6_rx.rx_bits = 0; | |
1079 s->t4_t6_rx.rx_skip_bits = 0; | |
1080 s->t4_t6_rx.rx_bitstream = 0; | |
1081 s->row_bits = 0; | |
1082 s->min_row_bits = INT_MAX; | |
1083 s->max_row_bits = 0; | |
1084 | |
1085 s->row_is_2d = (s->line_encoding == T4_COMPRESSION_ITU_T6); | |
1086 /* We start at -1 EOLs for 1D and 2D decoding, as an indication we are waiting for the | |
1087 first EOL. T.6 coding starts without any preamble. */ | |
1088 s->t4_t6_rx.consecutive_eols = (s->line_encoding == T4_COMPRESSION_ITU_T6) ? 0 : -1; | |
1089 | |
1090 s->t4_t6_rx.bad_rows = 0; | |
1091 s->t4_t6_rx.longest_bad_row_run = 0; | |
1092 s->t4_t6_rx.curr_bad_row_run = 0; | |
1093 s->image_length = 0; | |
1094 s->tx_bitstream = 0; | |
1095 s->tx_bits = 8; | |
1096 s->image_size = 0; | |
1097 s->line_image_size = 0; | |
1098 s->t4_t6_rx.last_row_starts_at = 0; | |
1099 | |
1100 s->row_len = 0; | |
1101 s->t4_t6_rx.its_black = FALSE; | |
1102 s->t4_t6_rx.black_white = 0; | |
1103 | |
1104 /* Initialise the reference line to all white */ | |
1105 s->ref_runs[0] = | |
1106 s->ref_runs[1] = | |
1107 s->ref_runs[2] = | |
1108 s->ref_runs[3] = s->image_width; | |
1109 | |
1110 s->t4_t6_rx.b_cursor = 1; | |
1111 s->t4_t6_rx.a_cursor = 0; | |
1112 s->t4_t6_rx.b1 = s->ref_runs[0]; | |
1113 s->t4_t6_rx.a0 = 0; | |
1114 | |
1115 s->t4_t6_rx.run_length = 0; | |
1116 | |
1117 time (&s->page_start_time); | |
1118 | |
1119 return 0; | |
1120 } | |
1121 /*- End of function --------------------------------------------------------*/ | |
1122 | |
1123 SPAN_DECLARE(int) t4_rx_release(t4_state_t *s) | |
1124 { | |
1125 if (!s->rx) | |
1126 return -1; | |
1127 if (s->tiff.tiff_file) | |
1128 close_tiff_output_file(s); | |
1129 free_buffers(s); | |
1130 return 0; | |
1131 } | |
1132 /*- End of function --------------------------------------------------------*/ | |
1133 | |
1134 SPAN_DECLARE(int) t4_rx_free(t4_state_t *s) | |
1135 { | |
1136 int ret; | |
1137 | |
1138 ret = t4_rx_release(s); | |
1139 free(s); | |
1140 return ret; | |
1141 } | |
1142 /*- End of function --------------------------------------------------------*/ | |
1143 | |
1144 SPAN_DECLARE(void) t4_rx_set_rx_encoding(t4_state_t *s, int encoding) | |
1145 { | |
1146 s->line_encoding = encoding; | |
1147 } | |
1148 /*- End of function --------------------------------------------------------*/ | |
1149 | |
1150 SPAN_DECLARE(void) t4_rx_set_image_width(t4_state_t *s, int width) | |
1151 { | |
1152 s->image_width = width; | |
1153 } | |
1154 /*- End of function --------------------------------------------------------*/ | |
1155 | |
1156 SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_state_t *s, int resolution) | |
1157 { | |
1158 s->y_resolution = resolution; | |
1159 } | |
1160 /*- End of function --------------------------------------------------------*/ | |
1161 | |
1162 SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_state_t *s, int resolution) | |
1163 { | |
1164 s->x_resolution = resolution; | |
1165 } | |
1166 /*- End of function --------------------------------------------------------*/ | |
1167 | |
1168 SPAN_DECLARE(void) t4_rx_set_dcs(t4_state_t *s, const char *dcs) | |
1169 { | |
1170 s->tiff.dcs = (dcs && dcs[0]) ? dcs : NULL; | |
1171 } | |
1172 /*- End of function --------------------------------------------------------*/ | |
1173 | |
1174 SPAN_DECLARE(void) t4_rx_set_sub_address(t4_state_t *s, const char *sub_address) | |
1175 { | |
1176 s->tiff.sub_address = (sub_address && sub_address[0]) ? sub_address : NULL; | |
1177 } | |
1178 /*- End of function --------------------------------------------------------*/ | |
1179 | |
1180 SPAN_DECLARE(void) t4_rx_set_far_ident(t4_state_t *s, const char *ident) | |
1181 { | |
1182 s->tiff.far_ident = (ident && ident[0]) ? ident : NULL; | |
1183 } | |
1184 /*- End of function --------------------------------------------------------*/ | |
1185 | |
1186 SPAN_DECLARE(void) t4_rx_set_vendor(t4_state_t *s, const char *vendor) | |
1187 { | |
1188 s->tiff.vendor = vendor; | |
1189 } | |
1190 /*- End of function --------------------------------------------------------*/ | |
1191 | |
1192 SPAN_DECLARE(void) t4_rx_set_model(t4_state_t *s, const char *model) | |
1193 { | |
1194 s->tiff.model = model; | |
1195 } | |
1196 /*- End of function --------------------------------------------------------*/ | |
1197 | |
1198 SPAN_DECLARE(void) t4_get_transfer_statistics(t4_state_t *s, t4_stats_t *t) | |
1199 { | |
1200 t->pages_transferred = s->current_page - s->tiff.start_page; | |
1201 t->pages_in_file = s->tiff.pages_in_file; | |
1202 t->width = s->image_width; | |
1203 t->length = s->image_length; | |
1204 t->bad_rows = s->t4_t6_rx.bad_rows; | |
1205 t->longest_bad_row_run = s->t4_t6_rx.longest_bad_row_run; | |
1206 t->x_resolution = s->x_resolution; | |
1207 t->y_resolution = s->y_resolution; | |
1208 t->encoding = s->line_encoding; | |
1209 t->line_image_size = s->line_image_size/8; | |
1210 } | |
1211 /*- End of function --------------------------------------------------------*/ | |
1212 | |
1213 SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding) | |
1214 { | |
1215 switch (encoding) | |
1216 { | |
1217 case T4_COMPRESSION_ITU_T4_1D: | |
1218 return "T.4 1-D"; | |
1219 case T4_COMPRESSION_ITU_T4_2D: | |
1220 return "T.4 2-D"; | |
1221 case T4_COMPRESSION_ITU_T6: | |
1222 return "T.6"; | |
1223 } | |
1224 return "???"; | |
1225 } | |
1226 /*- End of function --------------------------------------------------------*/ | |
1227 /*- End of file ------------------------------------------------------------*/ |