Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/t4_tx.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_tx.c - ITU T.4 FAX transmit 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_tx.c,v 1.13.2.9 2009/12/21 17:18:40 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 | |
56 /*! \file */ | |
57 | |
58 #if defined(HAVE_CONFIG_H) | |
59 #include "config.h" | |
60 #endif | |
61 | |
62 #include <stdlib.h> | |
63 #include <inttypes.h> | |
64 #include <limits.h> | |
65 #include <stdio.h> | |
66 #include <fcntl.h> | |
67 #include <unistd.h> | |
68 #include <time.h> | |
69 #include <memory.h> | |
70 #include <string.h> | |
71 #if defined(HAVE_TGMATH_H) | |
72 #include <tgmath.h> | |
73 #endif | |
74 #if defined(HAVE_MATH_H) | |
75 #include <math.h> | |
76 #endif | |
77 #include "floating_fudge.h" | |
78 #include <tiffio.h> | |
79 | |
80 #include "spandsp/telephony.h" | |
81 #include "spandsp/logging.h" | |
82 #include "spandsp/bit_operations.h" | |
83 #include "spandsp/async.h" | |
84 #include "spandsp/t4_rx.h" | |
85 #include "spandsp/t4_tx.h" | |
86 #include "spandsp/version.h" | |
87 | |
88 #include "spandsp/private/logging.h" | |
89 #include "spandsp/private/t4_rx.h" | |
90 #include "spandsp/private/t4_tx.h" | |
91 | |
92 /*! The number of centimetres in one inch */ | |
93 #define CM_PER_INCH 2.54f | |
94 | |
95 /*! The number of EOLs to be sent at the end of a T.4 page */ | |
96 #define EOLS_TO_END_T4_TX_PAGE 6 | |
97 /*! The number of EOLs to be sent at the end of a T.6 page */ | |
98 #define EOLS_TO_END_T6_TX_PAGE 2 | |
99 | |
100 #if defined(T4_STATE_DEBUGGING) | |
101 static void STATE_TRACE(const char *format, ...) | |
102 { | |
103 va_list arg_ptr; | |
104 | |
105 va_start(arg_ptr, format); | |
106 vprintf(format, arg_ptr); | |
107 va_end(arg_ptr); | |
108 } | |
109 /*- End of function --------------------------------------------------------*/ | |
110 #else | |
111 #define STATE_TRACE(...) /**/ | |
112 #endif | |
113 | |
114 /*! T.4 run length table entry */ | |
115 typedef struct | |
116 { | |
117 /*! Length of T.4 code, in bits */ | |
118 uint16_t length; | |
119 /*! T.4 code */ | |
120 uint16_t code; | |
121 /*! Run length, in bits */ | |
122 int16_t run_length; | |
123 } t4_run_table_entry_t; | |
124 | |
125 #include "faxfont.h" | |
126 | |
127 /* Legitimate runs of zero bits which are the tail end of one code | |
128 plus the start of the next code do not exceed 10 bits. */ | |
129 | |
130 /* | |
131 * Note that these tables are ordered such that the index into the table | |
132 * is known to be either the run length, or (run length / 64) + a fixed | |
133 * offset. | |
134 */ | |
135 static const t4_run_table_entry_t t4_white_codes[] = | |
136 { | |
137 { 8, 0x00AC, 0}, /* 0011 0101 */ | |
138 { 6, 0x0038, 1}, /* 0001 11 */ | |
139 { 4, 0x000E, 2}, /* 0111 */ | |
140 { 4, 0x0001, 3}, /* 1000 */ | |
141 { 4, 0x000D, 4}, /* 1011 */ | |
142 { 4, 0x0003, 5}, /* 1100 */ | |
143 { 4, 0x0007, 6}, /* 1110 */ | |
144 { 4, 0x000F, 7}, /* 1111 */ | |
145 { 5, 0x0019, 8}, /* 1001 1 */ | |
146 { 5, 0x0005, 9}, /* 1010 0 */ | |
147 { 5, 0x001C, 10}, /* 0011 1 */ | |
148 { 5, 0x0002, 11}, /* 0100 0 */ | |
149 { 6, 0x0004, 12}, /* 0010 00 */ | |
150 { 6, 0x0030, 13}, /* 0000 11 */ | |
151 { 6, 0x000B, 14}, /* 1101 00 */ | |
152 { 6, 0x002B, 15}, /* 1101 01 */ | |
153 { 6, 0x0015, 16}, /* 1010 10 */ | |
154 { 6, 0x0035, 17}, /* 1010 11 */ | |
155 { 7, 0x0072, 18}, /* 0100 111 */ | |
156 { 7, 0x0018, 19}, /* 0001 100 */ | |
157 { 7, 0x0008, 20}, /* 0001 000 */ | |
158 { 7, 0x0074, 21}, /* 0010 111 */ | |
159 { 7, 0x0060, 22}, /* 0000 011 */ | |
160 { 7, 0x0010, 23}, /* 0000 100 */ | |
161 { 7, 0x000A, 24}, /* 0101 000 */ | |
162 { 7, 0x006A, 25}, /* 0101 011 */ | |
163 { 7, 0x0064, 26}, /* 0010 011 */ | |
164 { 7, 0x0012, 27}, /* 0100 100 */ | |
165 { 7, 0x000C, 28}, /* 0011 000 */ | |
166 { 8, 0x0040, 29}, /* 0000 0010 */ | |
167 { 8, 0x00C0, 30}, /* 0000 0011 */ | |
168 { 8, 0x0058, 31}, /* 0001 1010 */ | |
169 { 8, 0x00D8, 32}, /* 0001 1011 */ | |
170 { 8, 0x0048, 33}, /* 0001 0010 */ | |
171 { 8, 0x00C8, 34}, /* 0001 0011 */ | |
172 { 8, 0x0028, 35}, /* 0001 0100 */ | |
173 { 8, 0x00A8, 36}, /* 0001 0101 */ | |
174 { 8, 0x0068, 37}, /* 0001 0110 */ | |
175 { 8, 0x00E8, 38}, /* 0001 0111 */ | |
176 { 8, 0x0014, 39}, /* 0010 1000 */ | |
177 { 8, 0x0094, 40}, /* 0010 1001 */ | |
178 { 8, 0x0054, 41}, /* 0010 1010 */ | |
179 { 8, 0x00D4, 42}, /* 0010 1011 */ | |
180 { 8, 0x0034, 43}, /* 0010 1100 */ | |
181 { 8, 0x00B4, 44}, /* 0010 1101 */ | |
182 { 8, 0x0020, 45}, /* 0000 0100 */ | |
183 { 8, 0x00A0, 46}, /* 0000 0101 */ | |
184 { 8, 0x0050, 47}, /* 0000 1010 */ | |
185 { 8, 0x00D0, 48}, /* 0000 1011 */ | |
186 { 8, 0x004A, 49}, /* 0101 0010 */ | |
187 { 8, 0x00CA, 50}, /* 0101 0011 */ | |
188 { 8, 0x002A, 51}, /* 0101 0100 */ | |
189 { 8, 0x00AA, 52}, /* 0101 0101 */ | |
190 { 8, 0x0024, 53}, /* 0010 0100 */ | |
191 { 8, 0x00A4, 54}, /* 0010 0101 */ | |
192 { 8, 0x001A, 55}, /* 0101 1000 */ | |
193 { 8, 0x009A, 56}, /* 0101 1001 */ | |
194 { 8, 0x005A, 57}, /* 0101 1010 */ | |
195 { 8, 0x00DA, 58}, /* 0101 1011 */ | |
196 { 8, 0x0052, 59}, /* 0100 1010 */ | |
197 { 8, 0x00D2, 60}, /* 0100 1011 */ | |
198 { 8, 0x004C, 61}, /* 0011 0010 */ | |
199 { 8, 0x00CC, 62}, /* 0011 0011 */ | |
200 { 8, 0x002C, 63}, /* 0011 0100 */ | |
201 { 5, 0x001B, 64}, /* 1101 1 */ | |
202 { 5, 0x0009, 128}, /* 1001 0 */ | |
203 { 6, 0x003A, 192}, /* 0101 11 */ | |
204 { 7, 0x0076, 256}, /* 0110 111 */ | |
205 { 8, 0x006C, 320}, /* 0011 0110 */ | |
206 { 8, 0x00EC, 384}, /* 0011 0111 */ | |
207 { 8, 0x0026, 448}, /* 0110 0100 */ | |
208 { 8, 0x00A6, 512}, /* 0110 0101 */ | |
209 { 8, 0x0016, 576}, /* 0110 1000 */ | |
210 { 8, 0x00E6, 640}, /* 0110 0111 */ | |
211 { 9, 0x0066, 704}, /* 0110 0110 0 */ | |
212 { 9, 0x0166, 768}, /* 0110 0110 1 */ | |
213 { 9, 0x0096, 832}, /* 0110 1001 0 */ | |
214 { 9, 0x0196, 896}, /* 0110 1001 1 */ | |
215 { 9, 0x0056, 960}, /* 0110 1010 0 */ | |
216 { 9, 0x0156, 1024}, /* 0110 1010 1 */ | |
217 { 9, 0x00D6, 1088}, /* 0110 1011 0 */ | |
218 { 9, 0x01D6, 1152}, /* 0110 1011 1 */ | |
219 { 9, 0x0036, 1216}, /* 0110 1100 0 */ | |
220 { 9, 0x0136, 1280}, /* 0110 1100 1 */ | |
221 { 9, 0x00B6, 1344}, /* 0110 1101 0 */ | |
222 { 9, 0x01B6, 1408}, /* 0110 1101 1 */ | |
223 { 9, 0x0032, 1472}, /* 0100 1100 0 */ | |
224 { 9, 0x0132, 1536}, /* 0100 1100 1 */ | |
225 { 9, 0x00B2, 1600}, /* 0100 1101 0 */ | |
226 { 6, 0x0006, 1664}, /* 0110 00 */ | |
227 { 9, 0x01B2, 1728}, /* 0100 1101 1 */ | |
228 {11, 0x0080, 1792}, /* 0000 0001 000 */ | |
229 {11, 0x0180, 1856}, /* 0000 0001 100 */ | |
230 {11, 0x0580, 1920}, /* 0000 0001 101 */ | |
231 {12, 0x0480, 1984}, /* 0000 0001 0010 */ | |
232 {12, 0x0C80, 2048}, /* 0000 0001 0011 */ | |
233 {12, 0x0280, 2112}, /* 0000 0001 0100 */ | |
234 {12, 0x0A80, 2176}, /* 0000 0001 0101 */ | |
235 {12, 0x0680, 2240}, /* 0000 0001 0110 */ | |
236 {12, 0x0E80, 2304}, /* 0000 0001 0111 */ | |
237 {12, 0x0380, 2368}, /* 0000 0001 1100 */ | |
238 {12, 0x0B80, 2432}, /* 0000 0001 1101 */ | |
239 {12, 0x0780, 2496}, /* 0000 0001 1110 */ | |
240 {12, 0x0F80, 2560}, /* 0000 0001 1111 */ | |
241 }; | |
242 | |
243 static const t4_run_table_entry_t t4_black_codes[] = | |
244 { | |
245 {10, 0x03B0, 0}, /* 0000 1101 11 */ | |
246 { 3, 0x0002, 1}, /* 010 */ | |
247 { 2, 0x0003, 2}, /* 11 */ | |
248 { 2, 0x0001, 3}, /* 10 */ | |
249 { 3, 0x0006, 4}, /* 011 */ | |
250 { 4, 0x000C, 5}, /* 0011 */ | |
251 { 4, 0x0004, 6}, /* 0010 */ | |
252 { 5, 0x0018, 7}, /* 0001 1 */ | |
253 { 6, 0x0028, 8}, /* 0001 01 */ | |
254 { 6, 0x0008, 9}, /* 0001 00 */ | |
255 { 7, 0x0010, 10}, /* 0000 100 */ | |
256 { 7, 0x0050, 11}, /* 0000 101 */ | |
257 { 7, 0x0070, 12}, /* 0000 111 */ | |
258 { 8, 0x0020, 13}, /* 0000 0100 */ | |
259 { 8, 0x00E0, 14}, /* 0000 0111 */ | |
260 { 9, 0x0030, 15}, /* 0000 1100 0 */ | |
261 {10, 0x03A0, 16}, /* 0000 0101 11 */ | |
262 {10, 0x0060, 17}, /* 0000 0110 00 */ | |
263 {10, 0x0040, 18}, /* 0000 0010 00 */ | |
264 {11, 0x0730, 19}, /* 0000 1100 111 */ | |
265 {11, 0x00B0, 20}, /* 0000 1101 000 */ | |
266 {11, 0x01B0, 21}, /* 0000 1101 100 */ | |
267 {11, 0x0760, 22}, /* 0000 0110 111 */ | |
268 {11, 0x00A0, 23}, /* 0000 0101 000 */ | |
269 {11, 0x0740, 24}, /* 0000 0010 111 */ | |
270 {11, 0x00C0, 25}, /* 0000 0011 000 */ | |
271 {12, 0x0530, 26}, /* 0000 1100 1010 */ | |
272 {12, 0x0D30, 27}, /* 0000 1100 1011 */ | |
273 {12, 0x0330, 28}, /* 0000 1100 1100 */ | |
274 {12, 0x0B30, 29}, /* 0000 1100 1101 */ | |
275 {12, 0x0160, 30}, /* 0000 0110 1000 */ | |
276 {12, 0x0960, 31}, /* 0000 0110 1001 */ | |
277 {12, 0x0560, 32}, /* 0000 0110 1010 */ | |
278 {12, 0x0D60, 33}, /* 0000 0110 1011 */ | |
279 {12, 0x04B0, 34}, /* 0000 1101 0010 */ | |
280 {12, 0x0CB0, 35}, /* 0000 1101 0011 */ | |
281 {12, 0x02B0, 36}, /* 0000 1101 0100 */ | |
282 {12, 0x0AB0, 37}, /* 0000 1101 0101 */ | |
283 {12, 0x06B0, 38}, /* 0000 1101 0110 */ | |
284 {12, 0x0EB0, 39}, /* 0000 1101 0111 */ | |
285 {12, 0x0360, 40}, /* 0000 0110 1100 */ | |
286 {12, 0x0B60, 41}, /* 0000 0110 1101 */ | |
287 {12, 0x05B0, 42}, /* 0000 1101 1010 */ | |
288 {12, 0x0DB0, 43}, /* 0000 1101 1011 */ | |
289 {12, 0x02A0, 44}, /* 0000 0101 0100 */ | |
290 {12, 0x0AA0, 45}, /* 0000 0101 0101 */ | |
291 {12, 0x06A0, 46}, /* 0000 0101 0110 */ | |
292 {12, 0x0EA0, 47}, /* 0000 0101 0111 */ | |
293 {12, 0x0260, 48}, /* 0000 0110 0100 */ | |
294 {12, 0x0A60, 49}, /* 0000 0110 0101 */ | |
295 {12, 0x04A0, 50}, /* 0000 0101 0010 */ | |
296 {12, 0x0CA0, 51}, /* 0000 0101 0011 */ | |
297 {12, 0x0240, 52}, /* 0000 0010 0100 */ | |
298 {12, 0x0EC0, 53}, /* 0000 0011 0111 */ | |
299 {12, 0x01C0, 54}, /* 0000 0011 1000 */ | |
300 {12, 0x0E40, 55}, /* 0000 0010 0111 */ | |
301 {12, 0x0140, 56}, /* 0000 0010 1000 */ | |
302 {12, 0x01A0, 57}, /* 0000 0101 1000 */ | |
303 {12, 0x09A0, 58}, /* 0000 0101 1001 */ | |
304 {12, 0x0D40, 59}, /* 0000 0010 1011 */ | |
305 {12, 0x0340, 60}, /* 0000 0010 1100 */ | |
306 {12, 0x05A0, 61}, /* 0000 0101 1010 */ | |
307 {12, 0x0660, 62}, /* 0000 0110 0110 */ | |
308 {12, 0x0E60, 63}, /* 0000 0110 0111 */ | |
309 {10, 0x03C0, 64}, /* 0000 0011 11 */ | |
310 {12, 0x0130, 128}, /* 0000 1100 1000 */ | |
311 {12, 0x0930, 192}, /* 0000 1100 1001 */ | |
312 {12, 0x0DA0, 256}, /* 0000 0101 1011 */ | |
313 {12, 0x0CC0, 320}, /* 0000 0011 0011 */ | |
314 {12, 0x02C0, 384}, /* 0000 0011 0100 */ | |
315 {12, 0x0AC0, 448}, /* 0000 0011 0101 */ | |
316 {13, 0x06C0, 512}, /* 0000 0011 0110 0 */ | |
317 {13, 0x16C0, 576}, /* 0000 0011 0110 1 */ | |
318 {13, 0x0A40, 640}, /* 0000 0010 0101 0 */ | |
319 {13, 0x1A40, 704}, /* 0000 0010 0101 1 */ | |
320 {13, 0x0640, 768}, /* 0000 0010 0110 0 */ | |
321 {13, 0x1640, 832}, /* 0000 0010 0110 1 */ | |
322 {13, 0x09C0, 896}, /* 0000 0011 1001 0 */ | |
323 {13, 0x19C0, 960}, /* 0000 0011 1001 1 */ | |
324 {13, 0x05C0, 1024}, /* 0000 0011 1010 0 */ | |
325 {13, 0x15C0, 1088}, /* 0000 0011 1010 1 */ | |
326 {13, 0x0DC0, 1152}, /* 0000 0011 1011 0 */ | |
327 {13, 0x1DC0, 1216}, /* 0000 0011 1011 1 */ | |
328 {13, 0x0940, 1280}, /* 0000 0010 1001 0 */ | |
329 {13, 0x1940, 1344}, /* 0000 0010 1001 1 */ | |
330 {13, 0x0540, 1408}, /* 0000 0010 1010 0 */ | |
331 {13, 0x1540, 1472}, /* 0000 0010 1010 1 */ | |
332 {13, 0x0B40, 1536}, /* 0000 0010 1101 0 */ | |
333 {13, 0x1B40, 1600}, /* 0000 0010 1101 1 */ | |
334 {13, 0x04C0, 1664}, /* 0000 0011 0010 0 */ | |
335 {13, 0x14C0, 1728}, /* 0000 0011 0010 1 */ | |
336 {11, 0x0080, 1792}, /* 0000 0001 000 */ | |
337 {11, 0x0180, 1856}, /* 0000 0001 100 */ | |
338 {11, 0x0580, 1920}, /* 0000 0001 101 */ | |
339 {12, 0x0480, 1984}, /* 0000 0001 0010 */ | |
340 {12, 0x0C80, 2048}, /* 0000 0001 0011 */ | |
341 {12, 0x0280, 2112}, /* 0000 0001 0100 */ | |
342 {12, 0x0A80, 2176}, /* 0000 0001 0101 */ | |
343 {12, 0x0680, 2240}, /* 0000 0001 0110 */ | |
344 {12, 0x0E80, 2304}, /* 0000 0001 0111 */ | |
345 {12, 0x0380, 2368}, /* 0000 0001 1100 */ | |
346 {12, 0x0B80, 2432}, /* 0000 0001 1101 */ | |
347 {12, 0x0780, 2496}, /* 0000 0001 1110 */ | |
348 {12, 0x0F80, 2560}, /* 0000 0001 1111 */ | |
349 }; | |
350 | |
351 static int encode_row(t4_state_t *s); | |
352 | |
353 static void make_header(t4_state_t *s, char *header) | |
354 { | |
355 time_t now; | |
356 struct tm tm; | |
357 static const char *months[] = | |
358 { | |
359 "Jan", | |
360 "Feb", | |
361 "Mar", | |
362 "Apr", | |
363 "May", | |
364 "Jun", | |
365 "Jul", | |
366 "Aug", | |
367 "Sep", | |
368 "Oct", | |
369 "Nov", | |
370 "Dec" | |
371 }; | |
372 | |
373 time(&now); | |
374 tm = *localtime(&now); | |
375 snprintf(header, | |
376 132, | |
377 " %2d-%s-%d %02d:%02d %-50s %-21s p.%d", | |
378 tm.tm_mday, | |
379 months[tm.tm_mon], | |
380 tm.tm_year + 1900, | |
381 tm.tm_hour, | |
382 tm.tm_min, | |
383 s->t4_t6_tx.header_info, | |
384 s->tiff.local_ident, | |
385 s->current_page + 1); | |
386 } | |
387 /*- End of function --------------------------------------------------------*/ | |
388 | |
389 static int t4_tx_put_fax_header(t4_state_t *s) | |
390 { | |
391 int row; | |
392 int i; | |
393 int repeats; | |
394 int pattern; | |
395 int row_bufptr; | |
396 char *t; | |
397 char header[132 + 1]; | |
398 | |
399 /* Modify the resulting image to include a header line, typical of hardware FAX machines */ | |
400 make_header(s, header); | |
401 switch (s->y_resolution) | |
402 { | |
403 case T4_Y_RESOLUTION_1200: | |
404 repeats = 12; | |
405 break; | |
406 case T4_Y_RESOLUTION_800: | |
407 repeats = 8; | |
408 break; | |
409 case T4_Y_RESOLUTION_600: | |
410 repeats = 6; | |
411 break; | |
412 case T4_Y_RESOLUTION_SUPERFINE: | |
413 repeats = 4; | |
414 break; | |
415 case T4_Y_RESOLUTION_300: | |
416 repeats = 3; | |
417 break; | |
418 case T4_Y_RESOLUTION_FINE: | |
419 repeats = 2; | |
420 break; | |
421 default: | |
422 repeats = 1; | |
423 break; | |
424 } | |
425 for (row = 0; row < 16; row++) | |
426 { | |
427 t = header; | |
428 row_bufptr = 0; | |
429 for (t = header; *t && row_bufptr <= s->bytes_per_row - 2; t++) | |
430 { | |
431 pattern = header_font[(uint8_t) *t][row]; | |
432 s->row_buf[row_bufptr++] = (uint8_t) (pattern >> 8); | |
433 s->row_buf[row_bufptr++] = (uint8_t) (pattern & 0xFF); | |
434 } | |
435 for ( ; row_bufptr < s->bytes_per_row; ) | |
436 s->row_buf[row_bufptr++] = 0; | |
437 for (i = 0; i < repeats; i++) | |
438 { | |
439 if (encode_row(s)) | |
440 return -1; | |
441 } | |
442 } | |
443 return 0; | |
444 } | |
445 /*- End of function --------------------------------------------------------*/ | |
446 | |
447 static int test_resolution(int res_unit, float actual, float expected) | |
448 { | |
449 if (res_unit == RESUNIT_INCH) | |
450 actual *= 1.0f/CM_PER_INCH; | |
451 return (expected*0.95f <= actual && actual <= expected*1.05f); | |
452 } | |
453 /*- End of function --------------------------------------------------------*/ | |
454 | |
455 static int get_tiff_directory_info(t4_state_t *s) | |
456 { | |
457 static const struct | |
458 { | |
459 float resolution; | |
460 int code; | |
461 } x_res_table[] = | |
462 { | |
463 { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, | |
464 { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, | |
465 { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, | |
466 { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, | |
467 { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, | |
468 { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, | |
469 {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, | |
470 { -1.00f, -1} | |
471 }; | |
472 static const struct | |
473 { | |
474 float resolution; | |
475 int code; | |
476 int max_rows_to_next_1d_row; | |
477 } y_res_table[] = | |
478 { | |
479 { 38.50f, T4_Y_RESOLUTION_STANDARD, 2}, | |
480 { 77.00f, T4_Y_RESOLUTION_FINE, 4}, | |
481 { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300, 6}, | |
482 { 154.00f, T4_Y_RESOLUTION_SUPERFINE, 8}, | |
483 { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600, 12}, | |
484 { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800, 16}, | |
485 {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200, 24}, | |
486 { -1.00f, -1, -1} | |
487 }; | |
488 uint16_t res_unit; | |
489 uint16_t parm16; | |
490 uint32_t parm32; | |
491 float x_resolution; | |
492 float y_resolution; | |
493 int i; | |
494 t4_tiff_state_t *t; | |
495 | |
496 t = &s->tiff; | |
497 parm16 = 0; | |
498 TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &parm16); | |
499 if (parm16 != 1) | |
500 return -1; | |
501 TIFFGetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, &parm16); | |
502 if (parm16 != 1) | |
503 return -1; | |
504 parm32 = 0; | |
505 TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); | |
506 s->image_width = parm32; | |
507 s->bytes_per_row = (s->image_width + 7)/8; | |
508 parm32 = 0; | |
509 TIFFGetField(t->tiff_file, TIFFTAG_IMAGELENGTH, &parm32); | |
510 s->image_length = parm32; | |
511 x_resolution = 0.0f; | |
512 TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); | |
513 y_resolution = 0.0f; | |
514 TIFFGetField(t->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution); | |
515 res_unit = RESUNIT_INCH; | |
516 TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); | |
517 t->photo_metric = PHOTOMETRIC_MINISWHITE; | |
518 TIFFGetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, &t->photo_metric); | |
519 if (t->photo_metric != PHOTOMETRIC_MINISWHITE) | |
520 span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", t->file); | |
521 t->fill_order = FILLORDER_LSB2MSB; | |
522 #if 0 | |
523 TIFFGetField(t->tiff_file, TIFFTAG_FILLORDER, &t->fill_order); | |
524 if (t->fill_order != FILLORDER_LSB2MSB) | |
525 span_log(&s->logging, SPAN_LOG_FLOW, "%s: Fill order needs swapping.\n", t->file); | |
526 #endif | |
527 | |
528 /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the | |
529 precise value. The other value should be exact. */ | |
530 /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ | |
531 s->x_resolution = T4_X_RESOLUTION_R8; | |
532 for (i = 0; x_res_table[i].code > 0; i++) | |
533 { | |
534 if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) | |
535 { | |
536 s->x_resolution = x_res_table[i].code; | |
537 break; | |
538 } | |
539 } | |
540 | |
541 s->y_resolution = T4_Y_RESOLUTION_STANDARD; | |
542 s->t4_t6_tx.max_rows_to_next_1d_row = 2; | |
543 for (i = 0; y_res_table[i].code > 0; i++) | |
544 { | |
545 if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) | |
546 { | |
547 s->y_resolution = y_res_table[i].code; | |
548 s->t4_t6_tx.max_rows_to_next_1d_row = y_res_table[i].max_rows_to_next_1d_row; | |
549 break; | |
550 } | |
551 } | |
552 | |
553 return 0; | |
554 } | |
555 /*- End of function --------------------------------------------------------*/ | |
556 | |
557 static int test_tiff_directory_info(t4_state_t *s) | |
558 { | |
559 static const struct | |
560 { | |
561 float resolution; | |
562 int code; | |
563 } x_res_table[] = | |
564 { | |
565 { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, | |
566 { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, | |
567 { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, | |
568 { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, | |
569 { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, | |
570 { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, | |
571 {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, | |
572 { -1.00f, -1} | |
573 }; | |
574 static const struct | |
575 { | |
576 float resolution; | |
577 int code; | |
578 int max_rows_to_next_1d_row; | |
579 } y_res_table[] = | |
580 { | |
581 { 38.50f, T4_Y_RESOLUTION_STANDARD, 2}, | |
582 { 77.00f, T4_Y_RESOLUTION_FINE, 4}, | |
583 { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300, 6}, | |
584 { 154.00f, T4_Y_RESOLUTION_SUPERFINE, 8}, | |
585 { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600, 12}, | |
586 { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800, 16}, | |
587 {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200, 24}, | |
588 { -1.00f, -1, -1} | |
589 }; | |
590 uint16_t res_unit; | |
591 uint16_t parm16; | |
592 uint32_t parm32; | |
593 float x_resolution; | |
594 float y_resolution; | |
595 int i; | |
596 t4_tiff_state_t *t; | |
597 | |
598 t = &s->tiff; | |
599 parm16 = 0; | |
600 TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &parm16); | |
601 if (parm16 != 1) | |
602 return -1; | |
603 parm32 = 0; | |
604 TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); | |
605 if (s->image_width != (int) parm32) | |
606 return 1; | |
607 x_resolution = 0.0f; | |
608 TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); | |
609 y_resolution = 0.0f; | |
610 TIFFGetField(t->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution); | |
611 res_unit = RESUNIT_INCH; | |
612 TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); | |
613 | |
614 /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the | |
615 precise value. The other value should be exact. */ | |
616 /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ | |
617 for (i = 0; x_res_table[i].code > 0; i++) | |
618 { | |
619 if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) | |
620 break; | |
621 } | |
622 if (s->x_resolution != x_res_table[i].code) | |
623 return 1; | |
624 for (i = 0; y_res_table[i].code > 0; i++) | |
625 { | |
626 if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) | |
627 break; | |
628 } | |
629 if (s->y_resolution != y_res_table[i].code) | |
630 return 1; | |
631 return 0; | |
632 } | |
633 /*- End of function --------------------------------------------------------*/ | |
634 | |
635 static int get_tiff_total_pages(t4_state_t *s) | |
636 { | |
637 int max; | |
638 | |
639 /* Each page *should* contain the total number of pages, but can this be | |
640 trusted? Some files say 0. Actually searching for the last page is | |
641 more reliable. */ | |
642 max = 0; | |
643 while (TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) max)) | |
644 max++; | |
645 /* Back to the previous page */ | |
646 if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) | |
647 return -1; | |
648 return max; | |
649 } | |
650 /*- End of function --------------------------------------------------------*/ | |
651 | |
652 static int open_tiff_input_file(t4_state_t *s, const char *file) | |
653 { | |
654 if ((s->tiff.tiff_file = TIFFOpen(file, "r")) == NULL) | |
655 return -1; | |
656 return 0; | |
657 } | |
658 /*- End of function --------------------------------------------------------*/ | |
659 | |
660 static int read_tiff_image(t4_state_t *s) | |
661 { | |
662 int row; | |
663 int image_length; | |
664 int i; | |
665 | |
666 image_length = 0; | |
667 TIFFGetField(s->tiff.tiff_file, TIFFTAG_IMAGELENGTH, &image_length); | |
668 for (row = 0; row < image_length; row++) | |
669 { | |
670 if (TIFFReadScanline(s->tiff.tiff_file, s->row_buf, row, 0) <= 0) | |
671 { | |
672 span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error at row %d.\n", s->tiff.file, row); | |
673 break; | |
674 } | |
675 if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE) | |
676 { | |
677 for (i = 0; i < s->bytes_per_row; i++) | |
678 s->row_buf[i] = ~s->row_buf[i]; | |
679 } | |
680 if (s->tiff.fill_order != FILLORDER_LSB2MSB) | |
681 bit_reverse(s->row_buf, s->row_buf, s->bytes_per_row); | |
682 if (encode_row(s)) | |
683 return -1; | |
684 } | |
685 return image_length; | |
686 } | |
687 /*- End of function --------------------------------------------------------*/ | |
688 | |
689 static int close_tiff_input_file(t4_state_t *s) | |
690 { | |
691 TIFFClose(s->tiff.tiff_file); | |
692 s->tiff.tiff_file = NULL; | |
693 if (s->tiff.file) | |
694 free((char *) s->tiff.file); | |
695 s->tiff.file = NULL; | |
696 return 0; | |
697 } | |
698 /*- End of function --------------------------------------------------------*/ | |
699 | |
700 static void update_row_bit_info(t4_state_t *s) | |
701 { | |
702 if (s->row_bits > s->max_row_bits) | |
703 s->max_row_bits = s->row_bits; | |
704 if (s->row_bits < s->min_row_bits) | |
705 s->min_row_bits = s->row_bits; | |
706 s->row_bits = 0; | |
707 } | |
708 /*- End of function --------------------------------------------------------*/ | |
709 | |
710 static int free_buffers(t4_state_t *s) | |
711 { | |
712 if (s->image_buffer) | |
713 { | |
714 free(s->image_buffer); | |
715 s->image_buffer = NULL; | |
716 s->image_buffer_size = 0; | |
717 } | |
718 if (s->cur_runs) | |
719 { | |
720 free(s->cur_runs); | |
721 s->cur_runs = NULL; | |
722 } | |
723 if (s->ref_runs) | |
724 { | |
725 free(s->ref_runs); | |
726 s->ref_runs = NULL; | |
727 } | |
728 if (s->row_buf) | |
729 { | |
730 free(s->row_buf); | |
731 s->row_buf = NULL; | |
732 } | |
733 return 0; | |
734 } | |
735 /*- End of function --------------------------------------------------------*/ | |
736 | |
737 static int row_to_run_lengths(uint32_t list[], const uint8_t row[], int width) | |
738 { | |
739 uint32_t flip; | |
740 uint32_t x; | |
741 int span; | |
742 int entry; | |
743 int frag; | |
744 int rem; | |
745 int limit; | |
746 int i; | |
747 int pos; | |
748 | |
749 /* Deal with whole words first. We know we are starting on a word boundary. */ | |
750 entry = 0; | |
751 flip = 0; | |
752 limit = (width >> 3) & ~3; | |
753 span = 0; | |
754 pos = 0; | |
755 for (i = 0; i < limit; i += sizeof(uint32_t)) | |
756 { | |
757 x = *((uint32_t *) &row[i]); | |
758 if (x != flip) | |
759 { | |
760 x = ((uint32_t) row[i] << 24) | ((uint32_t) row[i + 1] << 16) | ((uint32_t) row[i + 2] << 8) | ((uint32_t) row[i + 3]); | |
761 /* We know we are going to find at least one transition. */ | |
762 frag = 31 - top_bit(x ^ flip); | |
763 pos += ((i << 3) - span + frag); | |
764 list[entry++] = pos; | |
765 x <<= frag; | |
766 flip ^= 0xFFFFFFFF; | |
767 rem = 32 - frag; | |
768 /* Now see if there are any more */ | |
769 while ((frag = 31 - top_bit(x ^ flip)) < rem) | |
770 { | |
771 pos += frag; | |
772 list[entry++] = pos; | |
773 x <<= frag; | |
774 flip ^= 0xFFFFFFFF; | |
775 rem -= frag; | |
776 } | |
777 /* Save the remainder of the word */ | |
778 span = (i << 3) + 32 - rem; | |
779 } | |
780 } | |
781 /* Now deal with some whole bytes, if there are any left. */ | |
782 limit = width >> 3; | |
783 flip &= 0xFF000000; | |
784 if (i < limit) | |
785 { | |
786 for ( ; i < limit; i++) | |
787 { | |
788 x = (uint32_t) row[i] << 24; | |
789 if (x != flip) | |
790 { | |
791 /* We know we are going to find at least one transition. */ | |
792 frag = 31 - top_bit(x ^ flip); | |
793 pos += ((i << 3) - span + frag); | |
794 list[entry++] = pos; | |
795 x <<= frag; | |
796 flip ^= 0xFF000000; | |
797 rem = 8 - frag; | |
798 /* Now see if there are any more */ | |
799 while ((frag = 31 - top_bit(x ^ flip)) < rem) | |
800 { | |
801 pos += frag; | |
802 list[entry++] = pos; | |
803 x <<= frag; | |
804 flip ^= 0xFF000000; | |
805 rem -= frag; | |
806 } | |
807 /* Save the remainder of the word */ | |
808 span = (i << 3) + 8 - rem; | |
809 } | |
810 } | |
811 } | |
812 /* Deal with any left over fractional byte. */ | |
813 span = (i << 3) - span; | |
814 if ((rem = width & 7)) | |
815 { | |
816 x = row[i]; | |
817 x <<= 24; | |
818 do | |
819 { | |
820 frag = 31 - top_bit(x ^ flip); | |
821 if (frag > rem) | |
822 frag = rem; | |
823 pos += (span + frag); | |
824 list[entry++] = pos; | |
825 x <<= frag; | |
826 span = 0; | |
827 flip ^= 0xFF000000; | |
828 rem -= frag; | |
829 } | |
830 while (rem > 0); | |
831 } | |
832 else | |
833 { | |
834 if (span) | |
835 { | |
836 pos += span; | |
837 list[entry++] = pos; | |
838 } | |
839 } | |
840 return entry; | |
841 } | |
842 /*- End of function --------------------------------------------------------*/ | |
843 | |
844 static __inline__ int put_encoded_bits(t4_state_t *s, uint32_t bits, int length) | |
845 { | |
846 uint8_t *t; | |
847 | |
848 /* We might be called with a large length value, to spew out a mass of zero bits for | |
849 minimum row length padding. */ | |
850 s->tx_bitstream |= (bits << s->tx_bits); | |
851 s->tx_bits += length; | |
852 s->row_bits += length; | |
853 if ((s->image_size + (s->tx_bits + 7)/8) >= s->image_buffer_size) | |
854 { | |
855 if ((t = realloc(s->image_buffer, s->image_buffer_size + 100*s->bytes_per_row)) == NULL) | |
856 return -1; | |
857 s->image_buffer = t; | |
858 s->image_buffer_size += 100*s->bytes_per_row; | |
859 } | |
860 while (s->tx_bits >= 8) | |
861 { | |
862 s->image_buffer[s->image_size++] = (uint8_t) (s->tx_bitstream & 0xFF); | |
863 s->tx_bitstream >>= 8; | |
864 s->tx_bits -= 8; | |
865 } | |
866 return 0; | |
867 } | |
868 /*- End of function --------------------------------------------------------*/ | |
869 | |
870 /* | |
871 * Write the sequence of codes that describes | |
872 * the specified span of zero's or one's. The | |
873 * appropriate table that holds the make-up and | |
874 * terminating codes is supplied. | |
875 */ | |
876 static __inline__ int put_1d_span(t4_state_t *s, int32_t span, const t4_run_table_entry_t *tab) | |
877 { | |
878 const t4_run_table_entry_t *te; | |
879 | |
880 te = &tab[63 + (2560 >> 6)]; | |
881 while (span >= 2560 + 64) | |
882 { | |
883 if (put_encoded_bits(s, te->code, te->length)) | |
884 return -1; | |
885 span -= te->run_length; | |
886 } | |
887 te = &tab[63 + (span >> 6)]; | |
888 if (span >= 64) | |
889 { | |
890 if (put_encoded_bits(s, te->code, te->length)) | |
891 return -1; | |
892 span -= te->run_length; | |
893 } | |
894 if (put_encoded_bits(s, tab[span].code, tab[span].length)) | |
895 return -1; | |
896 return 0; | |
897 } | |
898 /*- End of function --------------------------------------------------------*/ | |
899 | |
900 #define pixel_is_black(x,bit) (((x)[(bit) >> 3] << ((bit) & 7)) & 0x80) | |
901 | |
902 /* | |
903 * Write an EOL code to the output stream. We also handle writing the tag | |
904 * bit for the next scanline when doing 2D encoding. | |
905 */ | |
906 static void encode_eol(t4_state_t *s) | |
907 { | |
908 uint32_t code; | |
909 int length; | |
910 | |
911 if (s->line_encoding == T4_COMPRESSION_ITU_T4_2D) | |
912 { | |
913 code = 0x0800 | ((!s->row_is_2d) << 12); | |
914 length = 13; | |
915 } | |
916 else | |
917 { | |
918 /* T.4 1D EOL, or T.6 EOFB */ | |
919 code = 0x800; | |
920 length = 12; | |
921 } | |
922 if (s->row_bits) | |
923 { | |
924 /* We may need to pad the row to a minimum length, unless we are in T.6 mode. | |
925 In T.6 we only come here at the end of the page to add the EOFB marker, which | |
926 is like two 1D EOLs. */ | |
927 if (s->line_encoding != T4_COMPRESSION_ITU_T6) | |
928 { | |
929 if (s->row_bits + length < s->t4_t6_tx.min_bits_per_row) | |
930 put_encoded_bits(s, 0, s->t4_t6_tx.min_bits_per_row - (s->row_bits + length)); | |
931 } | |
932 put_encoded_bits(s, code, length); | |
933 update_row_bit_info(s); | |
934 } | |
935 else | |
936 { | |
937 /* We don't pad zero length rows. They are the consecutive EOLs which end a page. */ | |
938 put_encoded_bits(s, code, length); | |
939 /* Don't do the full update row bit info, or the minimum suddenly drops to the | |
940 length of an EOL. Just clear the row bits, so we treat the next EOL as an | |
941 end of page EOL, with no padding. */ | |
942 s->row_bits = 0; | |
943 } | |
944 } | |
945 /*- End of function --------------------------------------------------------*/ | |
946 | |
947 /* | |
948 * 2D-encode a row of pixels. Consult ITU specification T.4 for the algorithm. | |
949 */ | |
950 static void encode_2d_row(t4_state_t *s) | |
951 { | |
952 static const t4_run_table_entry_t codes[] = | |
953 { | |
954 { 7, 0x60, 0 }, /* VR3 0000 011 */ | |
955 { 6, 0x30, 0 }, /* VR2 0000 11 */ | |
956 { 3, 0x06, 0 }, /* VR1 011 */ | |
957 { 1, 0x01, 0 }, /* V0 1 */ | |
958 { 3, 0x02, 0 }, /* VL1 010 */ | |
959 { 6, 0x10, 0 }, /* VL2 0000 10 */ | |
960 { 7, 0x20, 0 }, /* VL3 0000 010 */ | |
961 { 3, 0x04, 0 }, /* horizontal 001 */ | |
962 { 4, 0x08, 0 } /* pass 0001 */ | |
963 }; | |
964 | |
965 /* The reference or starting changing element on the coding line. At the start of the coding | |
966 line, a0 is set on an imaginary white changing element situated just before the first element | |
967 on the line. During the coding of the coding line, the position of a0 is defined by the | |
968 previous coding mode. (See T.4/4.2.1.3.2.) */ | |
969 int a0; | |
970 /* The next changing element to the right of a0 on the coding line. */ | |
971 int a1; | |
972 /* The next changing element to the right of a1 on the coding line. */ | |
973 int a2; | |
974 /* The first changing element on the reference line to the right of a0 and of opposite colour to a0. */ | |
975 int b1; | |
976 /* The next changing element to the right of b1 on the reference line. */ | |
977 int b2; | |
978 int diff; | |
979 int a_cursor; | |
980 int b_cursor; | |
981 int cur_steps; | |
982 uint32_t *p; | |
983 | |
984 /* | |
985 b1 b2 | |
986 XX XX XX XX XX -- -- -- -- -- XX XX XX -- -- -- -- -- | |
987 XX XX XX -- -- -- -- -- XX XX XX XX XX XX -- -- -- -- | |
988 a0 a1 a2 | |
989 | |
990 | |
991 a) Pass mode | |
992 This mode is identified when the position of b2 lies to the left of a1. When this mode | |
993 has been coded, a0 is set on the element of the coding line below b2 in preparation for | |
994 the next coding (i.e. on a0'). | |
995 | |
996 b1 b2 | |
997 XX XX XX XX -- -- XX XX XX -- -- -- -- -- | |
998 XX XX -- -- -- -- -- -- -- -- -- -- XX XX | |
999 a0 a0' a1 | |
1000 Pass mode | |
1001 | |
1002 | |
1003 However, the state where b2 occurs just above a1, as shown in the figure below, is not | |
1004 considered as a pass mode. | |
1005 | |
1006 b1 b2 | |
1007 XX XX XX XX -- -- XX XX XX -- -- -- -- -- | |
1008 XX XX -- -- -- -- -- -- -- XX XX XX XX XX | |
1009 a0 a1 | |
1010 Not pass mode | |
1011 | |
1012 | |
1013 b) Vertical mode | |
1014 When this mode is identified, the position of a1 is coded relative to the position of b1. | |
1015 The relative distance a1b1 can take on one of seven values V(0), VR(1), VR(2), VR(3), | |
1016 VL(1), VL(2) and VL(3), each of which is represented by a separate code word. The | |
1017 subscripts R and L indicate that a1 is to the right or left respectively of b1, and the | |
1018 number in brackets indicates the value of the distance a1b1. After vertical mode coding | |
1019 has occurred, the position of a0 is set on a1 (see figure below). | |
1020 | |
1021 c) Horizontal mode | |
1022 When this mode is identified, both the run-lengths a0a1 and a1a2 are coded using the code | |
1023 words H + M(a0a1) + M(a1a2). H is the flag code word 001 taken from the two-dimensional | |
1024 code table. M(a0a1) and M(a1a2) are code words which represent the length and "colour" | |
1025 of the runs a0a1 and a1a2 respectively and are taken from the appropriate white or black | |
1026 one-dimensional code tables. After a horizontal mode coding, the position of a0 is set on | |
1027 a2 (see figure below). | |
1028 | |
1029 Vertical | |
1030 <a1 b1> | |
1031 b1 b2 | |
1032 -- XX XX XX XX XX -- -- -- -- -- -- -- -- XX XX XX XX -- -- -- | |
1033 -- -- -- -- -- -- -- -- -- -- -- -- XX XX XX XX XX XX XX -- -- | |
1034 a0 a1 a2 | |
1035 <-------- a0a1 --------><-------- a1a2 ------------> | |
1036 Horizontal mode | |
1037 Vertical and horizontal modes | |
1038 */ | |
1039 /* The following implements the 2-D encoding section of the flow chart in Figure7/T.4 */ | |
1040 cur_steps = row_to_run_lengths(s->cur_runs, s->row_buf, s->image_width); | |
1041 /* Stretch the row a little, so when we step by 2 we are guaranteed to | |
1042 hit an entry showing the row length */ | |
1043 s->cur_runs[cur_steps] = | |
1044 s->cur_runs[cur_steps + 1] = | |
1045 s->cur_runs[cur_steps + 2] = s->cur_runs[cur_steps - 1]; | |
1046 | |
1047 a0 = 0; | |
1048 a1 = s->cur_runs[0]; | |
1049 b1 = s->ref_runs[0]; | |
1050 a_cursor = 0; | |
1051 b_cursor = 0; | |
1052 for (;;) | |
1053 { | |
1054 b2 = s->ref_runs[b_cursor + 1]; | |
1055 if (b2 >= a1) | |
1056 { | |
1057 diff = b1 - a1; | |
1058 if (abs(diff) <= 3) | |
1059 { | |
1060 /* Vertical mode coding */ | |
1061 put_encoded_bits(s, codes[diff + 3].code, codes[diff + 3].length); | |
1062 a0 = a1; | |
1063 a_cursor++; | |
1064 } | |
1065 else | |
1066 { | |
1067 /* Horizontal mode coding */ | |
1068 a2 = s->cur_runs[a_cursor + 1]; | |
1069 put_encoded_bits(s, codes[7].code, codes[7].length); | |
1070 if (a0 + a1 == 0 || pixel_is_black(s->row_buf, a0) == 0) | |
1071 { | |
1072 put_1d_span(s, a1 - a0, t4_white_codes); | |
1073 put_1d_span(s, a2 - a1, t4_black_codes); | |
1074 } | |
1075 else | |
1076 { | |
1077 put_1d_span(s, a1 - a0, t4_black_codes); | |
1078 put_1d_span(s, a2 - a1, t4_white_codes); | |
1079 } | |
1080 a0 = a2; | |
1081 a_cursor += 2; | |
1082 } | |
1083 if (a0 >= s->image_width) | |
1084 break; | |
1085 if (a_cursor >= cur_steps) | |
1086 a_cursor = cur_steps - 1; | |
1087 a1 = s->cur_runs[a_cursor]; | |
1088 } | |
1089 else | |
1090 { | |
1091 /* Pass mode coding */ | |
1092 put_encoded_bits(s, codes[8].code, codes[8].length); | |
1093 /* We now set a0 to somewhere in the middle of its current run, | |
1094 but we know are aren't moving beyond that run. */ | |
1095 a0 = b2; | |
1096 if (a0 >= s->image_width) | |
1097 break; | |
1098 } | |
1099 /* We need to hunt for the correct position in the reference row, as the | |
1100 runs there have no particular alignment with the runs in the current | |
1101 row. */ | |
1102 if (pixel_is_black(s->row_buf, a0)) | |
1103 b_cursor |= 1; | |
1104 else | |
1105 b_cursor &= ~1; | |
1106 if (a0 < (int) s->ref_runs[b_cursor]) | |
1107 { | |
1108 for ( ; b_cursor >= 0; b_cursor -= 2) | |
1109 { | |
1110 if (a0 >= (int) s->ref_runs[b_cursor]) | |
1111 break; | |
1112 } | |
1113 b_cursor += 2; | |
1114 } | |
1115 else | |
1116 { | |
1117 for ( ; b_cursor < s->t4_t6_tx.ref_steps; b_cursor += 2) | |
1118 { | |
1119 if (a0 < (int) s->ref_runs[b_cursor]) | |
1120 break; | |
1121 } | |
1122 if (b_cursor >= s->t4_t6_tx.ref_steps) | |
1123 b_cursor = s->t4_t6_tx.ref_steps - 1; | |
1124 } | |
1125 b1 = s->ref_runs[b_cursor]; | |
1126 } | |
1127 /* Swap the buffers */ | |
1128 s->t4_t6_tx.ref_steps = cur_steps; | |
1129 p = s->cur_runs; | |
1130 s->cur_runs = s->ref_runs; | |
1131 s->ref_runs = p; | |
1132 } | |
1133 /*- End of function --------------------------------------------------------*/ | |
1134 | |
1135 /* | |
1136 * 1D-encode a row of pixels. The encoding is a sequence of all-white or | |
1137 * all-black spans of pixels encoded with Huffman codes. | |
1138 */ | |
1139 static void encode_1d_row(t4_state_t *s) | |
1140 { | |
1141 int i; | |
1142 | |
1143 /* Do our work in the reference row buffer, and it is already in place if | |
1144 we need a reference row for a following 2D encoded row. */ | |
1145 s->t4_t6_tx.ref_steps = row_to_run_lengths(s->ref_runs, s->row_buf, s->image_width); | |
1146 put_1d_span(s, s->ref_runs[0], t4_white_codes); | |
1147 for (i = 1; i < s->t4_t6_tx.ref_steps; i++) | |
1148 put_1d_span(s, s->ref_runs[i] - s->ref_runs[i - 1], (i & 1) ? t4_black_codes : t4_white_codes); | |
1149 /* Stretch the row a little, so when we step by 2 we are guaranteed to | |
1150 hit an entry showing the row length */ | |
1151 s->ref_runs[s->t4_t6_tx.ref_steps] = | |
1152 s->ref_runs[s->t4_t6_tx.ref_steps + 1] = | |
1153 s->ref_runs[s->t4_t6_tx.ref_steps + 2] = s->ref_runs[s->t4_t6_tx.ref_steps - 1]; | |
1154 } | |
1155 /*- End of function --------------------------------------------------------*/ | |
1156 | |
1157 static int encode_row(t4_state_t *s) | |
1158 { | |
1159 switch (s->line_encoding) | |
1160 { | |
1161 case T4_COMPRESSION_ITU_T6: | |
1162 /* T.6 compression is a trivial step up from T.4 2D, so we just | |
1163 throw it in here. T.6 is only used with error correction, | |
1164 so it does not need independantly compressed (i.e. 1D) lines | |
1165 to recover from data errors. It doesn't need EOLs, either. */ | |
1166 if (s->row_bits) | |
1167 update_row_bit_info(s); | |
1168 encode_2d_row(s); | |
1169 break; | |
1170 case T4_COMPRESSION_ITU_T4_2D: | |
1171 encode_eol(s); | |
1172 if (s->row_is_2d) | |
1173 { | |
1174 encode_2d_row(s); | |
1175 s->t4_t6_tx.rows_to_next_1d_row--; | |
1176 } | |
1177 else | |
1178 { | |
1179 encode_1d_row(s); | |
1180 s->row_is_2d = TRUE; | |
1181 } | |
1182 if (s->t4_t6_tx.rows_to_next_1d_row <= 0) | |
1183 { | |
1184 /* Insert a row of 1D encoding */ | |
1185 s->row_is_2d = FALSE; | |
1186 s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; | |
1187 } | |
1188 break; | |
1189 default: | |
1190 case T4_COMPRESSION_ITU_T4_1D: | |
1191 encode_eol(s); | |
1192 encode_1d_row(s); | |
1193 break; | |
1194 } | |
1195 s->row++; | |
1196 return 0; | |
1197 } | |
1198 /*- End of function --------------------------------------------------------*/ | |
1199 | |
1200 SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_state_t *s, t4_row_read_handler_t handler, void *user_data) | |
1201 { | |
1202 s->t4_t6_tx.row_read_handler = handler; | |
1203 s->t4_t6_tx.row_read_user_data = user_data; | |
1204 return 0; | |
1205 } | |
1206 /*- End of function --------------------------------------------------------*/ | |
1207 | |
1208 SPAN_DECLARE(t4_state_t *) t4_tx_init(t4_state_t *s, const char *file, int start_page, int stop_page) | |
1209 { | |
1210 int run_space; | |
1211 | |
1212 if (s == NULL) | |
1213 { | |
1214 if ((s = (t4_state_t *) malloc(sizeof(*s))) == NULL) | |
1215 return NULL; | |
1216 } | |
1217 memset(s, 0, sizeof(*s)); | |
1218 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
1219 span_log_set_protocol(&s->logging, "T.4"); | |
1220 s->rx = FALSE; | |
1221 | |
1222 span_log(&s->logging, SPAN_LOG_FLOW, "Start tx document\n"); | |
1223 | |
1224 if (open_tiff_input_file(s, file) < 0) | |
1225 return NULL; | |
1226 s->tiff.file = strdup(file); | |
1227 s->current_page = | |
1228 s->tiff.start_page = (start_page >= 0) ? start_page : 0; | |
1229 s->tiff.stop_page = (stop_page >= 0) ? stop_page : INT_MAX; | |
1230 | |
1231 if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) | |
1232 return NULL; | |
1233 if (get_tiff_directory_info(s)) | |
1234 { | |
1235 close_tiff_input_file(s); | |
1236 return NULL; | |
1237 } | |
1238 | |
1239 s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; | |
1240 | |
1241 s->tiff.pages_in_file = -1; | |
1242 | |
1243 run_space = (s->image_width + 4)*sizeof(uint32_t); | |
1244 if ((s->cur_runs = (uint32_t *) malloc(run_space)) == NULL) | |
1245 return NULL; | |
1246 if ((s->ref_runs = (uint32_t *) malloc(run_space)) == NULL) | |
1247 { | |
1248 free_buffers(s); | |
1249 close_tiff_input_file(s); | |
1250 return NULL; | |
1251 } | |
1252 if ((s->row_buf = malloc(s->bytes_per_row)) == NULL) | |
1253 { | |
1254 free_buffers(s); | |
1255 close_tiff_input_file(s); | |
1256 return NULL; | |
1257 } | |
1258 s->ref_runs[0] = | |
1259 s->ref_runs[1] = | |
1260 s->ref_runs[2] = | |
1261 s->ref_runs[3] = s->image_width; | |
1262 s->t4_t6_tx.ref_steps = 1; | |
1263 s->image_buffer_size = 0; | |
1264 return s; | |
1265 } | |
1266 /*- End of function --------------------------------------------------------*/ | |
1267 | |
1268 SPAN_DECLARE(int) t4_tx_start_page(t4_state_t *s) | |
1269 { | |
1270 int row; | |
1271 int i; | |
1272 int run_space; | |
1273 int len; | |
1274 int old_image_width; | |
1275 uint8_t *bufptr8; | |
1276 uint32_t *bufptr; | |
1277 | |
1278 span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d\n", s->current_page); | |
1279 if (s->current_page > s->tiff.stop_page) | |
1280 return -1; | |
1281 if (s->tiff.tiff_file == NULL) | |
1282 return -1; | |
1283 old_image_width = s->image_width; | |
1284 if (s->t4_t6_tx.row_read_handler == NULL) | |
1285 { | |
1286 #if defined(HAVE_LIBTIFF) | |
1287 if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) | |
1288 return -1; | |
1289 get_tiff_directory_info(s); | |
1290 #endif | |
1291 } | |
1292 s->image_size = 0; | |
1293 s->tx_bitstream = 0; | |
1294 s->tx_bits = 0; | |
1295 s->row_is_2d = (s->line_encoding == T4_COMPRESSION_ITU_T6); | |
1296 s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; | |
1297 | |
1298 /* Allow for pages being of different width. */ | |
1299 run_space = (s->image_width + 4)*sizeof(uint32_t); | |
1300 if (old_image_width != s->image_width) | |
1301 { | |
1302 s->bytes_per_row = (s->image_width + 7)/8; | |
1303 | |
1304 if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL) | |
1305 return -1; | |
1306 s->cur_runs = bufptr; | |
1307 if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL) | |
1308 return -1; | |
1309 s->ref_runs = bufptr; | |
1310 if ((bufptr8 = realloc(s->row_buf, s->bytes_per_row)) == NULL) | |
1311 return -1; | |
1312 s->row_buf = bufptr8; | |
1313 } | |
1314 s->ref_runs[0] = | |
1315 s->ref_runs[1] = | |
1316 s->ref_runs[2] = | |
1317 s->ref_runs[3] = s->image_width; | |
1318 s->t4_t6_tx.ref_steps = 1; | |
1319 | |
1320 s->row_bits = 0; | |
1321 s->min_row_bits = INT_MAX; | |
1322 s->max_row_bits = 0; | |
1323 | |
1324 if (s->t4_t6_tx.header_info && s->t4_t6_tx.header_info[0]) | |
1325 { | |
1326 if (t4_tx_put_fax_header(s)) | |
1327 return -1; | |
1328 } | |
1329 if (s->t4_t6_tx.row_read_handler) | |
1330 { | |
1331 for (row = 0; ; row++) | |
1332 { | |
1333 if ((len = s->t4_t6_tx.row_read_handler(s->t4_t6_tx.row_read_user_data, s->row_buf, s->bytes_per_row)) < 0) | |
1334 { | |
1335 span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error at row %d.\n", s->tiff.file, row); | |
1336 break; | |
1337 } | |
1338 if (len == 0) | |
1339 break; | |
1340 if (encode_row(s)) | |
1341 return -1; | |
1342 } | |
1343 s->image_length = row; | |
1344 } | |
1345 else | |
1346 { | |
1347 if ((s->image_length = read_tiff_image(s)) < 0) | |
1348 return -1; | |
1349 } | |
1350 if (s->line_encoding == T4_COMPRESSION_ITU_T6) | |
1351 { | |
1352 /* Attach an EOFB (end of facsimile block == 2 x EOLs) to the end of the page */ | |
1353 for (i = 0; i < EOLS_TO_END_T6_TX_PAGE; i++) | |
1354 encode_eol(s); | |
1355 } | |
1356 else | |
1357 { | |
1358 /* Attach an RTC (return to control == 6 x EOLs) to the end of the page */ | |
1359 s->row_is_2d = FALSE; | |
1360 for (i = 0; i < EOLS_TO_END_T4_TX_PAGE; i++) | |
1361 encode_eol(s); | |
1362 } | |
1363 | |
1364 /* Force any partial byte in progress to flush using ones. Any post EOL padding when | |
1365 sending is normally ones, so this is consistent. */ | |
1366 put_encoded_bits(s, 0xFF, 7); | |
1367 s->t4_t6_tx.bit_pos = 7; | |
1368 s->t4_t6_tx.bit_ptr = 0; | |
1369 s->line_image_size = s->image_size*8; | |
1370 | |
1371 return 0; | |
1372 } | |
1373 /*- End of function --------------------------------------------------------*/ | |
1374 | |
1375 SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_state_t *s) | |
1376 { | |
1377 span_log(&s->logging, SPAN_LOG_FLOW, "Checking for the existance of page %d\n", s->current_page + 1); | |
1378 if (s->current_page >= s->tiff.stop_page) | |
1379 return -1; | |
1380 if (s->t4_t6_tx.row_read_handler == NULL) | |
1381 { | |
1382 #if defined(HAVE_LIBTIFF) | |
1383 if (s->tiff.tiff_file == NULL) | |
1384 return -1; | |
1385 if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page + 1)) | |
1386 return -1; | |
1387 return test_tiff_directory_info(s); | |
1388 #endif | |
1389 } | |
1390 return 0; | |
1391 } | |
1392 /*- End of function --------------------------------------------------------*/ | |
1393 | |
1394 SPAN_DECLARE(int) t4_tx_restart_page(t4_state_t *s) | |
1395 { | |
1396 s->t4_t6_tx.bit_pos = 7; | |
1397 s->t4_t6_tx.bit_ptr = 0; | |
1398 return 0; | |
1399 } | |
1400 /*- End of function --------------------------------------------------------*/ | |
1401 | |
1402 SPAN_DECLARE(int) t4_tx_end_page(t4_state_t *s) | |
1403 { | |
1404 s->current_page++; | |
1405 return 0; | |
1406 } | |
1407 /*- End of function --------------------------------------------------------*/ | |
1408 | |
1409 SPAN_DECLARE(int) t4_tx_get_bit(t4_state_t *s) | |
1410 { | |
1411 int bit; | |
1412 | |
1413 if (s->t4_t6_tx.bit_ptr >= s->image_size) | |
1414 return SIG_STATUS_END_OF_DATA; | |
1415 bit = (s->image_buffer[s->t4_t6_tx.bit_ptr] >> (7 - s->t4_t6_tx.bit_pos)) & 1; | |
1416 if (--s->t4_t6_tx.bit_pos < 0) | |
1417 { | |
1418 s->t4_t6_tx.bit_pos = 7; | |
1419 s->t4_t6_tx.bit_ptr++; | |
1420 } | |
1421 return bit; | |
1422 } | |
1423 /*- End of function --------------------------------------------------------*/ | |
1424 | |
1425 SPAN_DECLARE(int) t4_tx_get_byte(t4_state_t *s) | |
1426 { | |
1427 if (s->t4_t6_tx.bit_ptr >= s->image_size) | |
1428 return 0x100; | |
1429 return s->image_buffer[s->t4_t6_tx.bit_ptr++]; | |
1430 } | |
1431 /*- End of function --------------------------------------------------------*/ | |
1432 | |
1433 SPAN_DECLARE(int) t4_tx_get_chunk(t4_state_t *s, uint8_t buf[], int max_len) | |
1434 { | |
1435 if (s->t4_t6_tx.bit_ptr >= s->image_size) | |
1436 return 0; | |
1437 if (s->t4_t6_tx.bit_ptr + max_len > s->image_size) | |
1438 max_len = s->image_size - s->t4_t6_tx.bit_ptr; | |
1439 memcpy(buf, &s->image_buffer[s->t4_t6_tx.bit_ptr], max_len); | |
1440 s->t4_t6_tx.bit_ptr += max_len; | |
1441 return max_len; | |
1442 } | |
1443 /*- End of function --------------------------------------------------------*/ | |
1444 | |
1445 SPAN_DECLARE(int) t4_tx_check_bit(t4_state_t *s) | |
1446 { | |
1447 int bit; | |
1448 | |
1449 if (s->t4_t6_tx.bit_ptr >= s->image_size) | |
1450 return SIG_STATUS_END_OF_DATA; | |
1451 bit = (s->image_buffer[s->t4_t6_tx.bit_ptr] >> s->t4_t6_tx.bit_pos) & 1; | |
1452 return bit; | |
1453 } | |
1454 /*- End of function --------------------------------------------------------*/ | |
1455 | |
1456 SPAN_DECLARE(int) t4_tx_release(t4_state_t *s) | |
1457 { | |
1458 if (s->rx) | |
1459 return -1; | |
1460 if (s->tiff.tiff_file) | |
1461 close_tiff_input_file(s); | |
1462 free_buffers(s); | |
1463 return 0; | |
1464 } | |
1465 /*- End of function --------------------------------------------------------*/ | |
1466 | |
1467 SPAN_DECLARE(int) t4_tx_free(t4_state_t *s) | |
1468 { | |
1469 int ret; | |
1470 | |
1471 ret = t4_tx_release(s); | |
1472 free(s); | |
1473 return ret; | |
1474 } | |
1475 /*- End of function --------------------------------------------------------*/ | |
1476 | |
1477 SPAN_DECLARE(void) t4_tx_set_tx_encoding(t4_state_t *s, int encoding) | |
1478 { | |
1479 s->line_encoding = encoding; | |
1480 s->t4_t6_tx.rows_to_next_1d_row = s->t4_t6_tx.max_rows_to_next_1d_row - 1; | |
1481 s->row_is_2d = FALSE; | |
1482 } | |
1483 /*- End of function --------------------------------------------------------*/ | |
1484 | |
1485 SPAN_DECLARE(void) t4_tx_set_min_row_bits(t4_state_t *s, int bits) | |
1486 { | |
1487 s->t4_t6_tx.min_bits_per_row = bits; | |
1488 } | |
1489 /*- End of function --------------------------------------------------------*/ | |
1490 | |
1491 SPAN_DECLARE(void) t4_tx_set_local_ident(t4_state_t *s, const char *ident) | |
1492 { | |
1493 s->tiff.local_ident = (ident && ident[0]) ? ident : NULL; | |
1494 } | |
1495 /*- End of function --------------------------------------------------------*/ | |
1496 | |
1497 SPAN_DECLARE(void) t4_tx_set_header_info(t4_state_t *s, const char *info) | |
1498 { | |
1499 s->t4_t6_tx.header_info = (info && info[0]) ? info : NULL; | |
1500 } | |
1501 /*- End of function --------------------------------------------------------*/ | |
1502 | |
1503 SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_state_t *s) | |
1504 { | |
1505 return s->y_resolution; | |
1506 } | |
1507 /*- End of function --------------------------------------------------------*/ | |
1508 | |
1509 SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_state_t *s) | |
1510 { | |
1511 return s->x_resolution; | |
1512 } | |
1513 /*- End of function --------------------------------------------------------*/ | |
1514 | |
1515 SPAN_DECLARE(int) t4_tx_get_image_width(t4_state_t *s) | |
1516 { | |
1517 return s->image_width; | |
1518 } | |
1519 /*- End of function --------------------------------------------------------*/ | |
1520 | |
1521 SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_state_t *s) | |
1522 { | |
1523 int max; | |
1524 | |
1525 max = 0; | |
1526 if (s->t4_t6_tx.row_read_handler == NULL) | |
1527 max = get_tiff_total_pages(s); | |
1528 if (max >= 0) | |
1529 s->tiff.pages_in_file = max; | |
1530 return max; | |
1531 } | |
1532 /*- End of function --------------------------------------------------------*/ | |
1533 | |
1534 SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_state_t *s) | |
1535 { | |
1536 return s->current_page; | |
1537 } | |
1538 /*- End of function --------------------------------------------------------*/ | |
1539 /*- End of file ------------------------------------------------------------*/ |