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