File: | libs/spandsp/src/t42.c |
Location: | line 407, column 9 |
Description: | Function call argument is an uninitialized value |
1 | /* | |||
2 | * SpanDSP - a series of DSP components for telephony | |||
3 | * | |||
4 | * t42.c - ITU T.42 JPEG for FAX image processing | |||
5 | * | |||
6 | * Written by Steve Underwood <steveu@coppice.org> | |||
7 | * | |||
8 | * Copyright (C) 2011 Steve Underwood | |||
9 | * | |||
10 | * All rights reserved. | |||
11 | * | |||
12 | * This program is free software; you can redistribute it and/or modify | |||
13 | * it under the terms of the GNU Lesser General Public License version 2.1, | |||
14 | * as published by the Free Software Foundation. | |||
15 | * | |||
16 | * This program is distributed in the hope that it will be useful, | |||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
19 | * GNU Lesser General Public License for more details. | |||
20 | * | |||
21 | * You should have received a copy of the GNU Lesser General Public | |||
22 | * License along with this program; if not, write to the Free Software | |||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
24 | */ | |||
25 | ||||
26 | /*! \file */ | |||
27 | ||||
28 | #if defined(HAVE_CONFIG_H1) | |||
29 | #include "config.h" | |||
30 | #endif | |||
31 | ||||
32 | #include <stdlib.h> | |||
33 | #include <inttypes.h> | |||
34 | #include <limits.h> | |||
35 | #include <stdio.h> | |||
36 | #include <fcntl.h> | |||
37 | #include <unistd.h> | |||
38 | #include <time.h> | |||
39 | #include <memory.h> | |||
40 | #include <string.h> | |||
41 | #include <float.h> | |||
42 | #if defined(HAVE_TGMATH_H1) | |||
43 | #include <tgmath.h> | |||
44 | #endif | |||
45 | #if defined(HAVE_MATH_H1) | |||
46 | #include <math.h> | |||
47 | #endif | |||
48 | #if defined(HAVE_STDBOOL_H1) | |||
49 | #include <stdbool.h> | |||
50 | #else | |||
51 | #include "spandsp/stdbool.h" | |||
52 | #endif | |||
53 | #include "floating_fudge.h" | |||
54 | #include <tiffio.h> | |||
55 | #include <assert.h> | |||
56 | ||||
57 | #include "spandsp/telephony.h" | |||
58 | #include "spandsp/alloc.h" | |||
59 | #include "spandsp/fast_convert.h" | |||
60 | #include "spandsp/logging.h" | |||
61 | #include "spandsp/saturated.h" | |||
62 | #include "spandsp/async.h" | |||
63 | #include "spandsp/timezone.h" | |||
64 | #include "spandsp/t4_rx.h" | |||
65 | #include "spandsp/t4_tx.h" | |||
66 | #include "spandsp/t81_t82_arith_coding.h" | |||
67 | #include "spandsp/t85.h" | |||
68 | #include "spandsp/t42.h" | |||
69 | ||||
70 | #include "spandsp/private/logging.h" | |||
71 | #include "spandsp/private/t81_t82_arith_coding.h" | |||
72 | #include "spandsp/private/t85.h" | |||
73 | #include "spandsp/private/t42.h" | |||
74 | ||||
75 | /* The open_memstream() and fmemopen() in older versions of glibc seem quirky */ | |||
76 | #if defined(__GLIBC__2) && (__GLIBC__2 < 2 || (__GLIBC__2 == 2 && __GLIBC_MINOR__19 < 12)) | |||
77 | #undef OPEN_MEMSTREAM | |||
78 | #endif | |||
79 | ||||
80 | #define T42_USE_LUTS | |||
81 | ||||
82 | #include "t42_t43_local.h" | |||
83 | #if defined(T42_USE_LUTS) | |||
84 | #include "cielab_luts.h" | |||
85 | #endif | |||
86 | ||||
87 | typedef struct | |||
88 | { | |||
89 | float L; | |||
90 | float a; | |||
91 | float b; | |||
92 | } cielab_t; | |||
93 | ||||
94 | typedef struct | |||
95 | { | |||
96 | uint8_t tag[5]; | |||
97 | const char *name; | |||
98 | float xn; | |||
99 | float yn; | |||
100 | float zn; | |||
101 | } illuminant_t; | |||
102 | ||||
103 | static const illuminant_t illuminants[] = | |||
104 | { | |||
105 | {"\0D50", "CIE D50/2°", 96.422f, 100.000f, 82.521f}, /* Horizon Light. ICC profile PCS */ | |||
106 | {"", "CIE D50/10°", 96.720f, 100.000f, 81.427f}, | |||
107 | {"", "CIE D55/2°", 95.682f, 100.000f, 92.149f}, /* Mid-morning/mid-afternoon daylight */ | |||
108 | {"", "CIE D55/10°", 95.799f, 100.000f, 90.926f}, | |||
109 | {"\0D65", "CIE D65/2°", 95.047f, 100.000f, 108.883f}, /* Noon daylight, television, sRGB color space */ | |||
110 | {"", "CIE D65/10°", 94.811f, 100.000f, 107.304f}, | |||
111 | {"\0D75", "CIE D75/2°", 94.972f, 100.000f, 122.638f}, /* North sky daylight */ | |||
112 | {"", "CIE D75/10°", 94.416f, 100.000f, 120.641f}, | |||
113 | {"\0\0F2", "F02/2°", 99.186f, 100.000f, 67.393f}, /* Cool white fluorescent */ | |||
114 | {"", "F02/10°", 103.279f, 100.000f, 69.027f}, | |||
115 | {"\0\0F7", "F07/2°", 95.041f, 100.000f, 108.747f}, /* D65 simulator, daylight simulator */ | |||
116 | {"", "F07/10°", 95.792f, 100.000f, 107.686f}, | |||
117 | {"\0F11", "F11/2°", 100.962f, 100.000f, 64.350f}, /* Philips TL84, Ultralume 40 */ | |||
118 | {"", "F11/10°", 103.863f, 100.000f, 65.607f}, | |||
119 | {"\0\0SA", "A/2°", 109.850f, 100.000f, 35.585f}, /* Incandescent/tungsten */ | |||
120 | {"", "A/10°", 111.144f, 100.000f, 35.200f}, | |||
121 | {"\0\0SC", "C/2°", 98.074f, 100.000f, 118.232f}, /* {obsolete} average/north sky daylight */ | |||
122 | {"", "C/10°", 97.285f, 100.000f, 116.145f}, | |||
123 | {"", "", 0.000f, 0.000f, 0.000f} | |||
124 | }; | |||
125 | ||||
126 | /* LERP(a,b,c) = linear interpolation macro, is 'a' when c == 0.0 and 'b' when c == 1.0 */ | |||
127 | #define LERP(a,b,c)(((b) - (a))*(c) + (a)) (((b) - (a))*(c) + (a)) | |||
128 | ||||
129 | typedef struct UVT | |||
130 | { | |||
131 | double u; | |||
132 | double v; | |||
133 | double t; | |||
134 | } UVT; | |||
135 | ||||
136 | static const double rt[31] = | |||
137 | { | |||
138 | /* Reciprocal temperature (K) */ | |||
139 | FLT_MIN1.17549435e-38F, | |||
140 | 10.0e-6, | |||
141 | 20.0e-6, | |||
142 | 30.0e-6, | |||
143 | 40.0e-6, | |||
144 | 50.0e-6, | |||
145 | 60.0e-6, | |||
146 | 70.0e-6, | |||
147 | 80.0e-6, | |||
148 | 90.0e-6, | |||
149 | 100.0e-6, | |||
150 | 125.0e-6, | |||
151 | 150.0e-6, | |||
152 | 175.0e-6, | |||
153 | 200.0e-6, | |||
154 | 225.0e-6, | |||
155 | 250.0e-6, | |||
156 | 275.0e-6, | |||
157 | 300.0e-6, | |||
158 | 325.0e-6, | |||
159 | 350.0e-6, | |||
160 | 375.0e-6, | |||
161 | 400.0e-6, | |||
162 | 425.0e-6, | |||
163 | 450.0e-6, | |||
164 | 475.0e-6, | |||
165 | 500.0e-6, | |||
166 | 525.0e-6, | |||
167 | 550.0e-6, | |||
168 | 575.0e-6, | |||
169 | 600.0e-6 | |||
170 | }; | |||
171 | ||||
172 | static const UVT uvt[31] = | |||
173 | { | |||
174 | {0.18006, 0.26352, -0.24341}, | |||
175 | {0.18066, 0.26589, -0.25479}, | |||
176 | {0.18133, 0.26846, -0.26876}, | |||
177 | {0.18208, 0.27119, -0.28539}, | |||
178 | {0.18293, 0.27407, -0.30470}, | |||
179 | {0.18388, 0.27709, -0.32675}, | |||
180 | {0.18494, 0.28021, -0.35156}, | |||
181 | {0.18611, 0.28342, -0.37915}, | |||
182 | {0.18740, 0.28668, -0.40955}, | |||
183 | {0.18880, 0.28997, -0.44278}, | |||
184 | {0.19032, 0.29326, -0.47888}, | |||
185 | {0.19462, 0.30141, -0.58204}, | |||
186 | {0.19962, 0.30921, -0.70471}, | |||
187 | {0.20525, 0.31647, -0.84901}, | |||
188 | {0.21142, 0.32312, -1.01820}, | |||
189 | {0.21807, 0.32909, -1.21680}, | |||
190 | {0.22511, 0.33439, -1.45120}, | |||
191 | {0.23247, 0.33904, -1.72980}, | |||
192 | {0.24010, 0.34308, -2.06370}, | |||
193 | {0.24792, 0.34655, -2.46810}, /* Note: 0.24792 is a corrected value for the error found in W&S as 0.24702 */ | |||
194 | {0.25591, 0.34951, -2.96410}, | |||
195 | {0.26400, 0.35200, -3.58140}, | |||
196 | {0.27218, 0.35407, -4.36330}, | |||
197 | {0.28039, 0.35577, -5.37620}, | |||
198 | {0.28863, 0.35714, -6.72620}, | |||
199 | {0.29685, 0.35823, -8.59550}, | |||
200 | {0.30505, 0.35907, -11.3240}, | |||
201 | {0.31320, 0.35968, -15.6280}, | |||
202 | {0.32129, 0.36011, -23.3250}, | |||
203 | {0.32931, 0.36038, -40.7700}, | |||
204 | {0.33724, 0.36051, -116.450} | |||
205 | }; | |||
206 | ||||
207 | static __inline__ uint16_t pack_16(const uint8_t *s) | |||
208 | { | |||
209 | uint16_t value; | |||
210 | ||||
211 | value = ((uint16_t) s[0] << 8) | (uint16_t) s[1]; | |||
212 | return value; | |||
213 | } | |||
214 | /*- End of function --------------------------------------------------------*/ | |||
215 | ||||
216 | #if 0 | |||
217 | static __inline__ uint32_t pack_32(const uint8_t *s) | |||
218 | { | |||
219 | uint32_t value; | |||
220 | ||||
221 | value = ((uint32_t) s[0] << 24) | ((uint32_t) s[1] << 16) | ((uint32_t) s[2] << 8) | (uint32_t) s[3]; | |||
222 | return value; | |||
223 | } | |||
224 | /*- End of function --------------------------------------------------------*/ | |||
225 | #endif | |||
226 | ||||
227 | static __inline__ int unpack_16(uint8_t *s, uint16_t value) | |||
228 | { | |||
229 | s[0] = (value >> 8) & 0xFF; | |||
230 | s[1] = value & 0xFF; | |||
231 | return sizeof(uint16_t); | |||
232 | } | |||
233 | /*- End of function --------------------------------------------------------*/ | |||
234 | ||||
235 | SPAN_DECLARE(bool)__attribute__((visibility("default"))) _Bool t42_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len) | |||
236 | { | |||
237 | int type; | |||
238 | int seg; | |||
239 | int pos; | |||
240 | ||||
241 | /* Search the image data for its width and length */ | |||
242 | *length = 0; | |||
243 | *width = 0; | |||
244 | ||||
245 | pos = 0; | |||
246 | if (pack_16(&data[pos]) != 0xFFD8) | |||
247 | return false0; | |||
248 | pos += 2; | |||
249 | while (pos < len) | |||
250 | { | |||
251 | type = pack_16(&data[pos]); | |||
252 | pos += 2; | |||
253 | seg = pack_16(&data[pos]) - 2; | |||
254 | pos += 2; | |||
255 | if (type == 0xFFC0) | |||
256 | { | |||
257 | *length = pack_16(&data[pos + 1]); | |||
258 | *width = pack_16(&data[pos + 3]); | |||
259 | return true1; | |||
260 | } | |||
261 | pos += seg; | |||
262 | } | |||
263 | return false0; | |||
264 | } | |||
265 | /*- End of function --------------------------------------------------------*/ | |||
266 | ||||
267 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int xyz_to_corrected_color_temp(float *temp, float xyz[3]) | |||
268 | { | |||
269 | float us; | |||
270 | float vs; | |||
271 | float p; | |||
272 | float di; | |||
273 | float dm; | |||
274 | int i; | |||
275 | ||||
276 | /* Protect against possible divide-by-zero failure */ | |||
277 | if ((xyz[0] < 1.0e-20f) && (xyz[1] < 1.0e-20f) && (xyz[2] < 1.0e-20f)) | |||
278 | return -1; | |||
279 | us = (4.0f*xyz[0])/(xyz[0] + 15.0f*xyz[1] + 3.0f*xyz[2]); | |||
280 | vs = (6.0f*xyz[1])/(xyz[0] + 15.0f*xyz[1] + 3.0f*xyz[2]); | |||
281 | dm = 0.0f; | |||
282 | for (i = 0; i < 31; i++) | |||
283 | { | |||
284 | di = (vs - uvt[i].v) - uvt[i].t*(us - uvt[i].u); | |||
285 | if ((i > 0) && (((di < 0.0f) && (dm >= 0.0f)) || ((di >= 0.0f) && (dm < 0.0f)))) | |||
286 | break; /* found lines bounding (us, vs) : i-1 and i */ | |||
287 | dm = di; | |||
288 | } | |||
289 | if (i == 31) | |||
290 | { | |||
291 | /* Bad XYZ input, color temp would be less than minimum of 1666.7 degrees, or too far towards blue */ | |||
292 | return -1; | |||
293 | } | |||
294 | di = di/sqrtf(1.0f + uvt[i ].t*uvt[i ].t); | |||
295 | dm = dm/sqrtf(1.0f + uvt[i - 1].t*uvt[i - 1].t); | |||
296 | p = dm/(dm - di); /* p = interpolation parameter, 0.0 : i-1, 1.0 : i */ | |||
297 | p = 1.0f/(LERP(rt[i - 1], rt[i], p)(((rt[i]) - (rt[i - 1]))*(p) + (rt[i - 1]))); | |||
298 | *temp = p; | |||
299 | return 0; | |||
300 | } | |||
301 | /*- End of function --------------------------------------------------------*/ | |||
302 | ||||
303 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int colour_temp_to_xyz(float xyz[3], float temp) | |||
304 | { | |||
305 | float x; | |||
306 | float y; | |||
307 | ||||
308 | /* Should be good for 1667K to 25000K according to Wikipedia */ | |||
309 | if (temp < 1667.0f || temp > 25000.0f) | |||
310 | return -1; | |||
311 | ||||
312 | if (temp < 4000.0f) | |||
313 | x = -0.2661239e9f/(temp*temp*temp) - 0.2343580e6f/(temp*temp) + 0.8776956e3f/temp + 0.179910f; | |||
314 | else | |||
315 | x = -3.0258469e9f/(temp*temp*temp) + 2.1070379e6f/(temp*temp) + 0.2226347e3f/temp + 0.240390f; | |||
316 | ||||
317 | if (temp < 2222.0f) | |||
318 | y = -1.1063814f*x*x*x - 1.34811020f*x*x + 2.18555832f*x - 0.20219683f; | |||
319 | else if (temp < 4000.0f) | |||
320 | y = -0.9549476f*x*x*x - 1.37418593f*x*x + 2.09137015f*x - 0.16748867f; | |||
321 | else | |||
322 | y = 3.0817580f*x*x*x - 5.87338670f*x*x + 3.75112997f*x - 0.37001483f; | |||
323 | ||||
324 | xyz[0] = x/y; | |||
325 | xyz[1] = 1.0f; | |||
326 | xyz[2] = (1.0f - x - y)/y; | |||
327 | ||||
328 | return 0; | |||
329 | } | |||
330 | /*- End of function --------------------------------------------------------*/ | |||
331 | ||||
332 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void set_lab_illuminant(lab_params_t *lab, float new_xn, float new_yn, float new_zn) | |||
333 | { | |||
334 | if (new_yn > 10.0f) | |||
335 | { | |||
336 | lab->x_n = new_xn/100.0f; | |||
337 | lab->y_n = new_yn/100.0f; | |||
338 | lab->z_n = new_zn/100.0f; | |||
339 | } | |||
340 | else | |||
341 | { | |||
342 | lab->x_n = new_xn; | |||
343 | lab->y_n = new_yn; | |||
344 | lab->z_n = new_zn; | |||
345 | } | |||
346 | lab->x_rn = 1.0f/lab->x_n; | |||
347 | lab->y_rn = 1.0f/lab->y_n; | |||
348 | lab->z_rn = 1.0f/lab->z_n; | |||
349 | } | |||
350 | /*- End of function --------------------------------------------------------*/ | |||
351 | ||||
352 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void set_lab_gamut(lab_params_t *lab, int L_min, int L_max, int a_min, int a_max, int b_min, int b_max, int ab_are_signed) | |||
353 | { | |||
354 | lab->range_L = L_max - L_min; | |||
355 | lab->range_a = a_max - a_min; | |||
356 | lab->range_b = b_max - b_min; | |||
357 | ||||
358 | lab->offset_L = -256.0f*L_min/lab->range_L; | |||
359 | lab->offset_a = -256.0f*a_min/lab->range_a; | |||
360 | lab->offset_b = -256.0f*b_min/lab->range_b; | |||
361 | ||||
362 | lab->range_L /= (256.0f - 1.0f); | |||
363 | lab->range_a /= (256.0f - 1.0f); | |||
364 | lab->range_b /= (256.0f - 1.0f); | |||
365 | ||||
366 | lab->ab_are_signed = ab_are_signed; | |||
367 | } | |||
368 | /*- End of function --------------------------------------------------------*/ | |||
369 | ||||
370 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void set_lab_gamut2(lab_params_t *lab, int L_P, int L_Q, int a_P, int a_Q, int b_P, int b_Q) | |||
371 | { | |||
372 | lab->range_L = L_Q/(256.0f - 1.0f); | |||
373 | lab->range_a = a_Q/(256.0f - 1.0f); | |||
374 | lab->range_b = b_Q/(256.0f - 1.0f); | |||
375 | ||||
376 | lab->offset_L = L_P; | |||
377 | lab->offset_a = a_P; | |||
378 | lab->offset_b = b_P; | |||
379 | ||||
380 | lab->ab_are_signed = false0; | |||
381 | } | |||
382 | /*- End of function --------------------------------------------------------*/ | |||
383 | ||||
384 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void get_lab_gamut2(lab_params_t *lab, int *L_P, int *L_Q, int *a_P, int *a_Q, int *b_P, int *b_Q) | |||
385 | { | |||
386 | *L_Q = lab->range_L*(256.0f - 1.0f); | |||
387 | *a_Q = lab->range_a*(256.0f - 1.0f); | |||
388 | *b_Q = lab->range_b*(256.0f - 1.0f); | |||
389 | ||||
390 | *L_P = lab->offset_L; | |||
391 | *a_P = lab->offset_a; | |||
392 | *b_P = lab->offset_b; | |||
393 | } | |||
394 | /*- End of function --------------------------------------------------------*/ | |||
395 | ||||
396 | int set_illuminant_from_code(logging_state_t *logging, lab_params_t *lab, const uint8_t code[4]) | |||
397 | { | |||
398 | int i; | |||
399 | int colour_temp; | |||
400 | float xyz[3]; | |||
401 | ||||
402 | if (memcmp(code, "CT", 2) == 0) | |||
403 | { | |||
404 | colour_temp = pack_16(&code[2]); | |||
405 | span_log(logging, SPAN_LOG_FLOW, "Illuminant colour temp %dK\n", colour_temp); | |||
406 | colour_temp_to_xyz(xyz, (float) colour_temp); | |||
407 | set_lab_illuminant(lab, xyz[0], xyz[1], xyz[2]); | |||
| ||||
408 | return colour_temp; | |||
409 | } | |||
410 | for (i = 0; illuminants[i].name[0]; i++) | |||
411 | { | |||
412 | if (memcmp(code, illuminants[i].tag, 4) == 0) | |||
413 | { | |||
414 | span_log(logging, SPAN_LOG_FLOW, "Illuminant %s\n", illuminants[i].name); | |||
415 | set_lab_illuminant(lab, illuminants[i].xn, illuminants[i].yn, illuminants[i].zn); | |||
416 | return 0; | |||
417 | } | |||
418 | } | |||
419 | if (illuminants[i].name[0] == '\0') | |||
420 | span_log(logging, SPAN_LOG_FLOW, "Unrecognised illuminant 0x%x 0x%x 0x%x 0x%x\n", code[0], code[1], code[2], code[3]); | |||
421 | return -1; | |||
422 | } | |||
423 | /*- End of function --------------------------------------------------------*/ | |||
424 | ||||
425 | void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12]) | |||
426 | { | |||
427 | int i; | |||
428 | int val[6]; | |||
429 | ||||
430 | for (i = 0; i < 6; i++) | |||
431 | val[i] = pack_16(&code[2*i]); | |||
432 | span_log(logging, | |||
433 | SPAN_LOG_FLOW, | |||
434 | "Gamut L=[%d,%d], a*=[%d,%d], b*=[%d,%d]\n", | |||
435 | val[0], | |||
436 | val[1], | |||
437 | val[2], | |||
438 | val[3], | |||
439 | val[4], | |||
440 | val[5]); | |||
441 | set_lab_gamut2(s, val[0], val[1], val[2], val[3], val[4], val[5]); | |||
442 | } | |||
443 | /*- End of function --------------------------------------------------------*/ | |||
444 | ||||
445 | static __inline__ void itu_to_lab(lab_params_t *s, cielab_t *lab, const uint8_t in[3]) | |||
446 | { | |||
447 | uint8_t a; | |||
448 | uint8_t b; | |||
449 | ||||
450 | /* T.4 E.6.4 */ | |||
451 | lab->L = s->range_L*(in[0] - s->offset_L); | |||
452 | a = in[1]; | |||
453 | b = in[2]; | |||
454 | if (s->ab_are_signed) | |||
455 | { | |||
456 | a += 128; | |||
457 | b += 128; | |||
458 | } | |||
459 | lab->a = s->range_a*(a - s->offset_a); | |||
460 | lab->b = s->range_b*(b - s->offset_b); | |||
461 | } | |||
462 | /*- End of function --------------------------------------------------------*/ | |||
463 | ||||
464 | static __inline__ void lab_to_itu(lab_params_t *s, uint8_t out[3], const cielab_t *lab) | |||
465 | { | |||
466 | /* T.4 E.6.4 */ | |||
467 | out[0] = saturateu8(floorf(lab->L/s->range_L + s->offset_L)); | |||
468 | out[1] = saturateu8(floorf(lab->a/s->range_a + s->offset_a)); | |||
469 | out[2] = saturateu8(floorf(lab->b/s->range_b + s->offset_b)); | |||
470 | if (s->ab_are_signed) | |||
471 | { | |||
472 | out[1] -= 128; | |||
473 | out[2] -= 128; | |||
474 | } | |||
475 | } | |||
476 | /*- End of function --------------------------------------------------------*/ | |||
477 | ||||
478 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srgb[], int pixels) | |||
479 | { | |||
480 | float x; | |||
481 | float y; | |||
482 | float z; | |||
483 | float r; | |||
484 | float g; | |||
485 | float b; | |||
486 | float xx; | |||
487 | float yy; | |||
488 | float zz; | |||
489 | cielab_t l; | |||
490 | int i; | |||
491 | ||||
492 | for (i = 0; i < 3*pixels; i += 3) | |||
493 | { | |||
494 | #if defined(T42_USE_LUTS) | |||
495 | r = srgb_to_linear[srgb[i]]; | |||
496 | g = srgb_to_linear[srgb[i + 1]]; | |||
497 | b = srgb_to_linear[srgb[i + 2]]; | |||
498 | #else | |||
499 | r = srgb[i]/256.0f; | |||
500 | g = srgb[i + 1]/256.0f; | |||
501 | b = srgb[i + 2]/256.0f; | |||
502 | ||||
503 | /* sRGB to linear RGB */ | |||
504 | r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f; | |||
505 | g = (g > 0.04045f) ? powf((g + 0.055f)/1.055f, 2.4f) : g/12.92f; | |||
506 | b = (b > 0.04045f) ? powf((b + 0.055f)/1.055f, 2.4f) : b/12.92f; | |||
507 | #endif | |||
508 | ||||
509 | /* Linear RGB to XYZ */ | |||
510 | x = 0.4124f*r + 0.3576f*g + 0.1805f*b; | |||
511 | y = 0.2126f*r + 0.7152f*g + 0.0722f*b; | |||
512 | z = 0.0193f*r + 0.1192f*g + 0.9505f*b; | |||
513 | ||||
514 | /* Normalise for the illuminant */ | |||
515 | x *= s->x_rn; | |||
516 | y *= s->y_rn; | |||
517 | z *= s->z_rn; | |||
518 | ||||
519 | /* XYZ to Lab */ | |||
520 | xx = (x <= 0.008856f) ? (7.787f*x + 0.1379f) : cbrtf(x); | |||
521 | yy = (y <= 0.008856f) ? (7.787f*y + 0.1379f) : cbrtf(y); | |||
522 | zz = (z <= 0.008856f) ? (7.787f*z + 0.1379f) : cbrtf(z); | |||
523 | l.L = 116.0f*yy - 16.0f; | |||
524 | l.a = 500.0f*(xx - yy); | |||
525 | l.b = 200.0f*(yy - zz); | |||
526 | ||||
527 | lab_to_itu(s, lab, &l); | |||
528 | ||||
529 | lab += 3; | |||
530 | } | |||
531 | } | |||
532 | /*- End of function --------------------------------------------------------*/ | |||
533 | ||||
534 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void lab_to_srgb(lab_params_t *s, uint8_t srgb[], const uint8_t lab[], int pixels) | |||
535 | { | |||
536 | float x; | |||
537 | float y; | |||
538 | float z; | |||
539 | float r; | |||
540 | float g; | |||
541 | float b; | |||
542 | float ll; | |||
543 | cielab_t l; | |||
544 | int val; | |||
545 | int i; | |||
546 | ||||
547 | for (i = 0; i < 3*pixels; i += 3) | |||
548 | { | |||
549 | itu_to_lab(s, &l, lab); | |||
550 | ||||
551 | /* Lab to XYZ */ | |||
552 | ll = (1.0f/116.0f)*(l.L + 16.0f); | |||
553 | y = ll; | |||
554 | y = (y <= 0.2068f) ? (0.1284f*(y - 0.1379f)) : y*y*y; | |||
555 | x = ll + (1.0f/500.0f)*l.a; | |||
556 | x = (x <= 0.2068f) ? (0.1284f*(x - 0.1379f)) : x*x*x; | |||
557 | z = ll - (1.0f/200.0f)*l.b; | |||
558 | z = (z <= 0.2068f) ? (0.1284f*(z - 0.1379f)) : z*z*z; | |||
559 | ||||
560 | /* Normalise for the illuminant */ | |||
561 | x *= s->x_n; | |||
562 | y *= s->y_n; | |||
563 | z *= s->z_n; | |||
564 | ||||
565 | /* XYZ to linear RGB */ | |||
566 | r = 3.2406f*x - 1.5372f*y - 0.4986f*z; | |||
567 | g = -0.9689f*x + 1.8758f*y + 0.0415f*z; | |||
568 | b = 0.0557f*x - 0.2040f*y + 1.0570f*z; | |||
569 | ||||
570 | #if defined(T42_USE_LUTS) | |||
571 | val = r*4096.0f; | |||
572 | srgb[i] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; | |||
573 | val = g*4096.0f; | |||
574 | srgb[i + 1] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; | |||
575 | val = b*4096.0f; | |||
576 | srgb[i + 2] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; | |||
577 | #else | |||
578 | /* Linear RGB to sRGB */ | |||
579 | r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f; | |||
580 | g = (g > 0.0031308f) ? (1.055f*powf(g, 1.0f/2.4f) - 0.055f) : g*12.92f; | |||
581 | b = (b > 0.0031308f) ? (1.055f*powf(b, 1.0f/2.4f) - 0.055f) : b*12.92f; | |||
582 | ||||
583 | srgb[i] = saturateu8(floorf(r*256.0f)); | |||
584 | srgb[i + 1] = saturateu8(floorf(g*256.0f)); | |||
585 | srgb[i + 2] = saturateu8(floorf(b*256.0f)); | |||
586 | #endif | |||
587 | lab += 3; | |||
588 | } | |||
589 | } | |||
590 | /*- End of function --------------------------------------------------------*/ | |||
591 | ||||
592 | static int is_itu_fax(t42_decode_state_t *s, jpeg_saved_marker_ptr ptr) | |||
593 | { | |||
594 | const uint8_t *data; | |||
595 | int ok; | |||
596 | int val[6]; | |||
597 | ||||
598 | ok = false0; | |||
599 | for ( ; ptr; ptr = ptr->next) | |||
| ||||
600 | { | |||
601 | if (ptr->marker != (JPEG_APP00xE0 + 1)) | |||
602 | continue; | |||
603 | if (ptr->data_length < 6) | |||
604 | return false0; | |||
605 | /* Markers are: | |||
606 | JPEG_RST0 | |||
607 | JPEG_EOI | |||
608 | JPEG_APP0 | |||
609 | JPEG_COM */ | |||
610 | data = (const uint8_t *) ptr->data; | |||
611 | if (strncmp((const char *) data, "G3FAX", 5)(__extension__ (__builtin_constant_p (5) && ((__builtin_constant_p ((const char *) data) && strlen ((const char *) data ) < ((size_t) (5))) || (__builtin_constant_p ("G3FAX") && strlen ("G3FAX") < ((size_t) (5)))) ? __extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p ((const char *) data ) && __builtin_constant_p ("G3FAX") && (__s1_len = __builtin_strlen ((const char *) data), __s2_len = __builtin_strlen ("G3FAX"), (!((size_t)(const void *)(((const char *) data) + 1) - (size_t)(const void *)((const char *) data) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("G3FAX") + 1) - (size_t)(const void *)("G3FAX") == 1) || __s2_len >= 4) ) ? __builtin_strcmp ((const char *) data, "G3FAX") : (__builtin_constant_p ((const char *) data) && ((size_t)(const void *)(((const char *) data) + 1) - (size_t)(const void *)((const char *) data ) == 1) && (__s1_len = __builtin_strlen ((const char * ) data), __s1_len < 4) ? (__builtin_constant_p ("G3FAX") && ((size_t)(const void *)(("G3FAX") + 1) - (size_t)(const void *)("G3FAX") == 1) ? __builtin_strcmp ((const char *) data, "G3FAX" ) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("G3FAX"); int __result = (((const unsigned char *) (const char *) ((const char *) data))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = ( ((const unsigned char *) (const char *) ((const char *) data) )[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ((const char *) data))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ((const char *) data))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("G3FAX") && ((size_t)(const void *)(("G3FAX") + 1) - (size_t)(const void *)("G3FAX") == 1) && (__s2_len = __builtin_strlen ("G3FAX"), __s2_len < 4) ? ( __builtin_constant_p ((const char *) data) && ((size_t )(const void *)(((const char *) data) + 1) - (size_t)(const void *)((const char *) data) == 1) ? __builtin_strcmp ((const char *) data, "G3FAX") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ((const char * ) data); int __result = (((const unsigned char *) (const char *) ("G3FAX"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ( "G3FAX"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ( "G3FAX"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("G3FAX" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp ((const char *) data, "G3FAX")))); }) : strncmp ((const char *) data , "G3FAX", 5)))) | |||
612 | return false0; | |||
613 | switch (data[5]) | |||
614 | { | |||
615 | case 0: | |||
616 | if (ptr->data_length < 6 + 4) | |||
617 | { | |||
618 | span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX0 length - %d\n", ptr->data_length); | |||
619 | return false0; | |||
620 | } | |||
621 | val[0] = pack_16(&data[6]); | |||
622 | s->spatial_resolution = pack_16(&data[6 + 2]); | |||
623 | span_log(&s->logging, SPAN_LOG_FLOW, "Version %d, resolution %ddpi\n", val[0], s->spatial_resolution); | |||
624 | ok = true1; | |||
625 | break; | |||
626 | case 1: | |||
627 | span_log(&s->logging, SPAN_LOG_FLOW, "Set gamut\n"); | |||
628 | if (ptr->data_length < 6 + 12) | |||
629 | { | |||
630 | span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", ptr->data_length); | |||
631 | return false0; | |||
632 | } | |||
633 | set_gamut_from_code(&s->logging, &s->lab, &data[6]); | |||
634 | break; | |||
635 | case 2: | |||
636 | span_log(&s->logging, SPAN_LOG_FLOW, "Set illuminant\n"); | |||
637 | if (ptr->data_length < 6 + 4) | |||
638 | { | |||
639 | span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", ptr->data_length); | |||
640 | return false0; | |||
641 | } | |||
642 | s->illuminant_colour_temperature = set_illuminant_from_code(&s->logging, &s->lab, &data[6]); | |||
643 | break; | |||
644 | default: | |||
645 | span_log(&s->logging, SPAN_LOG_FLOW, "Got unexpected G3FAX%d length - %d\n", data[5], ptr->data_length); | |||
646 | return false0; | |||
647 | } | |||
648 | } | |||
649 | ||||
650 | return ok; | |||
651 | } | |||
652 | /*- End of function --------------------------------------------------------*/ | |||
653 | ||||
654 | static void set_itu_fax(t42_encode_state_t *s) | |||
655 | { | |||
656 | uint8_t data[50]; | |||
657 | int val[6]; | |||
658 | ||||
659 | memcpy(data, "G3FAX\0", 6); | |||
660 | unpack_16(&data[6 + 0], 1994); | |||
661 | unpack_16(&data[6 + 2], s->spatial_resolution); | |||
662 | jpeg_write_marker(&s->compressor, (JPEG_APP00xE0 + 1), data, 6 + 4); | |||
663 | ||||
664 | if (s->lab.offset_L != 0 | |||
665 | || | |||
666 | s->lab.range_L != 100 | |||
667 | || | |||
668 | s->lab.offset_a != 128 | |||
669 | || | |||
670 | s->lab.range_a != 170 | |||
671 | || | |||
672 | s->lab.offset_b != 96 | |||
673 | || | |||
674 | s->lab.range_b != 200) | |||
675 | { | |||
676 | span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX1\n"); | |||
677 | memcpy(data, "G3FAX\1", 6); | |||
678 | get_lab_gamut2(&s->lab, &val[0], &val[1], &val[2], &val[3], &val[4], &val[5]); | |||
679 | unpack_16(&data[6 + 0], val[0]); | |||
680 | unpack_16(&data[6 + 2], val[1]); | |||
681 | unpack_16(&data[6 + 4], val[2]); | |||
682 | unpack_16(&data[6 + 6], val[3]); | |||
683 | unpack_16(&data[6 + 8], val[4]); | |||
684 | unpack_16(&data[6 + 10], val[5]); | |||
685 | jpeg_write_marker(&s->compressor, (JPEG_APP00xE0 + 1), data, 6 + 12); | |||
686 | } | |||
687 | ||||
688 | if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0 | |||
689 | || | |||
690 | s->illuminant_colour_temperature > 0) | |||
691 | { | |||
692 | span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX2\n"); | |||
693 | memcpy(data, "G3FAX\2", 6); | |||
694 | if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0) | |||
695 | { | |||
696 | memcpy(&data[6], s->illuminant_code, 4); | |||
697 | } | |||
698 | else | |||
699 | { | |||
700 | memcpy(&data[6 + 0], "CT", 2); | |||
701 | unpack_16(&data[6 + 2], s->illuminant_colour_temperature); | |||
702 | } | |||
703 | jpeg_write_marker(&s->compressor, (JPEG_APP00xE0 + 1), data, 6 + 4); | |||
704 | } | |||
705 | } | |||
706 | /*- End of function --------------------------------------------------------*/ | |||
707 | ||||
708 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void t42_encode_set_options(t42_encode_state_t *s, | |||
709 | uint32_t l0, | |||
710 | int quality, | |||
711 | int options) | |||
712 | { | |||
713 | s->quality = quality; | |||
714 | s->no_subsampling = (options & 1); | |||
715 | } | |||
716 | /*- End of function --------------------------------------------------------*/ | |||
717 | ||||
718 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_set_image_width(t42_encode_state_t *s, uint32_t image_width) | |||
719 | { | |||
720 | s->image_width = image_width; | |||
721 | return 0; | |||
722 | } | |||
723 | /*- End of function --------------------------------------------------------*/ | |||
724 | ||||
725 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_set_image_length(t42_encode_state_t *s, uint32_t image_length) | |||
726 | { | |||
727 | s->image_length = image_length; | |||
728 | return 0; | |||
729 | } | |||
730 | /*- End of function --------------------------------------------------------*/ | |||
731 | ||||
732 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_set_image_type(t42_encode_state_t *s, int image_type) | |||
733 | { | |||
734 | s->image_type = image_type; | |||
735 | return 0; | |||
736 | } | |||
737 | /*- End of function --------------------------------------------------------*/ | |||
738 | ||||
739 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void t42_encode_abort(t42_encode_state_t *s) | |||
740 | { | |||
741 | } | |||
742 | /*- End of function --------------------------------------------------------*/ | |||
743 | ||||
744 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void t42_encode_comment(t42_encode_state_t *s, const uint8_t comment[], size_t len) | |||
745 | { | |||
746 | } | |||
747 | /*- End of function --------------------------------------------------------*/ | |||
748 | ||||
749 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_image_complete(t42_encode_state_t *s) | |||
750 | { | |||
751 | //if (????) | |||
752 | // return SIG_STATUS_END_OF_DATA; | |||
753 | return 0; | |||
754 | } | |||
755 | /*- End of function --------------------------------------------------------*/ | |||
756 | ||||
757 | /* Error handler for IJG library */ | |||
758 | static void jpg_encode_error_exit(j_common_ptr cinfo) | |||
759 | { | |||
760 | t42_encode_state_t *s; | |||
761 | ||||
762 | s = (t42_encode_state_t *) cinfo->client_data; | |||
763 | (*cinfo->err->format_message)(cinfo, s->error_message); | |||
764 | longjmp(s->escape, 1); | |||
765 | } | |||
766 | /*- End of function --------------------------------------------------------*/ | |||
767 | ||||
768 | /* This is the error catcher */ | |||
769 | static struct jpeg_error_mgr encode_error_handler = | |||
770 | { | |||
771 | #if defined(_MSC_VER) || defined(__sunos) || defined(__solaris) || defined(__sun) | |||
772 | jpg_encode_error_exit, | |||
773 | 0, | |||
774 | jpg_encode_error_exit | |||
775 | #else | |||
776 | .error_exit = jpg_encode_error_exit, | |||
777 | .output_message = jpg_encode_error_exit | |||
778 | #endif | |||
779 | }; | |||
780 | ||||
781 | static int t42_srgb_to_itulab_jpeg(t42_encode_state_t *s) | |||
782 | { | |||
783 | int i; | |||
784 | ||||
785 | if (setjmp(s->escape)_setjmp (s->escape)) | |||
786 | { | |||
787 | if (s->error_message[0]) | |||
788 | span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", s->error_message); | |||
789 | else | |||
790 | span_log(&s->logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); | |||
791 | if (s->scan_line_out) | |||
792 | { | |||
793 | span_free(s->scan_line_out); | |||
794 | s->scan_line_out = NULL((void*)0); | |||
795 | } | |||
796 | if (s->out) | |||
797 | { | |||
798 | fclose(s->out); | |||
799 | s->out = NULL((void*)0); | |||
800 | } | |||
801 | return -1; | |||
802 | } | |||
803 | ||||
804 | s->compressor.err = jpeg_std_error(&encode_error_handler); | |||
805 | s->compressor.client_data = (void *) s; | |||
806 | ||||
807 | jpeg_create_compress(&s->compressor)jpeg_CreateCompress((&s->compressor), 62, (size_t) sizeof (struct jpeg_compress_struct)); | |||
808 | jpeg_stdio_dest(&s->compressor, s->out); | |||
809 | ||||
810 | /* Force the destination colour space */ | |||
811 | if (s->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) | |||
812 | { | |||
813 | s->samples_per_pixel = 3; | |||
814 | s->compressor.in_color_space = JCS_YCbCr; | |||
815 | s->compressor.input_components = s->samples_per_pixel; | |||
816 | } | |||
817 | else | |||
818 | { | |||
819 | s->samples_per_pixel = 1; | |||
820 | s->compressor.in_color_space = JCS_GRAYSCALE; | |||
821 | s->compressor.input_components = s->samples_per_pixel; | |||
822 | } | |||
823 | ||||
824 | jpeg_set_defaults(&s->compressor); | |||
825 | /* Limit to baseline-JPEG values */ | |||
826 | //jpeg_set_quality(&s->compressor, s->quality, true); | |||
827 | ||||
828 | if (s->no_subsampling) | |||
829 | { | |||
830 | /* Set 1:1:1 */ | |||
831 | s->compressor.comp_info[0].h_samp_factor = 1; | |||
832 | s->compressor.comp_info[0].v_samp_factor = 1; | |||
833 | } | |||
834 | else | |||
835 | { | |||
836 | /* Set 4:1:1 */ | |||
837 | s->compressor.comp_info[0].h_samp_factor = 2; | |||
838 | s->compressor.comp_info[0].v_samp_factor = 2; | |||
839 | } | |||
840 | s->compressor.comp_info[1].h_samp_factor = 1; | |||
841 | s->compressor.comp_info[1].v_samp_factor = 1; | |||
842 | s->compressor.comp_info[2].h_samp_factor = 1; | |||
843 | s->compressor.comp_info[2].v_samp_factor = 1; | |||
844 | ||||
845 | /* Size, resolution, etc */ | |||
846 | s->compressor.image_width = s->image_width; | |||
847 | s->compressor.image_height = s->image_length; | |||
848 | ||||
849 | jpeg_start_compress(&s->compressor, true1); | |||
850 | ||||
851 | set_itu_fax(s); | |||
852 | ||||
853 | if ((s->scan_line_in = (JSAMPROW) span_alloc(s->samples_per_pixel*s->image_width)) == NULL((void*)0)) | |||
854 | return -1; | |||
855 | ||||
856 | if (s->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) | |||
857 | { | |||
858 | if ((s->scan_line_out = (JSAMPROW) span_alloc(s->samples_per_pixel*s->image_width)) == NULL((void*)0)) | |||
859 | return -1; | |||
860 | ||||
861 | for (i = 0; i < s->compressor.image_height; i++) | |||
862 | { | |||
863 | s->row_read_handler(s->row_read_user_data, s->scan_line_in, s->samples_per_pixel*s->image_width); | |||
864 | srgb_to_lab(&s->lab, s->scan_line_out, s->scan_line_in, s->image_width); | |||
865 | jpeg_write_scanlines(&s->compressor, &s->scan_line_out, 1); | |||
866 | } | |||
867 | } | |||
868 | else | |||
869 | { | |||
870 | for (i = 0; i < s->compressor.image_height; i++) | |||
871 | { | |||
872 | s->row_read_handler(s->row_read_user_data, s->scan_line_in, s->image_width); | |||
873 | jpeg_write_scanlines(&s->compressor, &s->scan_line_in, 1); | |||
874 | } | |||
875 | } | |||
876 | ||||
877 | if (s->scan_line_out) | |||
878 | { | |||
879 | span_free(s->scan_line_out); | |||
880 | s->scan_line_out = NULL((void*)0); | |||
881 | } | |||
882 | jpeg_finish_compress(&s->compressor); | |||
883 | jpeg_destroy_compress(&s->compressor); | |||
884 | ||||
885 | #if defined(HAVE_OPEN_MEMSTREAM1) | |||
886 | fclose(s->out); | |||
887 | s->buf_size = | |||
888 | s->compressed_image_size = s->outsize; | |||
889 | #else | |||
890 | s->buf_size = | |||
891 | s->compressed_image_size = ftell(s->out); | |||
892 | if ((s->compressed_buf = span_alloc(s->compressed_image_size)) == NULL((void*)0)) | |||
893 | return -1; | |||
894 | if (fseek(s->out, 0, SEEK_SET0) != 0) | |||
895 | { | |||
896 | fclose(s->out); | |||
897 | s->out = NULL((void*)0); | |||
898 | span_free(s->compressed_buf); | |||
899 | s->compressed_buf = NULL((void*)0); | |||
900 | return -1; | |||
901 | } | |||
902 | if (fread(s->compressed_buf, 1, s->compressed_image_size, s->out) != s->compressed_image_size) | |||
903 | { | |||
904 | fclose(s->out); | |||
905 | s->out = NULL((void*)0); | |||
906 | span_free(s->compressed_buf); | |||
907 | s->compressed_buf = NULL((void*)0); | |||
908 | return -1; | |||
909 | } | |||
910 | if (s->out) | |||
911 | { | |||
912 | fclose(s->out); | |||
913 | s->out = NULL((void*)0); | |||
914 | } | |||
915 | #endif | |||
916 | ||||
917 | return 0; | |||
918 | } | |||
919 | /*- End of function --------------------------------------------------------*/ | |||
920 | ||||
921 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_get(t42_encode_state_t *s, uint8_t buf[], size_t max_len) | |||
922 | { | |||
923 | int len; | |||
924 | ||||
925 | if (s->compressed_image_size == 0) | |||
926 | { | |||
927 | if (t42_srgb_to_itulab_jpeg(s)) | |||
928 | { | |||
929 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert to ITULAB.\n"); | |||
930 | return -1; | |||
931 | } | |||
932 | } | |||
933 | if (s->compressed_image_size >= s->compressed_image_ptr + max_len) | |||
934 | len = max_len; | |||
935 | else | |||
936 | len = s->compressed_image_size - s->compressed_image_ptr; | |||
937 | memcpy(buf, &s->compressed_buf[s->compressed_image_ptr], len); | |||
938 | s->compressed_image_ptr += len; | |||
939 | return len; | |||
940 | } | |||
941 | /*- End of function --------------------------------------------------------*/ | |||
942 | ||||
943 | SPAN_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t t42_encode_get_image_width(t42_encode_state_t *s) | |||
944 | { | |||
945 | return s->image_width; | |||
946 | } | |||
947 | /*- End of function --------------------------------------------------------*/ | |||
948 | ||||
949 | SPAN_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t t42_encode_get_image_length(t42_encode_state_t *s) | |||
950 | { | |||
951 | return s->image_length; | |||
952 | } | |||
953 | /*- End of function --------------------------------------------------------*/ | |||
954 | ||||
955 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_get_compressed_image_size(t42_encode_state_t *s) | |||
956 | { | |||
957 | return s->compressed_image_size; | |||
958 | } | |||
959 | /*- End of function --------------------------------------------------------*/ | |||
960 | ||||
961 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_set_row_read_handler(t42_encode_state_t *s, | |||
962 | t4_row_read_handler_t handler, | |||
963 | void *user_data) | |||
964 | { | |||
965 | s->row_read_handler = handler; | |||
966 | s->row_read_user_data = user_data; | |||
967 | return 0; | |||
968 | } | |||
969 | /*- End of function --------------------------------------------------------*/ | |||
970 | ||||
971 | SPAN_DECLARE(logging_state_t *)__attribute__((visibility("default"))) logging_state_t * t42_encode_get_logging_state(t42_encode_state_t *s) | |||
972 | { | |||
973 | return &s->logging; | |||
974 | } | |||
975 | /*- End of function --------------------------------------------------------*/ | |||
976 | ||||
977 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_restart(t42_encode_state_t *s, uint32_t image_width, uint32_t image_length) | |||
978 | { | |||
979 | s->image_width = image_width; | |||
980 | s->image_length = image_length; | |||
981 | ||||
982 | if (s->itu_ycc) | |||
983 | { | |||
984 | /* ITU-YCC */ | |||
985 | /* Illuminant D65 */ | |||
986 | //set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f); | |||
987 | set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); | |||
988 | set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false0); | |||
989 | } | |||
990 | else | |||
991 | { | |||
992 | /* ITULAB */ | |||
993 | /* Illuminant D50 */ | |||
994 | //set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f); | |||
995 | set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); | |||
996 | set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false0); | |||
997 | } | |||
998 | s->compressed_image_size = 0; | |||
999 | s->compressed_image_ptr = 0; | |||
1000 | ||||
1001 | s->spatial_resolution = 200; | |||
1002 | ||||
1003 | s->error_message[0] = '\0'; | |||
1004 | ||||
1005 | #if defined(HAVE_OPEN_MEMSTREAM1) | |||
1006 | s->outsize = 0; | |||
1007 | if ((s->out = open_memstream((char **) &s->compressed_buf, &s->outsize)) == NULL((void*)0)) | |||
1008 | { | |||
1009 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); | |||
1010 | return -1; | |||
1011 | } | |||
1012 | #else | |||
1013 | if ((s->out = tmpfile()) == NULL((void*)0)) | |||
1014 | { | |||
1015 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); | |||
1016 | return -1; | |||
1017 | } | |||
1018 | #endif | |||
1019 | s->scan_line_out = NULL((void*)0); | |||
1020 | ||||
1021 | return 0; | |||
1022 | } | |||
1023 | /*- End of function --------------------------------------------------------*/ | |||
1024 | ||||
1025 | SPAN_DECLARE(t42_encode_state_t *)__attribute__((visibility("default"))) t42_encode_state_t * t42_encode_init(t42_encode_state_t *s, | |||
1026 | uint32_t image_width, | |||
1027 | uint32_t image_length, | |||
1028 | t4_row_read_handler_t handler, | |||
1029 | void *user_data) | |||
1030 | { | |||
1031 | if (s == NULL((void*)0)) | |||
1032 | { | |||
1033 | if ((s = (t42_encode_state_t *) span_alloc(sizeof(*s))) == NULL((void*)0)) | |||
1034 | return NULL((void*)0); | |||
1035 | } | |||
1036 | memset(s, 0, sizeof(*s)); | |||
1037 | span_log_init(&s->logging, SPAN_LOG_NONE, NULL((void*)0)); | |||
1038 | span_log_set_protocol(&s->logging, "T.42"); | |||
1039 | ||||
1040 | s->quality = 90; | |||
1041 | s->image_type = T4_IMAGE_TYPE_COLOUR_8BIT; | |||
1042 | ||||
1043 | s->row_read_handler = handler; | |||
1044 | s->row_read_user_data = user_data; | |||
1045 | ||||
1046 | t42_encode_restart(s, image_width, image_length); | |||
1047 | ||||
1048 | return s; | |||
1049 | } | |||
1050 | /*- End of function --------------------------------------------------------*/ | |||
1051 | ||||
1052 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_release(t42_encode_state_t *s) | |||
1053 | { | |||
1054 | return 0; | |||
1055 | } | |||
1056 | /*- End of function --------------------------------------------------------*/ | |||
1057 | ||||
1058 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_encode_free(t42_encode_state_t *s) | |||
1059 | { | |||
1060 | int ret; | |||
1061 | ||||
1062 | ret = t42_encode_release(s); | |||
1063 | span_free(s); | |||
1064 | return ret; | |||
1065 | } | |||
1066 | /*- End of function --------------------------------------------------------*/ | |||
1067 | ||||
1068 | /* Error handler for IJG library */ | |||
1069 | static void jpg_decode_error_exit(j_common_ptr cinfo) | |||
1070 | { | |||
1071 | t42_decode_state_t *s; | |||
1072 | ||||
1073 | s = (t42_decode_state_t *) cinfo->client_data; | |||
1074 | (*cinfo->err->format_message)(cinfo, s->error_message); | |||
1075 | longjmp(s->escape, 1); | |||
1076 | } | |||
1077 | /*- End of function --------------------------------------------------------*/ | |||
1078 | ||||
1079 | /* This is the error catcher */ | |||
1080 | static struct jpeg_error_mgr decode_error_handler = | |||
1081 | { | |||
1082 | #if defined(_MSC_VER) || defined(__sunos) || defined(__solaris) || defined(__sun) | |||
1083 | jpg_decode_error_exit, | |||
1084 | 0, | |||
1085 | jpg_decode_error_exit | |||
1086 | #else | |||
1087 | .error_exit = jpg_decode_error_exit, | |||
1088 | .output_message = jpg_decode_error_exit | |||
1089 | #endif | |||
1090 | }; | |||
1091 | ||||
1092 | static int t42_itulab_jpeg_to_srgb(t42_decode_state_t *s) | |||
1093 | { | |||
1094 | int i; | |||
1095 | ||||
1096 | if (s->compressed_buf == NULL((void*)0)) | |||
1097 | return -1; | |||
1098 | ||||
1099 | #if defined(HAVE_OPEN_MEMSTREAM1) | |||
1100 | if ((s->in = fmemopen(s->compressed_buf, s->compressed_image_size, "r")) == NULL((void*)0)) | |||
1101 | { | |||
1102 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); | |||
1103 | return -1; | |||
1104 | } | |||
1105 | #else | |||
1106 | if ((s->in = tmpfile()) == NULL((void*)0)) | |||
1107 | { | |||
1108 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); | |||
1109 | return -1; | |||
1110 | } | |||
1111 | if (fwrite(s->compressed_buf, 1, s->compressed_image_size, s->in) != s->compressed_image_size) | |||
1112 | { | |||
1113 | fclose(s->in); | |||
1114 | s->in = NULL((void*)0); | |||
1115 | return -1; | |||
1116 | } | |||
1117 | if (fseek(s->in, 0, SEEK_SET0) != 0) | |||
1118 | { | |||
1119 | fclose(s->in); | |||
1120 | s->in = NULL((void*)0); | |||
1121 | return -1; | |||
1122 | } | |||
1123 | #endif | |||
1124 | s->scan_line_out = NULL((void*)0); | |||
1125 | ||||
1126 | if (setjmp(s->escape)_setjmp (s->escape)) | |||
1127 | { | |||
1128 | if (s->error_message[0]) | |||
1129 | span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", s->error_message); | |||
1130 | else | |||
1131 | span_log(&s->logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); | |||
1132 | if (s->scan_line_out) | |||
1133 | { | |||
1134 | span_free(s->scan_line_out); | |||
1135 | s->scan_line_out = NULL((void*)0); | |||
1136 | } | |||
1137 | if (s->in) | |||
1138 | { | |||
1139 | fclose(s->in); | |||
1140 | s->in = NULL((void*)0); | |||
1141 | } | |||
1142 | return -1; | |||
1143 | } | |||
1144 | /* Create input decompressor. */ | |||
1145 | s->decompressor.err = jpeg_std_error(&decode_error_handler); | |||
1146 | s->decompressor.client_data = (void *) s; | |||
1147 | ||||
1148 | jpeg_create_decompress(&s->decompressor)jpeg_CreateDecompress((&s->decompressor), 62, (size_t) sizeof(struct jpeg_decompress_struct)); | |||
1149 | jpeg_stdio_src(&s->decompressor, s->in); | |||
1150 | ||||
1151 | /* Get the FAX tags */ | |||
1152 | for (i = 0; i < 16; i++) | |||
1153 | jpeg_save_markers(&s->decompressor, JPEG_APP00xE0 + i, 0xFFFF); | |||
1154 | ||||
1155 | /* Take the header */ | |||
1156 | jpeg_read_header(&s->decompressor, false0); | |||
1157 | /* Sanity check and parameter check */ | |||
1158 | if (!is_itu_fax(s, s->decompressor.marker_list)) | |||
1159 | { | |||
1160 | span_log(&s->logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n"); | |||
1161 | return -1; | |||
1162 | } | |||
1163 | /* Copy size, resolution, etc */ | |||
1164 | s->image_width = s->decompressor.image_width; | |||
1165 | s->image_length = s->decompressor.image_height; | |||
1166 | s->samples_per_pixel = s->decompressor.num_components; | |||
1167 | ||||
1168 | if (s->samples_per_pixel == 3) | |||
1169 | { | |||
1170 | /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ | |||
1171 | s->decompressor.out_color_space = JCS_YCbCr; | |||
1172 | span_log(&s->logging, | |||
1173 | SPAN_LOG_FLOW, | |||
1174 | "Sampling %d %d %d %d %d %d\n", | |||
1175 | s->decompressor.comp_info[0].h_samp_factor, | |||
1176 | s->decompressor.comp_info[0].v_samp_factor, | |||
1177 | s->decompressor.comp_info[1].h_samp_factor, | |||
1178 | s->decompressor.comp_info[1].v_samp_factor, | |||
1179 | s->decompressor.comp_info[2].h_samp_factor, | |||
1180 | s->decompressor.comp_info[2].v_samp_factor); | |||
1181 | } | |||
1182 | else | |||
1183 | { | |||
1184 | s->decompressor.out_color_space = JCS_GRAYSCALE; | |||
1185 | span_log(&s->logging, | |||
1186 | SPAN_LOG_FLOW, | |||
1187 | "Sampling %d %d\n", | |||
1188 | s->decompressor.comp_info[0].h_samp_factor, | |||
1189 | s->decompressor.comp_info[0].v_samp_factor); | |||
1190 | } | |||
1191 | ||||
1192 | jpeg_start_decompress(&s->decompressor); | |||
1193 | ||||
1194 | if ((s->scan_line_in = span_alloc(s->samples_per_pixel*s->image_width)) == NULL((void*)0)) | |||
1195 | return -1; | |||
1196 | ||||
1197 | if (s->samples_per_pixel == 3) | |||
1198 | { | |||
1199 | if ((s->scan_line_out = span_alloc(s->samples_per_pixel*s->image_width)) == NULL((void*)0)) | |||
1200 | return -1; | |||
1201 | ||||
1202 | while (s->decompressor.output_scanline < s->image_length) | |||
1203 | { | |||
1204 | jpeg_read_scanlines(&s->decompressor, &s->scan_line_in, 1); | |||
1205 | lab_to_srgb(&s->lab, s->scan_line_out, s->scan_line_in, s->image_width); | |||
1206 | s->row_write_handler(s->row_write_user_data, s->scan_line_out, s->samples_per_pixel*s->image_width); | |||
1207 | } | |||
1208 | } | |||
1209 | else | |||
1210 | { | |||
1211 | while (s->decompressor.output_scanline < s->image_length) | |||
1212 | { | |||
1213 | jpeg_read_scanlines(&s->decompressor, &s->scan_line_in, 1); | |||
1214 | s->row_write_handler(s->row_write_user_data, s->scan_line_in, s->image_width); | |||
1215 | } | |||
1216 | } | |||
1217 | ||||
1218 | if (s->scan_line_in) | |||
1219 | { | |||
1220 | span_free(s->scan_line_in); | |||
1221 | s->scan_line_in = NULL((void*)0); | |||
1222 | } | |||
1223 | if (s->scan_line_out) | |||
1224 | { | |||
1225 | span_free(s->scan_line_out); | |||
1226 | s->scan_line_out = NULL((void*)0); | |||
1227 | } | |||
1228 | jpeg_finish_decompress(&s->decompressor); | |||
1229 | jpeg_destroy_decompress(&s->decompressor); | |||
1230 | fclose(s->in); | |||
1231 | s->in = NULL((void*)0); | |||
1232 | ||||
1233 | return 0; | |||
1234 | } | |||
1235 | /*- End of function --------------------------------------------------------*/ | |||
1236 | ||||
1237 | SPAN_DECLARE(void)__attribute__((visibility("default"))) void t42_decode_rx_status(t42_decode_state_t *s, int status) | |||
1238 | { | |||
1239 | span_log(&s->logging, SPAN_LOG_FLOW, "Signal status is %s (%d)\n", signal_status_to_str(status), status); | |||
1240 | switch (status) | |||
1241 | { | |||
1242 | case SIG_STATUS_TRAINING_IN_PROGRESS: | |||
1243 | case SIG_STATUS_TRAINING_FAILED: | |||
1244 | case SIG_STATUS_TRAINING_SUCCEEDED: | |||
1245 | case SIG_STATUS_CARRIER_UP: | |||
1246 | /* Ignore these */ | |||
1247 | break; | |||
1248 | case SIG_STATUS_CARRIER_DOWN: | |||
1249 | case SIG_STATUS_END_OF_DATA: | |||
1250 | /* Finalise the image */ | |||
1251 | if (!s->end_of_data) | |||
1252 | { | |||
1253 | if (t42_itulab_jpeg_to_srgb(s)) | |||
1254 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n"); | |||
1255 | s->end_of_data = true1; | |||
1256 | } | |||
1257 | break; | |||
1258 | default: | |||
1259 | span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected rx status - %d!\n", status); | |||
1260 | break; | |||
1261 | } | |||
1262 | } | |||
1263 | /*- End of function --------------------------------------------------------*/ | |||
1264 | ||||
1265 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_put(t42_decode_state_t *s, const uint8_t data[], size_t len) | |||
1266 | { | |||
1267 | uint8_t *buf; | |||
1268 | ||||
1269 | if (len == 0) | |||
1270 | { | |||
1271 | if (!s->end_of_data) | |||
1272 | { | |||
1273 | if (t42_itulab_jpeg_to_srgb(s)) | |||
1274 | span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n"); | |||
1275 | s->end_of_data = true1; | |||
1276 | } | |||
1277 | return T4_DECODE_OK; | |||
1278 | } | |||
1279 | ||||
1280 | if (s->compressed_image_size + len > s->buf_size) | |||
1281 | { | |||
1282 | if ((buf = (uint8_t *) span_realloc(s->compressed_buf, s->compressed_image_size + len + 10000)) == NULL((void*)0)) | |||
1283 | return -1; | |||
1284 | s->buf_size = s->compressed_image_size + len + 10000; | |||
1285 | s->compressed_buf = buf; | |||
1286 | } | |||
1287 | memcpy(&s->compressed_buf[s->compressed_image_size], data, len); | |||
1288 | s->compressed_image_size += len; | |||
1289 | return 0; | |||
1290 | } | |||
1291 | /*- End of function --------------------------------------------------------*/ | |||
1292 | ||||
1293 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_set_row_write_handler(t42_decode_state_t *s, | |||
1294 | t4_row_write_handler_t handler, | |||
1295 | void *user_data) | |||
1296 | { | |||
1297 | s->row_write_handler = handler; | |||
1298 | s->row_write_user_data = user_data; | |||
1299 | return 0; | |||
1300 | } | |||
1301 | /*- End of function --------------------------------------------------------*/ | |||
1302 | ||||
1303 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_set_comment_handler(t42_decode_state_t *s, | |||
1304 | uint32_t max_comment_len, | |||
1305 | t4_row_write_handler_t handler, | |||
1306 | void *user_data) | |||
1307 | { | |||
1308 | s->max_comment_len = max_comment_len; | |||
1309 | s->comment_handler = handler; | |||
1310 | s->comment_user_data = user_data; | |||
1311 | return 0; | |||
1312 | } | |||
1313 | /*- End of function --------------------------------------------------------*/ | |||
1314 | ||||
1315 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_set_image_size_constraints(t42_decode_state_t *s, | |||
1316 | uint32_t max_xd, | |||
1317 | uint32_t max_yd) | |||
1318 | { | |||
1319 | return 0; | |||
1320 | } | |||
1321 | /*- End of function --------------------------------------------------------*/ | |||
1322 | ||||
1323 | SPAN_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t t42_decode_get_image_width(t42_decode_state_t *s) | |||
1324 | { | |||
1325 | return s->image_width; | |||
1326 | } | |||
1327 | /*- End of function --------------------------------------------------------*/ | |||
1328 | ||||
1329 | SPAN_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t t42_decode_get_image_length(t42_decode_state_t *s) | |||
1330 | { | |||
1331 | return s->image_length; | |||
1332 | } | |||
1333 | /*- End of function --------------------------------------------------------*/ | |||
1334 | ||||
1335 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_get_compressed_image_size(t42_decode_state_t *s) | |||
1336 | { | |||
1337 | return s->compressed_image_size; | |||
1338 | } | |||
1339 | /*- End of function --------------------------------------------------------*/ | |||
1340 | ||||
1341 | SPAN_DECLARE(logging_state_t *)__attribute__((visibility("default"))) logging_state_t * t42_decode_get_logging_state(t42_decode_state_t *s) | |||
1342 | { | |||
1343 | return &s->logging; | |||
1344 | } | |||
1345 | /*- End of function --------------------------------------------------------*/ | |||
1346 | ||||
1347 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_restart(t42_decode_state_t *s) | |||
1348 | { | |||
1349 | if (s->itu_ycc) | |||
1350 | { | |||
1351 | /* ITU-YCC */ | |||
1352 | /* Illuminant D65 */ | |||
1353 | //set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f); | |||
1354 | set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); | |||
1355 | set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false0); | |||
1356 | } | |||
1357 | else | |||
1358 | { | |||
1359 | /* ITULAB */ | |||
1360 | /* Illuminant D50 */ | |||
1361 | //set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f); | |||
1362 | set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); | |||
1363 | set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false0); | |||
1364 | } | |||
1365 | ||||
1366 | s->end_of_data = false0; | |||
1367 | s->compressed_image_size = 0; | |||
1368 | ||||
1369 | s->error_message[0] = '\0'; | |||
1370 | ||||
1371 | return 0; | |||
1372 | } | |||
1373 | /*- End of function --------------------------------------------------------*/ | |||
1374 | ||||
1375 | SPAN_DECLARE(t42_decode_state_t *)__attribute__((visibility("default"))) t42_decode_state_t * t42_decode_init(t42_decode_state_t *s, | |||
1376 | t4_row_write_handler_t handler, | |||
1377 | void *user_data) | |||
1378 | { | |||
1379 | if (s == NULL((void*)0)) | |||
1380 | { | |||
1381 | if ((s = (t42_decode_state_t *) span_alloc(sizeof(*s))) == NULL((void*)0)) | |||
1382 | return NULL((void*)0); | |||
1383 | } | |||
1384 | memset(s, 0, sizeof(*s)); | |||
1385 | span_log_init(&s->logging, SPAN_LOG_NONE, NULL((void*)0)); | |||
1386 | span_log_set_protocol(&s->logging, "T.42"); | |||
1387 | ||||
1388 | s->row_write_handler = handler; | |||
1389 | s->row_write_user_data = user_data; | |||
1390 | ||||
1391 | s->buf_size = 0; | |||
1392 | s->compressed_buf = NULL((void*)0); | |||
1393 | ||||
1394 | t42_decode_restart(s); | |||
1395 | ||||
1396 | return s; | |||
1397 | } | |||
1398 | /*- End of function --------------------------------------------------------*/ | |||
1399 | ||||
1400 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_release(t42_decode_state_t *s) | |||
1401 | { | |||
1402 | if (s->scan_line_in) | |||
1403 | { | |||
1404 | span_free(s->scan_line_in); | |||
1405 | s->scan_line_in = NULL((void*)0); | |||
1406 | } | |||
1407 | if (s->scan_line_out) | |||
1408 | { | |||
1409 | span_free(s->scan_line_out); | |||
1410 | s->scan_line_out = NULL((void*)0); | |||
1411 | } | |||
1412 | jpeg_destroy_decompress(&s->decompressor); | |||
1413 | if (s->in) | |||
1414 | { | |||
1415 | fclose(s->in); | |||
1416 | s->in = NULL((void*)0); | |||
1417 | } | |||
1418 | if (s->comment) | |||
1419 | { | |||
1420 | span_free(s->comment); | |||
1421 | s->comment = NULL((void*)0); | |||
1422 | } | |||
1423 | return 0; | |||
1424 | } | |||
1425 | /*- End of function --------------------------------------------------------*/ | |||
1426 | ||||
1427 | SPAN_DECLARE(int)__attribute__((visibility("default"))) int t42_decode_free(t42_decode_state_t *s) | |||
1428 | { | |||
1429 | int ret; | |||
1430 | ||||
1431 | ret = t42_decode_release(s); | |||
1432 | span_free(s); | |||
1433 | return ret; | |||
1434 | } | |||
1435 | /*- End of function --------------------------------------------------------*/ | |||
1436 | /*- End of file ------------------------------------------------------------*/ |