Line data Source code
1 : /*
2 : * Copyright (c) 1996-1997 Sam Leffler
3 : * Copyright (c) 1996 Pixar
4 : *
5 : * Permission to use, copy, modify, distribute, and sell this software and
6 : * its documentation for any purpose is hereby granted without fee, provided
7 : * that (i) the above copyright notices and this permission notice appear in
8 : * all copies of the software and related documentation, and (ii) the names of
9 : * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or
10 : * publicity relating to the software without the specific, prior written
11 : * permission of Pixar, Sam Leffler and Silicon Graphics.
12 : *
13 : * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14 : * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 : * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 : *
17 : * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18 : * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 : * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 : * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 : * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 : * OF THIS SOFTWARE.
23 : */
24 :
25 : #include "tiffiop.h"
26 : #ifdef PIXARLOG_SUPPORT
27 :
28 : /*
29 : * TIFF Library.
30 : * PixarLog Compression Support
31 : *
32 : * Contributed by Dan McCoy.
33 : *
34 : * PixarLog film support uses the TIFF library to store companded
35 : * 11 bit values into a tiff file, which are compressed using the
36 : * zip compressor.
37 : *
38 : * The codec can take as input and produce as output 32-bit IEEE float values
39 : * as well as 16-bit or 8-bit unsigned integer values.
40 : *
41 : * On writing any of the above are converted into the internal
42 : * 11-bit log format. In the case of 8 and 16 bit values, the
43 : * input is assumed to be unsigned linear color values that represent
44 : * the range 0-1. In the case of IEEE values, the 0-1 range is assumed to
45 : * be the normal linear color range, in addition over 1 values are
46 : * accepted up to a value of about 25.0 to encode "hot" highlights and such.
47 : * The encoding is lossless for 8-bit values, slightly lossy for the
48 : * other bit depths. The actual color precision should be better
49 : * than the human eye can perceive with extra room to allow for
50 : * error introduced by further image computation. As with any quantized
51 : * color format, it is possible to perform image calculations which
52 : * expose the quantization error. This format should certainly be less
53 : * susceptible to such errors than standard 8-bit encodings, but more
54 : * susceptible than straight 16-bit or 32-bit encodings.
55 : *
56 : * On reading the internal format is converted to the desired output format.
57 : * The program can request which format it desires by setting the internal
58 : * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values:
59 : * PIXARLOGDATAFMT_FLOAT = provide IEEE float values.
60 : * PIXARLOGDATAFMT_16BIT = provide unsigned 16-bit integer values
61 : * PIXARLOGDATAFMT_8BIT = provide unsigned 8-bit integer values
62 : *
63 : * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer
64 : * values with the difference that if there are exactly three or four channels
65 : * (rgb or rgba) it swaps the channel order (bgr or abgr).
66 : *
67 : * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly
68 : * packed in 16-bit values. However no tools are supplied for interpreting
69 : * these values.
70 : *
71 : * "hot" (over 1.0) areas written in floating point get clamped to
72 : * 1.0 in the integer data types.
73 : *
74 : * When the file is closed after writing, the bit depth and sample format
75 : * are set always to appear as if 8-bit data has been written into it.
76 : * That way a naive program unaware of the particulars of the encoding
77 : * gets the format it is most likely able to handle.
78 : *
79 : * The codec does it's own horizontal differencing step on the coded
80 : * values so the libraries predictor stuff should be turned off.
81 : * The codec also handle byte swapping the encoded values as necessary
82 : * since the library does not have the information necessary
83 : * to know the bit depth of the raw unencoded buffer.
84 : *
85 : * NOTE: This decoder does not appear to update tif_rawcp, and tif_rawcc.
86 : * This can cause problems with the implementation of CHUNKY_STRIP_READ_SUPPORT
87 : * as noted in http://trac.osgeo.org/gdal/ticket/3894. FrankW - Jan'11
88 : */
89 :
90 : #include "tif_predict.h"
91 : #include "zlib.h"
92 :
93 : #include <math.h>
94 : #include <stdio.h>
95 : #include <stdlib.h>
96 :
97 : /* Tables for converting to/from 11 bit coded values */
98 :
99 : #define TSIZE 2048 /* decode table size (11-bit tokens) */
100 : #define TSIZEP1 2049 /* Plus one for slop */
101 : #define ONE 1250 /* token value of 1.0 exactly */
102 : #define RATIO 1.004 /* nominal ratio for log part */
103 :
104 : #define CODE_MASK 0x7ff /* 11 bits. */
105 :
106 : static float Fltsize;
107 : static float LogK1, LogK2;
108 :
109 : #define REPEAT(n, op) \
110 : { \
111 : int i; \
112 : i = n; \
113 : do \
114 : { \
115 : i--; \
116 : op; \
117 : } while (i > 0); \
118 : }
119 :
120 : /*
121 : * PIXARLOGDATAFMT_* buffers are application-facing user data buffers in
122 : * native byte order. Use fixed-size memcpy() calls directly so optimizing
123 : * compilers can expand them in these per-sample paths while callers remain
124 : * free to provide unaligned public buffers. _TIFFmemcpy() is an out-of-line
125 : * wrapper in non-LTO builds.
126 : */
127 0 : static float PixarLogLoadFloatNativeUnaligned(const uint8_t *cp)
128 : {
129 : float v;
130 0 : memcpy(&v, cp, sizeof(v));
131 0 : return v;
132 : }
133 :
134 0 : static void PixarLogStoreFloatNativeUnaligned(uint8_t *cp, float v)
135 : {
136 0 : memcpy(cp, &v, sizeof(v));
137 0 : }
138 :
139 0 : static uint16_t PixarLogLoad16NativeUnaligned(const uint8_t *cp)
140 : {
141 : uint16_t v;
142 0 : memcpy(&v, cp, sizeof(v));
143 0 : return v;
144 : }
145 :
146 0 : static void PixarLogStore16NativeUnaligned(uint8_t *cp, uint16_t v)
147 : {
148 0 : memcpy(cp, &v, sizeof(v));
149 0 : }
150 :
151 0 : static void horizontalAccumulateF(uint16_t *wp, tmsize_t n, int stride,
152 : uint8_t *op, float *ToLinearF)
153 : {
154 : unsigned int cr, cg, cb, ca, mask;
155 : float t0, t1, t2, t3;
156 :
157 0 : if (n >= stride)
158 : {
159 0 : mask = CODE_MASK;
160 0 : if (stride == 3)
161 : {
162 0 : t0 = ToLinearF[cr = (wp[0] & mask)];
163 0 : t1 = ToLinearF[cg = (wp[1] & mask)];
164 0 : t2 = ToLinearF[cb = (wp[2] & mask)];
165 0 : PixarLogStoreFloatNativeUnaligned(op, t0);
166 0 : PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
167 0 : PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
168 0 : n -= 3;
169 0 : while (n > 0)
170 : {
171 0 : wp += 3;
172 0 : op += 3 * sizeof(float);
173 0 : n -= 3;
174 0 : t0 = ToLinearF[(cr += wp[0]) & mask];
175 0 : t1 = ToLinearF[(cg += wp[1]) & mask];
176 0 : t2 = ToLinearF[(cb += wp[2]) & mask];
177 0 : PixarLogStoreFloatNativeUnaligned(op, t0);
178 0 : PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
179 0 : PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
180 : }
181 : }
182 0 : else if (stride == 4)
183 : {
184 0 : t0 = ToLinearF[cr = (wp[0] & mask)];
185 0 : t1 = ToLinearF[cg = (wp[1] & mask)];
186 0 : t2 = ToLinearF[cb = (wp[2] & mask)];
187 0 : t3 = ToLinearF[ca = (wp[3] & mask)];
188 0 : PixarLogStoreFloatNativeUnaligned(op, t0);
189 0 : PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
190 0 : PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
191 0 : PixarLogStoreFloatNativeUnaligned(op + 3 * sizeof(float), t3);
192 0 : n -= 4;
193 0 : while (n > 0)
194 : {
195 0 : wp += 4;
196 0 : op += 4 * sizeof(float);
197 0 : n -= 4;
198 0 : t0 = ToLinearF[(cr += wp[0]) & mask];
199 0 : t1 = ToLinearF[(cg += wp[1]) & mask];
200 0 : t2 = ToLinearF[(cb += wp[2]) & mask];
201 0 : t3 = ToLinearF[(ca += wp[3]) & mask];
202 0 : PixarLogStoreFloatNativeUnaligned(op, t0);
203 0 : PixarLogStoreFloatNativeUnaligned(op + sizeof(float), t1);
204 0 : PixarLogStoreFloatNativeUnaligned(op + 2 * sizeof(float), t2);
205 0 : PixarLogStoreFloatNativeUnaligned(op + 3 * sizeof(float), t3);
206 : }
207 : }
208 : else
209 : {
210 0 : REPEAT(stride,
211 : PixarLogStoreFloatNativeUnaligned(op, ToLinearF[*wp & mask]);
212 : wp++; op += sizeof(float))
213 0 : n -= stride;
214 0 : while (n > 0)
215 : {
216 0 : REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
217 : PixarLogStoreFloatNativeUnaligned(op,
218 : ToLinearF[*wp & mask]);
219 : wp++; op += sizeof(float))
220 0 : n -= stride;
221 : }
222 : }
223 : }
224 0 : }
225 :
226 0 : static void horizontalAccumulate12(uint16_t *wp, tmsize_t n, int stride,
227 : uint8_t *op, float *ToLinearF)
228 : {
229 : unsigned int cr, cg, cb, ca, mask;
230 : float t0, t1, t2, t3;
231 :
232 : #define SCALE12 2048.0f
233 : #define CLAMP12(t) (((t) < 3071) ? (int16_t)(uint16_t)(t) : (int16_t)3071)
234 :
235 0 : if (n >= stride)
236 : {
237 0 : mask = CODE_MASK;
238 0 : if (stride == 3)
239 : {
240 0 : t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12;
241 0 : t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12;
242 0 : t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12;
243 0 : PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
244 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
245 0 : (uint16_t)CLAMP12(t1));
246 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
247 0 : (uint16_t)CLAMP12(t2));
248 0 : n -= 3;
249 0 : while (n > 0)
250 : {
251 0 : wp += 3;
252 0 : op += 3 * sizeof(uint16_t);
253 0 : n -= 3;
254 0 : t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
255 0 : t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
256 0 : t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
257 0 : PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
258 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
259 0 : (uint16_t)CLAMP12(t1));
260 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
261 0 : (uint16_t)CLAMP12(t2));
262 : }
263 : }
264 0 : else if (stride == 4)
265 : {
266 0 : t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12;
267 0 : t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12;
268 0 : t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12;
269 0 : t3 = ToLinearF[ca = (wp[3] & mask)] * SCALE12;
270 0 : PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
271 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
272 0 : (uint16_t)CLAMP12(t1));
273 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
274 0 : (uint16_t)CLAMP12(t2));
275 0 : PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t),
276 0 : (uint16_t)CLAMP12(t3));
277 0 : n -= 4;
278 0 : while (n > 0)
279 : {
280 0 : wp += 4;
281 0 : op += 4 * sizeof(uint16_t);
282 0 : n -= 4;
283 0 : t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
284 0 : t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
285 0 : t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
286 0 : t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12;
287 0 : PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
288 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
289 0 : (uint16_t)CLAMP12(t1));
290 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
291 0 : (uint16_t)CLAMP12(t2));
292 0 : PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t),
293 0 : (uint16_t)CLAMP12(t3));
294 : }
295 : }
296 : else
297 : {
298 0 : REPEAT(stride, t0 = ToLinearF[*wp & mask] * SCALE12;
299 : PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
300 : wp++; op += sizeof(uint16_t))
301 0 : n -= stride;
302 0 : while (n > 0)
303 : {
304 0 : REPEAT(
305 : stride, *wp = (uint16_t)(*wp + wp[-stride]);
306 : t0 = ToLinearF[*wp & mask] * SCALE12;
307 : PixarLogStore16NativeUnaligned(op, (uint16_t)CLAMP12(t0));
308 : wp++; op += sizeof(uint16_t))
309 0 : n -= stride;
310 : }
311 : }
312 : }
313 0 : }
314 :
315 0 : static void horizontalAccumulate16(uint16_t *wp, tmsize_t n, int stride,
316 : uint8_t *op, uint16_t *ToLinear16)
317 : {
318 : unsigned int cr, cg, cb, ca, mask;
319 :
320 0 : if (n >= stride)
321 : {
322 0 : mask = CODE_MASK;
323 0 : if (stride == 3)
324 : {
325 0 : PixarLogStore16NativeUnaligned(op, ToLinear16[cr = (wp[0] & mask)]);
326 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
327 0 : ToLinear16[cg = (wp[1] & mask)]);
328 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
329 0 : ToLinear16[cb = (wp[2] & mask)]);
330 0 : n -= 3;
331 0 : while (n > 0)
332 : {
333 0 : wp += 3;
334 0 : op += 3 * sizeof(uint16_t);
335 0 : n -= 3;
336 0 : PixarLogStore16NativeUnaligned(
337 0 : op, ToLinear16[(cr += wp[0]) & mask]);
338 0 : PixarLogStore16NativeUnaligned(
339 0 : op + sizeof(uint16_t), ToLinear16[(cg += wp[1]) & mask]);
340 0 : PixarLogStore16NativeUnaligned(
341 : op + 2 * sizeof(uint16_t),
342 0 : ToLinear16[(cb += wp[2]) & mask]);
343 : }
344 : }
345 0 : else if (stride == 4)
346 : {
347 0 : PixarLogStore16NativeUnaligned(op, ToLinear16[cr = (wp[0] & mask)]);
348 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t),
349 0 : ToLinear16[cg = (wp[1] & mask)]);
350 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t),
351 0 : ToLinear16[cb = (wp[2] & mask)]);
352 0 : PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t),
353 0 : ToLinear16[ca = (wp[3] & mask)]);
354 0 : n -= 4;
355 0 : while (n > 0)
356 : {
357 0 : wp += 4;
358 0 : op += 4 * sizeof(uint16_t);
359 0 : n -= 4;
360 0 : PixarLogStore16NativeUnaligned(
361 0 : op, ToLinear16[(cr += wp[0]) & mask]);
362 0 : PixarLogStore16NativeUnaligned(
363 0 : op + sizeof(uint16_t), ToLinear16[(cg += wp[1]) & mask]);
364 0 : PixarLogStore16NativeUnaligned(
365 : op + 2 * sizeof(uint16_t),
366 0 : ToLinear16[(cb += wp[2]) & mask]);
367 0 : PixarLogStore16NativeUnaligned(
368 : op + 3 * sizeof(uint16_t),
369 0 : ToLinear16[(ca += wp[3]) & mask]);
370 : }
371 : }
372 : else
373 : {
374 0 : REPEAT(stride,
375 : PixarLogStore16NativeUnaligned(op, ToLinear16[*wp & mask]);
376 : wp++; op += sizeof(uint16_t))
377 0 : n -= stride;
378 0 : while (n > 0)
379 : {
380 0 : REPEAT(
381 : stride, *wp = (uint16_t)(*wp + wp[-stride]);
382 : PixarLogStore16NativeUnaligned(op, ToLinear16[*wp & mask]);
383 : wp++; op += sizeof(uint16_t))
384 0 : n -= stride;
385 : }
386 : }
387 : }
388 0 : }
389 :
390 : /*
391 : * Returns the log encoded 11-bit values with the horizontal
392 : * differencing undone.
393 : */
394 0 : static void horizontalAccumulate11(uint16_t *wp, tmsize_t n, int stride,
395 : uint8_t *op)
396 : {
397 : unsigned int cr, cg, cb, ca, mask;
398 :
399 0 : if (n >= stride)
400 : {
401 0 : mask = CODE_MASK;
402 0 : if (stride == 3)
403 : {
404 0 : PixarLogStore16NativeUnaligned(op, wp[0]);
405 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t), wp[1]);
406 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t), wp[2]);
407 0 : cr = wp[0];
408 0 : cg = wp[1];
409 0 : cb = wp[2];
410 0 : n -= 3;
411 0 : while (n > 0)
412 : {
413 0 : wp += 3;
414 0 : op += 3 * sizeof(uint16_t);
415 0 : n -= 3;
416 0 : PixarLogStore16NativeUnaligned(
417 0 : op, (uint16_t)((cr += wp[0]) & mask));
418 0 : PixarLogStore16NativeUnaligned(
419 0 : op + sizeof(uint16_t), (uint16_t)((cg += wp[1]) & mask));
420 0 : PixarLogStore16NativeUnaligned(
421 : op + 2 * sizeof(uint16_t),
422 0 : (uint16_t)((cb += wp[2]) & mask));
423 : }
424 : }
425 0 : else if (stride == 4)
426 : {
427 0 : PixarLogStore16NativeUnaligned(op, wp[0]);
428 0 : PixarLogStore16NativeUnaligned(op + sizeof(uint16_t), wp[1]);
429 0 : PixarLogStore16NativeUnaligned(op + 2 * sizeof(uint16_t), wp[2]);
430 0 : PixarLogStore16NativeUnaligned(op + 3 * sizeof(uint16_t), wp[3]);
431 0 : cr = wp[0];
432 0 : cg = wp[1];
433 0 : cb = wp[2];
434 0 : ca = wp[3];
435 0 : n -= 4;
436 0 : while (n > 0)
437 : {
438 0 : wp += 4;
439 0 : op += 4 * sizeof(uint16_t);
440 0 : n -= 4;
441 0 : PixarLogStore16NativeUnaligned(
442 0 : op, (uint16_t)((cr += wp[0]) & mask));
443 0 : PixarLogStore16NativeUnaligned(
444 0 : op + sizeof(uint16_t), (uint16_t)((cg += wp[1]) & mask));
445 0 : PixarLogStore16NativeUnaligned(
446 : op + 2 * sizeof(uint16_t),
447 0 : (uint16_t)((cb += wp[2]) & mask));
448 0 : PixarLogStore16NativeUnaligned(
449 : op + 3 * sizeof(uint16_t),
450 0 : (uint16_t)((ca += wp[3]) & mask));
451 : }
452 : }
453 : else
454 : {
455 0 : REPEAT(stride,
456 : PixarLogStore16NativeUnaligned(op, (uint16_t)(*wp & mask));
457 : wp++; op += sizeof(uint16_t))
458 0 : n -= stride;
459 0 : while (n > 0)
460 : {
461 0 : REPEAT(
462 : stride, *wp = (uint16_t)(*wp + wp[-stride]);
463 : PixarLogStore16NativeUnaligned(op, (uint16_t)(*wp & mask));
464 : wp++; op += sizeof(uint16_t))
465 0 : n -= stride;
466 : }
467 : }
468 : }
469 0 : }
470 :
471 0 : static void horizontalAccumulate8(uint16_t *wp, tmsize_t n, int stride,
472 : unsigned char *op, unsigned char *ToLinear8)
473 : {
474 : unsigned int cr, cg, cb, ca, mask;
475 :
476 0 : if (n >= stride)
477 : {
478 0 : mask = CODE_MASK;
479 0 : if (stride == 3)
480 : {
481 0 : op[0] = ToLinear8[cr = (wp[0] & mask)];
482 0 : op[1] = ToLinear8[cg = (wp[1] & mask)];
483 0 : op[2] = ToLinear8[cb = (wp[2] & mask)];
484 0 : n -= 3;
485 0 : while (n > 0)
486 : {
487 0 : n -= 3;
488 0 : wp += 3;
489 0 : op += 3;
490 0 : op[0] = ToLinear8[(cr += wp[0]) & mask];
491 0 : op[1] = ToLinear8[(cg += wp[1]) & mask];
492 0 : op[2] = ToLinear8[(cb += wp[2]) & mask];
493 : }
494 : }
495 0 : else if (stride == 4)
496 : {
497 0 : op[0] = ToLinear8[cr = (wp[0] & mask)];
498 0 : op[1] = ToLinear8[cg = (wp[1] & mask)];
499 0 : op[2] = ToLinear8[cb = (wp[2] & mask)];
500 0 : op[3] = ToLinear8[ca = (wp[3] & mask)];
501 0 : n -= 4;
502 0 : while (n > 0)
503 : {
504 0 : n -= 4;
505 0 : wp += 4;
506 0 : op += 4;
507 0 : op[0] = ToLinear8[(cr += wp[0]) & mask];
508 0 : op[1] = ToLinear8[(cg += wp[1]) & mask];
509 0 : op[2] = ToLinear8[(cb += wp[2]) & mask];
510 0 : op[3] = ToLinear8[(ca += wp[3]) & mask];
511 : }
512 : }
513 : else
514 : {
515 0 : REPEAT(stride, *op = ToLinear8[*wp & mask]; wp++; op++)
516 0 : n -= stride;
517 0 : while (n > 0)
518 : {
519 0 : REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
520 : *op = ToLinear8[*wp & mask]; wp++; op++)
521 0 : n -= stride;
522 : }
523 : }
524 : }
525 0 : }
526 :
527 0 : static void horizontalAccumulate8abgr(uint16_t *wp, tmsize_t n, int stride,
528 : unsigned char *op,
529 : unsigned char *ToLinear8)
530 : {
531 : unsigned int cr, cg, cb, ca, mask;
532 : unsigned char t0, t1, t2, t3;
533 :
534 0 : if (n >= stride)
535 : {
536 0 : mask = CODE_MASK;
537 0 : if (stride == 3)
538 : {
539 0 : op[0] = 0;
540 0 : t1 = ToLinear8[cb = (wp[2] & mask)];
541 0 : t2 = ToLinear8[cg = (wp[1] & mask)];
542 0 : t3 = ToLinear8[cr = (wp[0] & mask)];
543 0 : op[1] = t1;
544 0 : op[2] = t2;
545 0 : op[3] = t3;
546 0 : n -= 3;
547 0 : while (n > 0)
548 : {
549 0 : n -= 3;
550 0 : wp += 3;
551 0 : op += 4;
552 0 : op[0] = 0;
553 0 : t1 = ToLinear8[(cb += wp[2]) & mask];
554 0 : t2 = ToLinear8[(cg += wp[1]) & mask];
555 0 : t3 = ToLinear8[(cr += wp[0]) & mask];
556 0 : op[1] = t1;
557 0 : op[2] = t2;
558 0 : op[3] = t3;
559 : }
560 : }
561 0 : else if (stride == 4)
562 : {
563 0 : t0 = ToLinear8[ca = (wp[3] & mask)];
564 0 : t1 = ToLinear8[cb = (wp[2] & mask)];
565 0 : t2 = ToLinear8[cg = (wp[1] & mask)];
566 0 : t3 = ToLinear8[cr = (wp[0] & mask)];
567 0 : op[0] = t0;
568 0 : op[1] = t1;
569 0 : op[2] = t2;
570 0 : op[3] = t3;
571 0 : n -= 4;
572 0 : while (n > 0)
573 : {
574 0 : n -= 4;
575 0 : wp += 4;
576 0 : op += 4;
577 0 : t0 = ToLinear8[(ca += wp[3]) & mask];
578 0 : t1 = ToLinear8[(cb += wp[2]) & mask];
579 0 : t2 = ToLinear8[(cg += wp[1]) & mask];
580 0 : t3 = ToLinear8[(cr += wp[0]) & mask];
581 0 : op[0] = t0;
582 0 : op[1] = t1;
583 0 : op[2] = t2;
584 0 : op[3] = t3;
585 : }
586 : }
587 : else
588 : {
589 0 : REPEAT(stride, *op = ToLinear8[*wp & mask]; wp++; op++)
590 0 : n -= stride;
591 0 : while (n > 0)
592 : {
593 0 : REPEAT(stride, *wp = (uint16_t)(*wp + wp[-stride]);
594 : *op = ToLinear8[*wp & mask]; wp++; op++)
595 0 : n -= stride;
596 : }
597 : }
598 : }
599 0 : }
600 :
601 : /*
602 : * State block for each open TIFF
603 : * file using PixarLog compression/decompression.
604 : */
605 : typedef struct
606 : {
607 : TIFFPredictorState predict;
608 : z_stream stream;
609 : tmsize_t tbuf_size; /* only set/used on reading for now */
610 : uint16_t *tbuf;
611 : uint16_t stride;
612 : int state;
613 : int user_datafmt;
614 : int quality;
615 : #define PLSTATE_INIT 1
616 :
617 : TIFFVSetMethod vgetparent; /* super-class method */
618 : TIFFVSetMethod vsetparent; /* super-class method */
619 :
620 : float *ToLinearF;
621 : uint16_t *ToLinear16;
622 : unsigned char *ToLinear8;
623 : uint16_t *FromLT2;
624 : uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */
625 : uint16_t *From8;
626 :
627 : } PixarLogState;
628 :
629 0 : static int PixarLogMakeTables(TIFF *tif, PixarLogState *sp)
630 : {
631 :
632 : /*
633 : * We make several tables here to convert between various external
634 : * representations (float, 16-bit, and 8-bit) and the internal
635 : * 11-bit companded representation. The 11-bit representation has two
636 : * distinct regions. A linear bottom end up through .018316 in steps
637 : * of about .000073, and a region of constant ratio up to about 25.
638 : * These floating point numbers are stored in the main table ToLinearF.
639 : * All other tables are derived from this one. The tables (and the
640 : * ratios) are continuous at the internal seam.
641 : */
642 :
643 : int nlin, lt2size;
644 : int i, j;
645 : double b, c, linstep, v;
646 : float *ToLinearF;
647 : uint16_t *ToLinear16;
648 : unsigned char *ToLinear8;
649 : uint16_t *FromLT2;
650 : uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */
651 : uint16_t *From8;
652 :
653 0 : c = log(RATIO);
654 0 : nlin = (int)(1. / c); /* nlin must be an integer */
655 0 : c = 1. / nlin;
656 0 : b = exp(-c * ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */
657 0 : linstep = b * c * exp(1.);
658 :
659 0 : LogK1 = (float)(1. / c); /* if (v >= 2) token = k1*log(v*k2) */
660 0 : LogK2 = (float)(1. / b);
661 0 : lt2size = (int)(2. / linstep) + 1;
662 0 : FromLT2 = (uint16_t *)_TIFFmallocExt(
663 0 : tif, (tmsize_t)((size_t)lt2size * sizeof(uint16_t)));
664 0 : From14 = (uint16_t *)_TIFFmallocExt(tif, 16384 * sizeof(uint16_t));
665 0 : From8 = (uint16_t *)_TIFFmallocExt(tif, 256 * sizeof(uint16_t));
666 0 : ToLinearF = (float *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(float));
667 0 : ToLinear16 = (uint16_t *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(uint16_t));
668 : ToLinear8 =
669 0 : (unsigned char *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(unsigned char));
670 0 : if (FromLT2 == NULL || From14 == NULL || From8 == NULL ||
671 0 : ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL)
672 : {
673 0 : if (FromLT2)
674 0 : _TIFFfreeExt(tif, FromLT2);
675 0 : if (From14)
676 0 : _TIFFfreeExt(tif, From14);
677 0 : if (From8)
678 0 : _TIFFfreeExt(tif, From8);
679 0 : if (ToLinearF)
680 0 : _TIFFfreeExt(tif, ToLinearF);
681 0 : if (ToLinear16)
682 0 : _TIFFfreeExt(tif, ToLinear16);
683 0 : if (ToLinear8)
684 0 : _TIFFfreeExt(tif, ToLinear8);
685 0 : sp->FromLT2 = NULL;
686 0 : sp->From14 = NULL;
687 0 : sp->From8 = NULL;
688 0 : sp->ToLinearF = NULL;
689 0 : sp->ToLinear16 = NULL;
690 0 : sp->ToLinear8 = NULL;
691 0 : return 0;
692 : }
693 :
694 0 : j = 0;
695 :
696 0 : for (i = 0; i < nlin; i++)
697 : {
698 0 : v = i * linstep;
699 0 : ToLinearF[j++] = (float)v;
700 : }
701 :
702 0 : for (i = nlin; i < TSIZE; i++)
703 0 : ToLinearF[j++] = (float)(b * exp(c * i));
704 :
705 0 : ToLinearF[2048] = ToLinearF[2047];
706 :
707 0 : for (i = 0; i < TSIZEP1; i++)
708 : {
709 0 : v = (double)ToLinearF[i] * 65535.0 + 0.5;
710 0 : ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16_t)v;
711 0 : v = (double)ToLinearF[i] * 255.0 + 0.5;
712 0 : ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v;
713 : }
714 :
715 0 : j = 0;
716 0 : for (i = 0; i < lt2size; i++)
717 : {
718 0 : if ((i * linstep) * (i * linstep) >
719 0 : (double)ToLinearF[j] * (double)ToLinearF[j + 1])
720 0 : j++;
721 0 : FromLT2[i] = (uint16_t)j;
722 : }
723 :
724 : /*
725 : * Since we lose info anyway on 16-bit data, we set up a 14-bit
726 : * table and shift 16-bit values down two bits on input.
727 : * saves a little table space.
728 : */
729 0 : j = 0;
730 0 : for (i = 0; i < 16384; i++)
731 : {
732 0 : while ((i / 16383.) * (i / 16383.) >
733 0 : (double)ToLinearF[j] * (double)ToLinearF[j + 1])
734 0 : j++;
735 0 : From14[i] = (uint16_t)j;
736 : }
737 :
738 0 : j = 0;
739 0 : for (i = 0; i < 256; i++)
740 : {
741 0 : while ((i / 255.) * (i / 255.) >
742 0 : (double)ToLinearF[j] * (double)ToLinearF[j + 1])
743 0 : j++;
744 0 : From8[i] = (uint16_t)j;
745 : }
746 :
747 0 : Fltsize = (float)(lt2size / 2);
748 :
749 0 : sp->ToLinearF = ToLinearF;
750 0 : sp->ToLinear16 = ToLinear16;
751 0 : sp->ToLinear8 = ToLinear8;
752 0 : sp->FromLT2 = FromLT2;
753 0 : sp->From14 = From14;
754 0 : sp->From8 = From8;
755 :
756 0 : return 1;
757 : }
758 :
759 : #define PixarLogDecoderState(tif) ((PixarLogState *)(tif)->tif_data)
760 : #define PixarLogEncoderState(tif) ((PixarLogState *)(tif)->tif_data)
761 :
762 : static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
763 : static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
764 :
765 : #define PIXARLOGDATAFMT_UNKNOWN -1
766 :
767 0 : static int PixarLogGuessDataFmt(TIFFDirectory *td)
768 : {
769 0 : int guess = PIXARLOGDATAFMT_UNKNOWN;
770 0 : int format = td->td_sampleformat;
771 :
772 : /* If the user didn't tell us his datafmt,
773 : * take our best guess from the bitspersample.
774 : */
775 0 : switch (td->td_bitspersample)
776 : {
777 0 : case 32:
778 0 : if (format == SAMPLEFORMAT_IEEEFP)
779 0 : guess = PIXARLOGDATAFMT_FLOAT;
780 0 : break;
781 0 : case 16:
782 0 : if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
783 0 : guess = PIXARLOGDATAFMT_16BIT;
784 0 : break;
785 0 : case 12:
786 0 : if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT)
787 0 : guess = PIXARLOGDATAFMT_12BITPICIO;
788 0 : break;
789 0 : case 11:
790 0 : if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
791 0 : guess = PIXARLOGDATAFMT_11BITLOG;
792 0 : break;
793 0 : case 8:
794 0 : if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
795 0 : guess = PIXARLOGDATAFMT_8BIT;
796 0 : break;
797 0 : default:
798 0 : break;
799 : }
800 :
801 0 : return guess;
802 : }
803 :
804 0 : static tmsize_t multiply_ms(tmsize_t m1, tmsize_t m2)
805 : {
806 0 : return _TIFFMultiplySSize(NULL, m1, m2, NULL);
807 : }
808 :
809 0 : static tmsize_t add_ms(tmsize_t m1, tmsize_t m2)
810 : {
811 0 : assert(m1 >= 0 && m2 >= 0);
812 : /* if either input is zero, assume overflow already occurred */
813 0 : if (m1 == 0 || m2 == 0)
814 0 : return 0;
815 0 : else if (m1 > TIFF_TMSIZE_T_MAX - m2)
816 0 : return 0;
817 :
818 0 : return m1 + m2;
819 : }
820 :
821 0 : static int PixarLogFixupTags(TIFF *tif)
822 : {
823 : (void)tif;
824 0 : return (1);
825 : }
826 :
827 0 : static int PixarLogSetupDecode(TIFF *tif)
828 : {
829 : static const char module[] = "PixarLogSetupDecode";
830 0 : TIFFDirectory *td = &tif->tif_dir;
831 0 : PixarLogState *sp = PixarLogDecoderState(tif);
832 : tmsize_t tbuf_size;
833 : uint32_t strip_height;
834 :
835 0 : assert(sp != NULL);
836 :
837 : /* This function can possibly be called several times by */
838 : /* PredictorSetupDecode() if this function succeeds but */
839 : /* PredictorSetup() fails */
840 0 : if ((sp->state & PLSTATE_INIT) != 0)
841 0 : return 1;
842 :
843 0 : strip_height = td->td_rowsperstrip;
844 0 : if (strip_height > td->td_imagelength)
845 0 : strip_height = td->td_imagelength;
846 :
847 : /* Make sure no byte swapping happens on the data
848 : * after decompression. */
849 0 : tif->tif_postdecode = _TIFFNoPostDecode;
850 :
851 : /* for some reason, we can't do this in TIFFInitPixarLog */
852 :
853 0 : sp->stride =
854 0 : (td->td_planarconfig == PLANARCONFIG_CONTIG ? td->td_samplesperpixel
855 : : 1);
856 0 : tbuf_size = multiply_ms(
857 0 : multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), strip_height),
858 : sizeof(uint16_t));
859 : /* add one more stride in case input ends mid-stride */
860 : tbuf_size =
861 0 : add_ms(tbuf_size, (tmsize_t)(sizeof(uint16_t) * (size_t)sp->stride));
862 0 : if (tbuf_size == 0)
863 0 : return (0); /* TODO: this is an error return without error report
864 : through TIFFErrorExt */
865 0 : sp->tbuf = (uint16_t *)_TIFFmallocExt(tif, tbuf_size);
866 0 : if (sp->tbuf == NULL)
867 0 : return (0);
868 0 : sp->tbuf_size = tbuf_size;
869 0 : if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
870 0 : sp->user_datafmt = PixarLogGuessDataFmt(td);
871 0 : if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
872 : {
873 0 : _TIFFfreeExt(tif, sp->tbuf);
874 0 : sp->tbuf = NULL;
875 0 : sp->tbuf_size = 0;
876 0 : TIFFErrorExtR(tif, module,
877 : "PixarLog compression can't handle bits depth/data "
878 : "format combination (depth: %" PRIu16 ")",
879 0 : td->td_bitspersample);
880 0 : return (0);
881 : }
882 :
883 0 : if (inflateInit(&sp->stream) != Z_OK)
884 : {
885 0 : _TIFFfreeExt(tif, sp->tbuf);
886 0 : sp->tbuf = NULL;
887 0 : sp->tbuf_size = 0;
888 0 : TIFFErrorExtR(tif, module, "%s",
889 0 : sp->stream.msg ? sp->stream.msg : "(null)");
890 0 : return (0);
891 : }
892 : else
893 : {
894 0 : sp->state |= PLSTATE_INIT;
895 0 : return (1);
896 : }
897 : }
898 :
899 : /*
900 : * Setup state for decoding a strip.
901 : */
902 0 : static int PixarLogPreDecode(TIFF *tif, uint16_t s)
903 : {
904 : static const char module[] = "PixarLogPreDecode";
905 0 : PixarLogState *sp = PixarLogDecoderState(tif);
906 :
907 : (void)s;
908 0 : assert(sp != NULL);
909 0 : sp->stream.next_in = tif->tif_rawdata;
910 : assert(sizeof(sp->stream.avail_in) == 4); /* if this assert gets raised,
911 : we need to simplify this code to reflect a ZLib that is likely updated
912 : to deal with 8byte memory sizes, though this code will respond
913 : appropriately even before we simplify it */
914 0 : sp->stream.avail_in = (uInt)tif->tif_rawcc;
915 0 : if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
916 : {
917 0 : TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
918 0 : return (0);
919 : }
920 0 : return (inflateReset(&sp->stream) == Z_OK);
921 : }
922 :
923 0 : static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
924 : {
925 : static const char module[] = "PixarLogDecode";
926 0 : TIFFDirectory *td = &tif->tif_dir;
927 0 : PixarLogState *sp = PixarLogDecoderState(tif);
928 : tmsize_t i;
929 : tmsize_t nsamples;
930 : tmsize_t llen;
931 : uint16_t *up;
932 :
933 0 : switch (sp->user_datafmt)
934 : {
935 0 : case PIXARLOGDATAFMT_FLOAT:
936 0 : nsamples = (tmsize_t)((uint64_t)occ /
937 : sizeof(float)); /* XXX float == 32 bits */
938 0 : break;
939 0 : case PIXARLOGDATAFMT_16BIT:
940 : case PIXARLOGDATAFMT_12BITPICIO:
941 : case PIXARLOGDATAFMT_11BITLOG:
942 0 : nsamples =
943 0 : (tmsize_t)((uint64_t)occ /
944 : sizeof(uint16_t)); /* XXX uint16_t == 16 bits */
945 0 : break;
946 0 : case PIXARLOGDATAFMT_8BIT:
947 : case PIXARLOGDATAFMT_8BITABGR:
948 0 : nsamples = occ;
949 0 : break;
950 0 : default:
951 0 : TIFFErrorExtR(tif, module,
952 : "%" PRIu16 " bit input not supported in PixarLog",
953 0 : td->td_bitspersample);
954 0 : memset(op, 0, (size_t)occ);
955 0 : return 0;
956 : }
957 :
958 : /* stride (≤ td_samplesperpixel, max 65535) × imagewidth: fits tmsize_t */
959 0 : llen = (tmsize_t)sp->stride * td->td_imagewidth;
960 :
961 : /* Fix: ABGR with stride=3 expands 3 samples to 4 output bytes per pixel */
962 0 : if (sp->user_datafmt == PIXARLOGDATAFMT_8BITABGR && sp->stride == 3)
963 : {
964 : /* imagewidth × 4: fits tmsize_t (imagewidth is uint32) */
965 0 : tmsize_t required = (tmsize_t)td->td_imagewidth * 4;
966 : tmsize_t max_rows;
967 : tmsize_t max_nsamples;
968 :
969 : /*
970 : * Ensure at least one expanded output row fits.
971 : */
972 0 : if (occ < required)
973 : {
974 0 : TIFFErrorExtR(tif, module,
975 : "Output buffer too small for PixarLog ABGR data");
976 0 : memset(op, 0, (size_t)occ);
977 0 : return (0);
978 : }
979 :
980 : /*
981 : * The caller-provided output buffer size must represent a whole
982 : * number of expanded ABGR scanlines.
983 : */
984 0 : if (occ % required)
985 : {
986 0 : TIFFErrorExtR(
987 : tif, module,
988 : "Fractional scanline not supported for PixarLog ABGR data");
989 0 : memset(op, 0, (size_t)occ);
990 0 : return (0);
991 : }
992 :
993 : /*
994 : * PixarLogDecode() may process multiple rows per call
995 : * (e.g. strip decoding). Limit nsamples so the total
996 : * output written by the loop below never exceeds occ.
997 : */
998 0 : max_rows = occ / required;
999 0 : max_nsamples = max_rows * llen;
1000 :
1001 0 : if (nsamples > max_nsamples)
1002 : {
1003 0 : TIFFErrorExtR(tif, module,
1004 : "Output buffer too small for PixarLog ABGR data");
1005 0 : memset(op, 0, (size_t)occ);
1006 0 : return (0);
1007 : }
1008 : }
1009 :
1010 : (void)s;
1011 0 : assert(sp != NULL);
1012 :
1013 0 : sp->stream.next_in = tif->tif_rawcp;
1014 0 : sp->stream.avail_in = (uInt)tif->tif_rawcc;
1015 :
1016 0 : sp->stream.next_out = (unsigned char *)sp->tbuf;
1017 : assert(sizeof(sp->stream.avail_out) == 4); /* if this assert gets raised,
1018 : we need to simplify this code to reflect a ZLib that is likely updated
1019 : to deal with 8byte memory sizes, though this code will respond
1020 : appropriately even before we simplify it */
1021 0 : sp->stream.avail_out = (uInt)((unsigned long)nsamples * sizeof(uint16_t));
1022 0 : if (sp->stream.avail_out != (unsigned long)nsamples * sizeof(uint16_t))
1023 : {
1024 0 : TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
1025 0 : memset(op, 0, (size_t)occ);
1026 0 : return (0);
1027 : }
1028 : /* Check that we will not fill more than what was allocated */
1029 0 : if ((tmsize_t)sp->stream.avail_out > sp->tbuf_size)
1030 : {
1031 0 : TIFFErrorExtR(tif, module, "sp->stream.avail_out > sp->tbuf_size");
1032 0 : memset(op, 0, (size_t)occ);
1033 0 : return (0);
1034 : }
1035 : do
1036 : {
1037 0 : int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
1038 0 : if (state == Z_STREAM_END)
1039 : {
1040 0 : break; /* XXX */
1041 : }
1042 0 : if (state == Z_DATA_ERROR)
1043 : {
1044 0 : TIFFErrorExtR(tif, module,
1045 : "Decoding error at scanline %" PRIu32 ", %s",
1046 : tif->tif_dir.td_row,
1047 0 : sp->stream.msg ? sp->stream.msg : "(null)");
1048 0 : memset(op, 0, (size_t)occ);
1049 0 : return (0);
1050 : }
1051 0 : if (state != Z_OK)
1052 : {
1053 0 : TIFFErrorExtR(tif, module, "ZLib error: %s",
1054 0 : sp->stream.msg ? sp->stream.msg : "(null)");
1055 0 : memset(op, 0, (size_t)occ);
1056 0 : return (0);
1057 : }
1058 0 : } while (sp->stream.avail_out > 0);
1059 :
1060 : /* hopefully, we got all the bytes we needed */
1061 0 : if (sp->stream.avail_out != 0)
1062 : {
1063 0 : TIFFErrorExtR(tif, module,
1064 : "Not enough data at scanline %" PRIu32
1065 : " (short %u bytes)",
1066 : tif->tif_dir.td_row, sp->stream.avail_out);
1067 0 : memset(op, 0, (size_t)occ);
1068 0 : return (0);
1069 : }
1070 :
1071 0 : tif->tif_rawcp = sp->stream.next_in;
1072 0 : tif->tif_rawcc = sp->stream.avail_in;
1073 :
1074 0 : up = sp->tbuf;
1075 : /* Swap bytes in the data if from a different endian machine. */
1076 0 : if (tif->tif_flags & TIFF_SWAB)
1077 0 : TIFFSwabArrayOfShort(up, nsamples);
1078 :
1079 : /*
1080 : * if llen is not an exact multiple of nsamples, the decode operation
1081 : * may overflow the output buffer, so truncate it enough to prevent
1082 : * that but still salvage as much data as possible.
1083 : */
1084 0 : if (nsamples % llen)
1085 : {
1086 0 : TIFFWarningExtR(tif, module,
1087 : "stride %" TIFF_SSIZE_FORMAT
1088 : " is not a multiple of sample count, "
1089 : "%" TIFF_SSIZE_FORMAT ", data truncated.",
1090 : llen, nsamples);
1091 0 : nsamples -= nsamples % llen;
1092 : }
1093 :
1094 0 : for (i = 0; i < nsamples; i += llen, up += llen)
1095 : {
1096 0 : switch (sp->user_datafmt)
1097 : {
1098 0 : case PIXARLOGDATAFMT_FLOAT:
1099 0 : horizontalAccumulateF(up, llen, sp->stride, op, sp->ToLinearF);
1100 0 : op += (unsigned long)llen * sizeof(float);
1101 0 : break;
1102 0 : case PIXARLOGDATAFMT_16BIT:
1103 0 : horizontalAccumulate16(up, llen, sp->stride, op,
1104 : sp->ToLinear16);
1105 0 : op += (unsigned long)llen * sizeof(uint16_t);
1106 0 : break;
1107 0 : case PIXARLOGDATAFMT_12BITPICIO:
1108 0 : horizontalAccumulate12(up, llen, sp->stride, op, sp->ToLinearF);
1109 0 : op += (unsigned long)llen * sizeof(int16_t);
1110 0 : break;
1111 0 : case PIXARLOGDATAFMT_11BITLOG:
1112 0 : horizontalAccumulate11(up, llen, sp->stride, op);
1113 0 : op += (unsigned long)llen * sizeof(uint16_t);
1114 0 : break;
1115 0 : case PIXARLOGDATAFMT_8BIT:
1116 0 : horizontalAccumulate8(up, llen, sp->stride, (unsigned char *)op,
1117 : sp->ToLinear8);
1118 0 : op += (unsigned long)llen * sizeof(unsigned char);
1119 0 : break;
1120 0 : case PIXARLOGDATAFMT_8BITABGR:
1121 0 : horizontalAccumulate8abgr(up, llen, sp->stride,
1122 : (unsigned char *)op, sp->ToLinear8);
1123 :
1124 : /* For stride == 3 (RGB), horizontalAccumulate8abgr expands to 4
1125 : * bytes/pixel (ABGR) */
1126 0 : if (sp->stride == 3)
1127 0 : op += (unsigned long)td->td_imagewidth * 4;
1128 : else
1129 0 : op += (unsigned long)llen * sizeof(unsigned char);
1130 0 : break;
1131 0 : default:
1132 0 : TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16,
1133 0 : td->td_bitspersample);
1134 0 : memset(op, 0, (size_t)occ);
1135 0 : return (0);
1136 : }
1137 : }
1138 :
1139 0 : return (1);
1140 : }
1141 :
1142 0 : static int PixarLogSetupEncode(TIFF *tif)
1143 : {
1144 : static const char module[] = "PixarLogSetupEncode";
1145 0 : TIFFDirectory *td = &tif->tif_dir;
1146 0 : PixarLogState *sp = PixarLogEncoderState(tif);
1147 : tmsize_t tbuf_size;
1148 :
1149 0 : assert(sp != NULL);
1150 :
1151 : /* for some reason, we can't do this in TIFFInitPixarLog */
1152 :
1153 0 : sp->stride =
1154 0 : (td->td_planarconfig == PLANARCONFIG_CONTIG ? td->td_samplesperpixel
1155 : : 1);
1156 : tbuf_size =
1157 0 : multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
1158 0 : td->td_rowsperstrip),
1159 : sizeof(uint16_t));
1160 0 : if (tbuf_size == 0)
1161 0 : return (0); /* TODO: this is an error return without error report
1162 : through TIFFErrorExt */
1163 0 : sp->tbuf = (uint16_t *)_TIFFmallocExt(tif, tbuf_size);
1164 0 : if (sp->tbuf == NULL)
1165 0 : return (0);
1166 0 : if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
1167 0 : sp->user_datafmt = PixarLogGuessDataFmt(td);
1168 0 : if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
1169 : {
1170 0 : TIFFErrorExtR(tif, module,
1171 : "PixarLog compression can't handle %" PRIu16
1172 : " bit linear encodings",
1173 0 : td->td_bitspersample);
1174 0 : return (0);
1175 : }
1176 :
1177 0 : if (deflateInit(&sp->stream, sp->quality) != Z_OK)
1178 : {
1179 0 : TIFFErrorExtR(tif, module, "%s",
1180 0 : sp->stream.msg ? sp->stream.msg : "(null)");
1181 0 : return (0);
1182 : }
1183 : else
1184 : {
1185 0 : sp->state |= PLSTATE_INIT;
1186 0 : return (1);
1187 : }
1188 : }
1189 :
1190 : /*
1191 : * Reset encoding state at the start of a strip.
1192 : */
1193 0 : static int PixarLogPreEncode(TIFF *tif, uint16_t s)
1194 : {
1195 : static const char module[] = "PixarLogPreEncode";
1196 0 : PixarLogState *sp = PixarLogEncoderState(tif);
1197 :
1198 : (void)s;
1199 0 : assert(sp != NULL);
1200 0 : sp->stream.next_out = tif->tif_rawdata;
1201 : assert(sizeof(sp->stream.avail_out) == 4); /* if this assert gets raised,
1202 : we need to simplify this code to reflect a ZLib that is likely updated
1203 : to deal with 8byte memory sizes, though this code will respond
1204 : appropriately even before we simplify it */
1205 0 : sp->stream.avail_out = (uInt)tif->tif_rawdatasize;
1206 0 : if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
1207 : {
1208 0 : TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
1209 0 : return (0);
1210 : }
1211 0 : return (deflateReset(&sp->stream) == Z_OK);
1212 : }
1213 :
1214 0 : static void horizontalDifferenceF(const uint8_t *ip, tmsize_t n, int stride,
1215 : uint16_t *wp, uint16_t *FromLT2)
1216 : {
1217 : int32_t r1, g1, b1, a1, r2, g2, b2, a2, mask;
1218 0 : float fltsize = Fltsize;
1219 :
1220 : #define CLAMP(v) \
1221 : ((v < (float)0.) ? 0 \
1222 : : (v < (float)2.) ? FromLT2[(int)(v * fltsize)] \
1223 : : (v > (float)24.2) \
1224 : ? 2047 \
1225 : : (double)LogK1 * log((double)v * (double)LogK2) + 0.5)
1226 :
1227 0 : mask = CODE_MASK;
1228 0 : if (n >= stride)
1229 : {
1230 0 : if (stride == 3)
1231 : {
1232 0 : r2 = wp[0] = (uint16_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
1233 0 : g2 = wp[1] = (uint16_t)CLAMP(
1234 : PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1235 0 : b2 = wp[2] = (uint16_t)CLAMP(
1236 : PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1237 0 : n -= 3;
1238 0 : while (n > 0)
1239 : {
1240 0 : n -= 3;
1241 0 : wp += 3;
1242 0 : ip += 3 * sizeof(float);
1243 0 : r1 = (int32_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
1244 0 : wp[0] = (uint16_t)((r1 - r2) & mask);
1245 0 : r2 = r1;
1246 0 : g1 = (int32_t)CLAMP(
1247 : PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1248 0 : wp[1] = (uint16_t)((g1 - g2) & mask);
1249 0 : g2 = g1;
1250 0 : b1 = (int32_t)CLAMP(
1251 : PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1252 0 : wp[2] = (uint16_t)((b1 - b2) & mask);
1253 0 : b2 = b1;
1254 : }
1255 : }
1256 0 : else if (stride == 4)
1257 : {
1258 0 : r2 = wp[0] = (uint16_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
1259 0 : g2 = wp[1] = (uint16_t)CLAMP(
1260 : PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1261 0 : b2 = wp[2] = (uint16_t)CLAMP(
1262 : PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1263 0 : a2 = wp[3] = (uint16_t)CLAMP(
1264 : PixarLogLoadFloatNativeUnaligned(ip + 3 * sizeof(float)));
1265 0 : n -= 4;
1266 0 : while (n > 0)
1267 : {
1268 0 : n -= 4;
1269 0 : wp += 4;
1270 0 : ip += 4 * sizeof(float);
1271 0 : r1 = (int32_t)CLAMP(PixarLogLoadFloatNativeUnaligned(ip));
1272 0 : wp[0] = (uint16_t)((r1 - r2) & mask);
1273 0 : r2 = r1;
1274 0 : g1 = (int32_t)CLAMP(
1275 : PixarLogLoadFloatNativeUnaligned(ip + sizeof(float)));
1276 0 : wp[1] = (uint16_t)((g1 - g2) & mask);
1277 0 : g2 = g1;
1278 0 : b1 = (int32_t)CLAMP(
1279 : PixarLogLoadFloatNativeUnaligned(ip + 2 * sizeof(float)));
1280 0 : wp[2] = (uint16_t)((b1 - b2) & mask);
1281 0 : b2 = b1;
1282 0 : a1 = (int32_t)CLAMP(
1283 : PixarLogLoadFloatNativeUnaligned(ip + 3 * sizeof(float)));
1284 0 : wp[3] = (uint16_t)((a1 - a2) & mask);
1285 0 : a2 = a1;
1286 : }
1287 : }
1288 : else
1289 : {
1290 0 : REPEAT(stride, wp[0] = (uint16_t)CLAMP(
1291 : PixarLogLoadFloatNativeUnaligned(ip));
1292 : wp++; ip += sizeof(float))
1293 0 : n -= stride;
1294 0 : while (n > 0)
1295 : {
1296 0 : REPEAT(
1297 : stride,
1298 : wp[0] =
1299 : (uint16_t)(((int32_t)CLAMP(
1300 : PixarLogLoadFloatNativeUnaligned(ip)) -
1301 : (int32_t)CLAMP(
1302 : PixarLogLoadFloatNativeUnaligned(
1303 : ip -
1304 : (tmsize_t)stride *
1305 : (tmsize_t)sizeof(float)))) &
1306 : mask);
1307 : wp++; ip += sizeof(float))
1308 0 : n -= stride;
1309 : }
1310 : }
1311 : }
1312 0 : }
1313 :
1314 0 : static void horizontalDifference16(const uint8_t *ip, tmsize_t n, int stride,
1315 : unsigned short *wp, uint16_t *From14)
1316 : {
1317 : int r1, g1, b1, a1, r2, g2, b2, a2, mask;
1318 :
1319 : /* assumption is unsigned pixel values */
1320 : #undef CLAMP
1321 : #define CLAMP(v) From14[(v) >> 2]
1322 :
1323 0 : mask = CODE_MASK;
1324 0 : if (n >= stride)
1325 : {
1326 0 : if (stride == 3)
1327 : {
1328 0 : r2 = wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
1329 0 : g2 = wp[1] =
1330 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
1331 0 : b2 = wp[2] =
1332 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
1333 0 : n -= 3;
1334 0 : while (n > 0)
1335 : {
1336 0 : n -= 3;
1337 0 : wp += 3;
1338 0 : ip += 3 * sizeof(uint16_t);
1339 0 : r1 = CLAMP(PixarLogLoad16NativeUnaligned(ip));
1340 0 : wp[0] = (uint16_t)((r1 - r2) & mask);
1341 0 : r2 = r1;
1342 0 : g1 =
1343 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
1344 0 : wp[1] = (uint16_t)((g1 - g2) & mask);
1345 0 : g2 = g1;
1346 0 : b1 = CLAMP(
1347 : PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
1348 0 : wp[2] = (uint16_t)((b1 - b2) & mask);
1349 0 : b2 = b1;
1350 : }
1351 : }
1352 0 : else if (stride == 4)
1353 : {
1354 0 : r2 = wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
1355 0 : g2 = wp[1] =
1356 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
1357 0 : b2 = wp[2] =
1358 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
1359 0 : a2 = wp[3] =
1360 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + 3 * sizeof(uint16_t)));
1361 0 : n -= 4;
1362 0 : while (n > 0)
1363 : {
1364 0 : n -= 4;
1365 0 : wp += 4;
1366 0 : ip += 4 * sizeof(uint16_t);
1367 0 : r1 = CLAMP(PixarLogLoad16NativeUnaligned(ip));
1368 0 : wp[0] = (uint16_t)((r1 - r2) & mask);
1369 0 : r2 = r1;
1370 0 : g1 =
1371 0 : CLAMP(PixarLogLoad16NativeUnaligned(ip + sizeof(uint16_t)));
1372 0 : wp[1] = (uint16_t)((g1 - g2) & mask);
1373 0 : g2 = g1;
1374 0 : b1 = CLAMP(
1375 : PixarLogLoad16NativeUnaligned(ip + 2 * sizeof(uint16_t)));
1376 0 : wp[2] = (uint16_t)((b1 - b2) & mask);
1377 0 : b2 = b1;
1378 0 : a1 = CLAMP(
1379 : PixarLogLoad16NativeUnaligned(ip + 3 * sizeof(uint16_t)));
1380 0 : wp[3] = (uint16_t)((a1 - a2) & mask);
1381 0 : a2 = a1;
1382 : }
1383 : }
1384 : else
1385 : {
1386 0 : REPEAT(stride, wp[0] = CLAMP(PixarLogLoad16NativeUnaligned(ip));
1387 : wp++; ip += sizeof(uint16_t))
1388 0 : n -= stride;
1389 0 : while (n > 0)
1390 : {
1391 0 : REPEAT(
1392 : stride,
1393 : wp[0] =
1394 : (uint16_t)((CLAMP(PixarLogLoad16NativeUnaligned(ip)) -
1395 : CLAMP(PixarLogLoad16NativeUnaligned(
1396 : ip - (tmsize_t)stride *
1397 : (tmsize_t)sizeof(uint16_t)))) &
1398 : mask);
1399 : wp++; ip += sizeof(uint16_t))
1400 0 : n -= stride;
1401 : }
1402 : }
1403 : }
1404 0 : }
1405 :
1406 0 : static void horizontalDifference8(unsigned char *ip, tmsize_t n, int stride,
1407 : unsigned short *wp, uint16_t *From8)
1408 : {
1409 : int r1, g1, b1, a1, r2, g2, b2, a2, mask;
1410 :
1411 : #undef CLAMP
1412 : #define CLAMP(v) (From8[(v)])
1413 :
1414 0 : mask = CODE_MASK;
1415 0 : if (n >= stride)
1416 : {
1417 0 : if (stride == 3)
1418 : {
1419 0 : r2 = wp[0] = CLAMP(ip[0]);
1420 0 : g2 = wp[1] = CLAMP(ip[1]);
1421 0 : b2 = wp[2] = CLAMP(ip[2]);
1422 0 : n -= 3;
1423 0 : while (n > 0)
1424 : {
1425 0 : n -= 3;
1426 0 : r1 = CLAMP(ip[3]);
1427 0 : wp[3] = (uint16_t)((r1 - r2) & mask);
1428 0 : r2 = r1;
1429 0 : g1 = CLAMP(ip[4]);
1430 0 : wp[4] = (uint16_t)((g1 - g2) & mask);
1431 0 : g2 = g1;
1432 0 : b1 = CLAMP(ip[5]);
1433 0 : wp[5] = (uint16_t)((b1 - b2) & mask);
1434 0 : b2 = b1;
1435 0 : wp += 3;
1436 0 : ip += 3;
1437 : }
1438 : }
1439 0 : else if (stride == 4)
1440 : {
1441 0 : r2 = wp[0] = CLAMP(ip[0]);
1442 0 : g2 = wp[1] = CLAMP(ip[1]);
1443 0 : b2 = wp[2] = CLAMP(ip[2]);
1444 0 : a2 = wp[3] = CLAMP(ip[3]);
1445 0 : n -= 4;
1446 0 : while (n > 0)
1447 : {
1448 0 : n -= 4;
1449 0 : r1 = CLAMP(ip[4]);
1450 0 : wp[4] = (uint16_t)((r1 - r2) & mask);
1451 0 : r2 = r1;
1452 0 : g1 = CLAMP(ip[5]);
1453 0 : wp[5] = (uint16_t)((g1 - g2) & mask);
1454 0 : g2 = g1;
1455 0 : b1 = CLAMP(ip[6]);
1456 0 : wp[6] = (uint16_t)((b1 - b2) & mask);
1457 0 : b2 = b1;
1458 0 : a1 = CLAMP(ip[7]);
1459 0 : wp[7] = (uint16_t)((a1 - a2) & mask);
1460 0 : a2 = a1;
1461 0 : wp += 4;
1462 0 : ip += 4;
1463 : }
1464 : }
1465 : else
1466 : {
1467 0 : REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++)
1468 0 : n -= stride;
1469 0 : while (n > 0)
1470 : {
1471 0 : REPEAT(stride,
1472 : wp[0] = (uint16_t)((CLAMP(ip[0]) - CLAMP(ip[-stride])) &
1473 : mask);
1474 : wp++; ip++)
1475 0 : n -= stride;
1476 : }
1477 : }
1478 : }
1479 0 : }
1480 :
1481 : /*
1482 : * Encode a chunk of pixels.
1483 : */
1484 0 : static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
1485 : {
1486 : static const char module[] = "PixarLogEncode";
1487 0 : TIFFDirectory *td = &tif->tif_dir;
1488 0 : PixarLogState *sp = PixarLogEncoderState(tif);
1489 : tmsize_t i;
1490 : tmsize_t n;
1491 : tmsize_t llen;
1492 : unsigned short *up;
1493 :
1494 : (void)s;
1495 :
1496 0 : switch (sp->user_datafmt)
1497 : {
1498 0 : case PIXARLOGDATAFMT_FLOAT:
1499 0 : n = (tmsize_t)((unsigned long)cc /
1500 : sizeof(float)); /* XXX float == 32 bits */
1501 0 : break;
1502 0 : case PIXARLOGDATAFMT_16BIT:
1503 : case PIXARLOGDATAFMT_12BITPICIO:
1504 : case PIXARLOGDATAFMT_11BITLOG:
1505 0 : n = (tmsize_t)((unsigned long)cc /
1506 : sizeof(uint16_t)); /* XXX uint16_t == 16 bits */
1507 0 : break;
1508 0 : case PIXARLOGDATAFMT_8BIT:
1509 : case PIXARLOGDATAFMT_8BITABGR:
1510 0 : n = cc;
1511 0 : break;
1512 0 : default:
1513 0 : TIFFErrorExtR(tif, module,
1514 : "%" PRIu16 " bit input not supported in PixarLog",
1515 0 : td->td_bitspersample);
1516 0 : return 0;
1517 : }
1518 :
1519 : /* stride (≤ td_samplesperpixel, max 65535) × imagewidth: fits tmsize_t */
1520 0 : llen = (tmsize_t)sp->stride * td->td_imagewidth;
1521 : /* Check against the number of elements (of size uint16_t) of sp->tbuf */
1522 : tmsize_t max_n =
1523 0 : _TIFFMultiplySSize(tif, (tmsize_t)td->td_rowsperstrip, llen, module);
1524 0 : if (max_n == 0 || n > max_n)
1525 : {
1526 0 : TIFFErrorExtR(tif, module, "Too many input bytes provided");
1527 0 : return 0;
1528 : }
1529 :
1530 0 : for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen)
1531 : {
1532 0 : switch (sp->user_datafmt)
1533 : {
1534 0 : case PIXARLOGDATAFMT_FLOAT:
1535 0 : horizontalDifferenceF(bp, llen, sp->stride, up, sp->FromLT2);
1536 0 : bp += (unsigned long)llen * sizeof(float);
1537 0 : break;
1538 0 : case PIXARLOGDATAFMT_16BIT:
1539 0 : horizontalDifference16(bp, llen, sp->stride, up, sp->From14);
1540 0 : bp += (unsigned long)llen * sizeof(uint16_t);
1541 0 : break;
1542 0 : case PIXARLOGDATAFMT_8BIT:
1543 0 : horizontalDifference8((unsigned char *)bp, llen, sp->stride, up,
1544 : sp->From8);
1545 0 : bp += (unsigned long)llen * sizeof(unsigned char);
1546 0 : break;
1547 0 : default:
1548 0 : TIFFErrorExtR(tif, module,
1549 : "%" PRIu16 " bit input not supported in PixarLog",
1550 0 : td->td_bitspersample);
1551 0 : return 0;
1552 : }
1553 : }
1554 :
1555 0 : sp->stream.next_in = (unsigned char *)sp->tbuf;
1556 : assert(sizeof(sp->stream.avail_in) == 4); /* if this assert gets raised,
1557 : we need to simplify this code to reflect a ZLib that is likely updated
1558 : to deal with 8byte memory sizes, though this code will respond
1559 : appropriately even before we simplify it */
1560 0 : sp->stream.avail_in = (uInt)((unsigned long)n * sizeof(uint16_t));
1561 0 : if ((sp->stream.avail_in / sizeof(uint16_t)) != (unsigned long)n)
1562 : {
1563 0 : TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
1564 0 : return (0);
1565 : }
1566 :
1567 : do
1568 : {
1569 0 : if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK)
1570 : {
1571 0 : TIFFErrorExtR(tif, module, "Encoder error: %s",
1572 0 : sp->stream.msg ? sp->stream.msg : "(null)");
1573 0 : return (0);
1574 : }
1575 0 : if (sp->stream.avail_out == 0)
1576 : {
1577 0 : tif->tif_rawcc = tif->tif_rawdatasize;
1578 0 : if (!TIFFFlushData1(tif))
1579 0 : return 0;
1580 0 : sp->stream.next_out = tif->tif_rawdata;
1581 0 : sp->stream.avail_out =
1582 0 : (uInt)tif
1583 0 : ->tif_rawdatasize; /* this is a safe typecast, as check is
1584 : made already in PixarLogPreEncode */
1585 : }
1586 0 : } while (sp->stream.avail_in > 0);
1587 0 : return (1);
1588 : }
1589 :
1590 : /*
1591 : * Finish off an encoded strip by flushing the last
1592 : * string and tacking on an End Of Information code.
1593 : */
1594 :
1595 0 : static int PixarLogPostEncode(TIFF *tif)
1596 : {
1597 : static const char module[] = "PixarLogPostEncode";
1598 0 : PixarLogState *sp = PixarLogEncoderState(tif);
1599 : int state;
1600 :
1601 0 : sp->stream.avail_in = 0;
1602 :
1603 : do
1604 : {
1605 0 : state = deflate(&sp->stream, Z_FINISH);
1606 0 : switch (state)
1607 : {
1608 0 : case Z_STREAM_END:
1609 : case Z_OK:
1610 0 : if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
1611 : {
1612 0 : tif->tif_rawcc =
1613 0 : tif->tif_rawdatasize - sp->stream.avail_out;
1614 0 : if (!TIFFFlushData1(tif))
1615 0 : return 0;
1616 0 : sp->stream.next_out = tif->tif_rawdata;
1617 0 : sp->stream.avail_out =
1618 0 : (uInt)tif->tif_rawdatasize; /* this is a safe typecast,
1619 : as check is made already
1620 : in PixarLogPreEncode */
1621 : }
1622 0 : break;
1623 0 : default:
1624 0 : TIFFErrorExtR(tif, module, "ZLib error: %s",
1625 0 : sp->stream.msg ? sp->stream.msg : "(null)");
1626 0 : return (0);
1627 : }
1628 0 : } while (state != Z_STREAM_END);
1629 0 : return (1);
1630 : }
1631 :
1632 0 : static void PixarLogClose(TIFF *tif)
1633 : {
1634 0 : PixarLogState *sp = (PixarLogState *)tif->tif_data;
1635 0 : TIFFDirectory *td = &tif->tif_dir;
1636 :
1637 0 : assert(sp != 0);
1638 : /* In a really sneaky (and really incorrect, and untruthful, and
1639 : * troublesome, and error-prone) maneuver that completely goes against
1640 : * the spirit of TIFF, and breaks TIFF, on close, we covertly
1641 : * modify both bitspersample and sampleformat in the directory to
1642 : * indicate 8-bit linear. This way, the decode "just works" even for
1643 : * readers that don't know about PixarLog, or how to set
1644 : * the PIXARLOGDATFMT pseudo-tag.
1645 : */
1646 :
1647 0 : if (sp->state & PLSTATE_INIT)
1648 : {
1649 : /* We test the state to avoid an issue such as in
1650 : * http://bugzilla.maptools.org/show_bug.cgi?id=2604
1651 : * What appends in that case is that the bitspersample is 1 and
1652 : * a TransferFunction is set. The size of the TransferFunction
1653 : * depends on 1<<bitspersample. So if we increase it, an access
1654 : * out of the buffer will happen at directory flushing.
1655 : * Another option would be to clear those targs.
1656 : */
1657 0 : td->td_bitspersample = 8;
1658 0 : td->td_sampleformat = SAMPLEFORMAT_UINT;
1659 : }
1660 0 : }
1661 :
1662 0 : static void PixarLogCleanup(TIFF *tif)
1663 : {
1664 0 : PixarLogState *sp = (PixarLogState *)tif->tif_data;
1665 :
1666 0 : assert(sp != 0);
1667 :
1668 0 : (void)TIFFPredictorCleanup(tif);
1669 :
1670 0 : tif->tif_tagmethods.vgetfield = sp->vgetparent;
1671 0 : tif->tif_tagmethods.vsetfield = sp->vsetparent;
1672 :
1673 0 : if (sp->FromLT2)
1674 0 : _TIFFfreeExt(tif, sp->FromLT2);
1675 0 : if (sp->From14)
1676 0 : _TIFFfreeExt(tif, sp->From14);
1677 0 : if (sp->From8)
1678 0 : _TIFFfreeExt(tif, sp->From8);
1679 0 : if (sp->ToLinearF)
1680 0 : _TIFFfreeExt(tif, sp->ToLinearF);
1681 0 : if (sp->ToLinear16)
1682 0 : _TIFFfreeExt(tif, sp->ToLinear16);
1683 0 : if (sp->ToLinear8)
1684 0 : _TIFFfreeExt(tif, sp->ToLinear8);
1685 0 : if (sp->state & PLSTATE_INIT)
1686 : {
1687 0 : if (tif->tif_mode == O_RDONLY)
1688 0 : inflateEnd(&sp->stream);
1689 : else
1690 0 : deflateEnd(&sp->stream);
1691 : }
1692 0 : if (sp->tbuf)
1693 0 : _TIFFfreeExt(tif, sp->tbuf);
1694 0 : _TIFFfreeExt(tif, sp);
1695 0 : tif->tif_data = NULL;
1696 :
1697 0 : _TIFFSetDefaultCompressionState(tif);
1698 0 : }
1699 :
1700 0 : static int PixarLogVSetField(TIFF *tif, uint32_t tag, va_list ap)
1701 : {
1702 : static const char module[] = "PixarLogVSetField";
1703 0 : PixarLogState *sp = (PixarLogState *)tif->tif_data;
1704 : int result;
1705 :
1706 0 : switch (tag)
1707 : {
1708 0 : case TIFFTAG_PIXARLOGQUALITY:
1709 0 : sp->quality = (int)va_arg(ap, int);
1710 0 : if (tif->tif_mode != O_RDONLY && (sp->state & PLSTATE_INIT))
1711 : {
1712 0 : if (deflateParams(&sp->stream, sp->quality,
1713 : Z_DEFAULT_STRATEGY) != Z_OK)
1714 : {
1715 0 : TIFFErrorExtR(tif, module, "ZLib error: %s",
1716 0 : sp->stream.msg ? sp->stream.msg : "(null)");
1717 0 : return (0);
1718 : }
1719 : }
1720 0 : return (1);
1721 0 : case TIFFTAG_PIXARLOGDATAFMT:
1722 0 : sp->user_datafmt = (int)va_arg(ap, int);
1723 : /* Tweak the TIFF header so that the rest of libtiff knows what
1724 : * size of data will be passed between app and library, and
1725 : * assume that the app knows what it is doing and is not
1726 : * confused by these header manipulations...
1727 : */
1728 0 : switch (sp->user_datafmt)
1729 : {
1730 0 : case PIXARLOGDATAFMT_8BIT:
1731 : case PIXARLOGDATAFMT_8BITABGR:
1732 0 : TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
1733 0 : TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
1734 0 : break;
1735 0 : case PIXARLOGDATAFMT_11BITLOG:
1736 0 : TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
1737 0 : TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
1738 0 : break;
1739 0 : case PIXARLOGDATAFMT_12BITPICIO:
1740 0 : TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
1741 0 : TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
1742 0 : break;
1743 0 : case PIXARLOGDATAFMT_16BIT:
1744 0 : TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
1745 0 : TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
1746 0 : break;
1747 0 : case PIXARLOGDATAFMT_FLOAT:
1748 0 : TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
1749 0 : TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT,
1750 : SAMPLEFORMAT_IEEEFP);
1751 0 : break;
1752 0 : default:
1753 0 : break;
1754 : }
1755 : /*
1756 : * Must recalculate sizes should bits/sample change.
1757 : */
1758 0 : tif->tif_dir.td_tilesize =
1759 0 : isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1);
1760 0 : tif->tif_dir.td_scanlinesize = TIFFScanlineSize(tif);
1761 0 : result = 1; /* NB: pseudo tag */
1762 0 : break;
1763 0 : default:
1764 0 : result = (*sp->vsetparent)(tif, tag, ap);
1765 : }
1766 0 : return (result);
1767 : }
1768 :
1769 0 : static int PixarLogVGetField(TIFF *tif, uint32_t tag, va_list ap)
1770 : {
1771 0 : PixarLogState *sp = (PixarLogState *)tif->tif_data;
1772 :
1773 0 : switch (tag)
1774 : {
1775 0 : case TIFFTAG_PIXARLOGQUALITY:
1776 0 : *va_arg(ap, int *) = sp->quality;
1777 0 : break;
1778 0 : case TIFFTAG_PIXARLOGDATAFMT:
1779 0 : *va_arg(ap, int *) = sp->user_datafmt;
1780 0 : break;
1781 0 : default:
1782 0 : return (*sp->vgetparent)(tif, tag, ap);
1783 : }
1784 0 : return (1);
1785 : }
1786 :
1787 : static const TIFFField pixarlogFields[] = {
1788 : {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO,
1789 : FALSE, FALSE, "", NULL},
1790 : {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO,
1791 : FALSE, FALSE, "", NULL}};
1792 :
1793 0 : static uint64_t PixarLogGetMaxCompressionRatio(TIFF *tif)
1794 : {
1795 : (void)tif;
1796 : /* cf https://zlib.net/zlib_tech.html */
1797 0 : const uint64_t MAX_DEFLATE_RATIO = 1032;
1798 :
1799 : /* security margin as I don't understand what this codec does */
1800 0 : return MAX_DEFLATE_RATIO * (uint64_t)4;
1801 : }
1802 :
1803 0 : int TIFFInitPixarLog(TIFF *tif, int scheme)
1804 : {
1805 : static const char module[] = "TIFFInitPixarLog";
1806 :
1807 : PixarLogState *sp;
1808 :
1809 : (void)scheme;
1810 0 : assert(scheme == COMPRESSION_PIXARLOG);
1811 :
1812 : /*
1813 : * Merge codec-specific tag information.
1814 : */
1815 0 : if (!_TIFFMergeFields(tif, pixarlogFields, TIFFArrayCount(pixarlogFields)))
1816 : {
1817 0 : TIFFErrorExtR(tif, module,
1818 : "Merging PixarLog codec-specific tags failed");
1819 0 : return 0;
1820 : }
1821 :
1822 : /*
1823 : * Allocate state block so tag methods have storage to record values.
1824 : */
1825 0 : tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(PixarLogState));
1826 0 : if (tif->tif_data == NULL)
1827 0 : goto bad;
1828 0 : sp = (PixarLogState *)tif->tif_data;
1829 0 : _TIFFmemset(sp, 0, sizeof(*sp));
1830 0 : sp->stream.data_type = Z_BINARY;
1831 0 : sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN;
1832 :
1833 : /*
1834 : * Install codec methods.
1835 : */
1836 0 : tif->tif_fixuptags = PixarLogFixupTags;
1837 0 : tif->tif_setupdecode = PixarLogSetupDecode;
1838 0 : tif->tif_predecode = PixarLogPreDecode;
1839 0 : tif->tif_decoderow = PixarLogDecode;
1840 0 : tif->tif_decodestrip = PixarLogDecode;
1841 0 : tif->tif_decodetile = PixarLogDecode;
1842 0 : tif->tif_setupencode = PixarLogSetupEncode;
1843 0 : tif->tif_preencode = PixarLogPreEncode;
1844 0 : tif->tif_postencode = PixarLogPostEncode;
1845 0 : tif->tif_encoderow = PixarLogEncode;
1846 0 : tif->tif_encodestrip = PixarLogEncode;
1847 0 : tif->tif_encodetile = PixarLogEncode;
1848 0 : tif->tif_close = PixarLogClose;
1849 0 : tif->tif_cleanup = PixarLogCleanup;
1850 0 : tif->tif_getmaxcompressionratio = PixarLogGetMaxCompressionRatio;
1851 :
1852 : /* Override SetField so we can handle our private pseudo-tag */
1853 0 : sp->vgetparent = tif->tif_tagmethods.vgetfield;
1854 0 : tif->tif_tagmethods.vgetfield = PixarLogVGetField; /* hook for codec tags */
1855 0 : sp->vsetparent = tif->tif_tagmethods.vsetfield;
1856 0 : tif->tif_tagmethods.vsetfield = PixarLogVSetField; /* hook for codec tags */
1857 :
1858 : /* Default values for codec-specific fields */
1859 0 : sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */
1860 0 : sp->state = 0;
1861 :
1862 : /* we don't wish to use the predictor,
1863 : * the default is none, which predictor value 1
1864 : */
1865 0 : (void)TIFFPredictorInit(tif);
1866 :
1867 : /*
1868 : * build the companding tables
1869 : */
1870 0 : PixarLogMakeTables(tif, sp);
1871 :
1872 0 : return (1);
1873 0 : bad:
1874 0 : TIFFErrorExtR(tif, module, "No space for PixarLog state block");
1875 0 : return (0);
1876 : }
1877 : #endif /* PIXARLOG_SUPPORT */
|