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 ------------------------------------------------------------*/ |
