1 // SPDX-License-Identifier: BSD-3-Clause
2 // Copyright Contributors to the OpenEXR Project.
3
4 #include "write.h"
5
6 #include "test_value.h"
7
8 #include <openexr.h>
9
10 #include <memory.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <iomanip>
15 #include <iostream>
16 #include <vector>
17
18 #include <ImathRandom.h>
19 #include <ImfArray.h>
20 #include <ImfChannelList.h>
21 #include <ImfCompressor.h>
22 #include <ImfFrameBuffer.h>
23 #include <ImfHeader.h>
24 #include <ImfHuf.h>
25 #include <ImfInputFile.h>
26 #include <ImfOutputFile.h>
27 #include <ImfTiledOutputFile.h>
28 #include <half.h>
29
30 #if defined(OPENEXR_ENABLE_API_VISIBILITY)
31 # include "../../lib/OpenEXRCore/internal_huf.c"
32
33 void*
internal_exr_alloc(size_t bytes)34 internal_exr_alloc (size_t bytes)
35 {
36 return malloc (bytes);
37 }
38 void
internal_exr_free(void * p)39 internal_exr_free (void* p)
40 {
41 if (p) free (p);
42 }
43
44 #else
45 # include "../../lib/OpenEXRCore/internal_huf.h"
46 #endif
47
48 using namespace IMATH_NAMESPACE;
49 namespace IMF = OPENEXR_IMF_NAMESPACE;
50 using namespace IMF;
51
52 #if (IMATH_VERSION_MAJOR < 3) || \
53 (IMATH_VERSION_MAJOR == 3 && IMATH_VERSION_MINOR < 1)
54 inline float
imath_half_to_float(uint16_t a)55 imath_half_to_float (uint16_t a)
56 {
57 half tmp;
58 tmp.setBits (a);
59 return static_cast<float> (tmp);
60 }
61 #endif
62
63 ////////////////////////////////////////
64
65 inline int
shiftAndRound(int x,int shift)66 shiftAndRound (int x, int shift)
67 {
68 x <<= 1;
69 int a = (1 << shift) - 1;
70 shift += 1;
71 int b = (x >> shift) & 1;
72 return (x + a + b) >> shift;
73 }
74
75 inline bool
withinB44ErrorBounds(const uint16_t A[4][4],const uint16_t B[4][4])76 withinB44ErrorBounds (const uint16_t A[4][4], const uint16_t B[4][4])
77 {
78 //
79 // Assuming that a 4x4 pixel block, B, was generated by
80 // compressing and uncompressing another pixel block, A,
81 // using OpenEXR's B44 compression method, check whether
82 // the differences between A and B are what we would
83 // expect from the compressor.
84 //
85
86 //
87 // The block may not have been compressed at all if it
88 // was part of a very small tile.
89 //
90
91 bool equal = true;
92
93 for (int i = 0; i < 4; ++i)
94 for (int j = 0; j < 4; ++j)
95 if (A[i][j] != B[i][j]) equal = false;
96
97 if (equal) return true;
98
99 //
100 // The block was compressed.
101 //
102 // Perform a "light" version of the B44 compression on A
103 // (see the pack() function in ImfB44Compressor.cpp).
104 //
105
106 uint16_t t[16];
107
108 for (int i = 0; i < 16; ++i)
109 {
110 uint16_t Abits = A[i / 4][i % 4];
111
112 if ((Abits & 0x7c00) == 0x7c00)
113 t[i] = 0x8000;
114 else if (Abits & 0x8000)
115 t[i] = ~Abits;
116 else
117 t[i] = Abits | 0x8000;
118 }
119
120 uint16_t tMax = 0;
121
122 for (int i = 0; i < 16; ++i)
123 if (tMax < t[i]) tMax = t[i];
124
125 int shift = -1;
126 int d[16];
127 int r[15];
128 int rMin;
129 int rMax;
130
131 do
132 {
133 shift += 1;
134
135 for (int i = 0; i < 16; ++i)
136 d[i] = shiftAndRound (tMax - t[i], shift);
137
138 const int bias = 0x20;
139
140 r[0] = d[0] - d[4] + bias;
141 r[1] = d[4] - d[8] + bias;
142 r[2] = d[8] - d[12] + bias;
143
144 r[3] = d[0] - d[1] + bias;
145 r[4] = d[4] - d[5] + bias;
146 r[5] = d[8] - d[9] + bias;
147 r[6] = d[12] - d[13] + bias;
148
149 r[7] = d[1] - d[2] + bias;
150 r[8] = d[5] - d[6] + bias;
151 r[9] = d[9] - d[10] + bias;
152 r[10] = d[13] - d[14] + bias;
153
154 r[11] = d[2] - d[3] + bias;
155 r[12] = d[6] - d[7] + bias;
156 r[13] = d[10] - d[11] + bias;
157 r[14] = d[14] - d[15] + bias;
158
159 rMin = r[0];
160 rMax = r[0];
161
162 for (int i = 1; i < 15; ++i)
163 {
164 if (rMin > r[i]) rMin = r[i];
165
166 if (rMax < r[i]) rMax = r[i];
167 }
168 } while (rMin < 0 || rMax > 0x3f);
169
170 t[0] = tMax - (d[0] << shift);
171
172 //
173 // Now perform a "light" version of the decompression method.
174 // (see the unpack() function in ImfB44Compressor.cpp).
175 //
176
177 uint16_t A1[16];
178 const int bias = 0x20 << shift;
179
180 A1[0] = t[0];
181 A1[4] = A1[0] + (r[0] << shift) - bias;
182 A1[8] = A1[4] + (r[1] << shift) - bias;
183 A1[12] = A1[8] + (r[2] << shift) - bias;
184
185 A1[1] = A1[0] + (r[3] << shift) - bias;
186 A1[5] = A1[4] + (r[4] << shift) - bias;
187 A1[9] = A1[8] + (r[5] << shift) - bias;
188 A1[13] = A1[12] + (r[6] << shift) - bias;
189
190 A1[2] = A1[1] + (r[7] << shift) - bias;
191 A1[6] = A1[5] + (r[8] << shift) - bias;
192 A1[10] = A1[9] + (r[9] << shift) - bias;
193 A1[14] = A1[13] + (r[10] << shift) - bias;
194
195 A1[3] = A1[2] + (r[11] << shift) - bias;
196 A1[7] = A1[6] + (r[12] << shift) - bias;
197 A1[11] = A1[10] + (r[13] << shift) - bias;
198 A1[15] = A1[14] + (r[14] << shift) - bias;
199
200 //
201 // Compare the result with B, allowing for an difference
202 // of a couple of units in the last place.
203 //
204
205 for (int i = 0; i < 16; ++i)
206 {
207 uint16_t A1bits = A1[i];
208 uint16_t Bbits = B[i / 4][i % 4];
209 uint16_t Abits = A[i / 4][i % 4];
210
211 if (Bbits & 0x8000)
212 Bbits = ~Bbits;
213 else
214 Bbits = Bbits | 0x8000;
215
216 if (Bbits > A1bits + 5 || Bbits < A1bits - 5)
217 {
218 std::cerr << "B44 idx " << i << ": B bits " << std::hex << Bbits
219 << std::dec << " (" << imath_half_to_float (Bbits)
220 << ") too different from A1 bits " << std::hex << A1bits
221 << std::dec << " (" << imath_half_to_float (A1bits) << ")"
222 << " orig " << std::hex << Abits << std::dec << " ("
223 << imath_half_to_float (Abits) << ")" << std::endl;
224 return false;
225 }
226 }
227
228 return true;
229 }
230
231 ////////////////////////////////////////
232
233 struct pixels
234 {
235 int _w, _h;
236 int _stride_x;
237
238 std::vector<uint32_t> i;
239 std::vector<float> f;
240 std::vector<uint16_t> h;
241 std::vector<uint16_t> rgba[4];
242
pixelspixels243 pixels (int iw, int ih, int s) : _w (iw), _h (ih), _stride_x (s)
244 {
245 i.resize (_stride_x * _h, 0);
246 f.resize (_stride_x * _h, 0.f);
247 h.resize (_stride_x * _h, 0);
248 for (int c = 0; c < 4; ++c)
249 rgba[c].resize (_stride_x * _h, 0);
250 }
251
fillZeropixels252 void fillZero ()
253 {
254 for (int y = 0; y < _h; ++y)
255 {
256 for (int x = 0; x < _w; ++x)
257 {
258 size_t idx = y * _stride_x + x;
259 i[idx] = 0;
260 f[idx] = 0.f;
261 h[idx] = 0;
262 for (int c = 0; c < 4; ++c)
263 rgba[c][idx] = 0;
264 }
265 }
266 }
267
fillDeadpixels268 void fillDead ()
269 {
270 for (int y = 0; y < _h; ++y)
271 {
272 for (int x = 0; x < _w; ++x)
273 {
274 size_t idx = y * _stride_x + x;
275 i[idx] = 0xDEADBEEF;
276 union
277 {
278 uint32_t iv;
279 float fv;
280 } tmp;
281 tmp.iv = 0xDEADBEEF;
282 f[idx] = tmp.fv;
283 h[idx] = 0xDEAD;
284 for (int c = 0; c < 4; ++c)
285 rgba[c][idx] = 0xDEAD;
286 }
287 }
288 }
289
fillPattern1pixels290 void fillPattern1 ()
291 {
292 for (int y = 0; y < _h; ++y)
293 {
294 for (int x = 0; x < _w; ++x)
295 {
296 size_t idx = y * _stride_x + x;
297 i[idx] = (x + y) & 1;
298 f[idx] = float (i[idx]);
299 h[idx] = half (f[idx]).bits ();
300 for (int c = 0; c < 4; ++c)
301 rgba[c][idx] = h[idx];
302 }
303 }
304 }
305
fillPattern2pixels306 void fillPattern2 ()
307 {
308 for (int y = 0; y < _h; ++y)
309 {
310 for (int x = 0; x < _w; ++x)
311 {
312 size_t idx = y * _stride_x + x;
313 i[idx] = x % 100 + 100 * (y % 100);
314 f[idx] =
315 half (sin (double (y)) + sin (double (x) * 0.5)).bits ();
316 h[idx] =
317 half (sin (double (x)) + sin (double (y) * 0.5)).bits ();
318 for (int c = 0; c < 4; ++c)
319 rgba[c][idx] =
320 half (sin (double (x + c)) + sin (double (y) * 0.5))
321 .bits ();
322 }
323 }
324 }
325
fillRandompixels326 void fillRandom ()
327 {
328 Rand48 rand;
329
330 for (int y = 0; y < _h; ++y)
331 {
332 for (int x = 0; x < _w; ++x)
333 {
334 size_t idx = y * _stride_x + x;
335 i[idx] = rand.nexti ();
336 h[idx] = (uint16_t) (rand.nexti ());
337 for (int c = 0; c < 4; ++c)
338 rgba[c][idx] = (uint16_t) (rand.nexti ());
339
340 union
341 {
342 int i;
343 float f;
344 } u;
345 u.i = rand.nexti ();
346
347 f[idx] = u.f;
348 }
349 }
350 }
351
compareExactpixels352 static inline void compareExact (
353 uint16_t a,
354 uint16_t b,
355 int x,
356 int y,
357 const char* taga,
358 const char* tagb,
359 const char* chan)
360 {
361 if (a != b)
362 {
363 std::cout << chan << " half at " << x << ", " << y
364 << " not equal: " << taga << " 0x" << std::hex << a
365 << std::dec << " (" << imath_half_to_float (a) << ") vs "
366 << tagb << " 0x" << std::hex << b << std::hex << " ("
367 << imath_half_to_float (b) << ")" << std::endl;
368 }
369 EXRCORE_TEST (a == b);
370 }
compareExactpixels371 static inline void compareExact (
372 uint32_t a,
373 uint32_t b,
374 int x,
375 int y,
376 const char* taga,
377 const char* tagb,
378 const char* chan)
379 {
380 if (a != b)
381 {
382 std::cout << chan << " uint at " << x << ", " << y
383 << " not equal: " << taga << " 0x" << std::hex << a
384 << std::dec << " vs " << tagb << " 0x" << std::hex << b
385 << std::dec << std::endl;
386 }
387 EXRCORE_TEST (a == b);
388 }
compareExactpixels389 static inline void compareExact (
390 float af,
391 float bf,
392 int x,
393 int y,
394 const char* taga,
395 const char* tagb,
396 const char* chan)
397 {
398 union
399 {
400 uint32_t iv;
401 float fv;
402 } a, b;
403 a.fv = af;
404 b.fv = bf;
405 if (a.iv != b.iv)
406 {
407 std::cout << chan << " float at " << x << ", " << y
408 << " not equal: " << taga << " 0x" << std::hex << a.iv
409 << std::dec << " (" << af << ") vs " << tagb << " "
410 << std::hex << b.iv << std::dec << " (" << bf << ")"
411 << std::endl;
412 }
413 EXRCORE_TEST (a.iv == b.iv);
414 }
415 void
compareExactpixels416 compareExact (const pixels& o, const char* otag, const char* selftag) const
417 {
418 for (int y = 0; y < _h; ++y)
419 {
420 for (int x = 0; x < _w; ++x)
421 {
422 size_t idx = y * _stride_x + x;
423 compareExact (o.i[idx], i[idx], x, y, otag, selftag, "I");
424 compareExact (o.h[idx], h[idx], x, y, otag, selftag, "H");
425 compareExact (o.f[idx], f[idx], x, y, otag, selftag, "F");
426 compareExact (
427 o.rgba[0][idx], rgba[0][idx], x, y, otag, selftag, "R");
428 compareExact (
429 o.rgba[1][idx], rgba[1][idx], x, y, otag, selftag, "G");
430 compareExact (
431 o.rgba[2][idx], rgba[2][idx], x, y, otag, selftag, "B");
432 compareExact (
433 o.rgba[3][idx], rgba[3][idx], x, y, otag, selftag, "A");
434 }
435 }
436 }
437
compareClosepixels438 void compareClose (
439 const pixels& o,
440 exr_compression_t comp,
441 const char* otag,
442 const char* selftag) const
443 {
444 for (int y = 0; y < _h; ++y)
445 {
446 for (int x = 0; x < _w; ++x)
447 {
448 size_t idx = y * _stride_x + x;
449
450 compareExact (o.i[idx], i[idx], x, y, otag, selftag, "I");
451
452 if (comp == EXR_COMPRESSION_PXR24)
453 {
454 union
455 {
456 uint32_t iv;
457 float fv;
458 } a, b;
459 a.fv = o.f[idx];
460 b.fv = f[idx];
461 int32_t delta =
462 (int32_t) (a.iv >> 8) - (int32_t) (b.iv >> 8);
463 EXRCORE_TEST_LOCATION (delta < 2 && delta > -2, x, y);
464 }
465 else
466 {
467 // b44 & dwa don't change floats
468 compareExact (o.f[idx], f[idx], x, y, otag, selftag, "F");
469 }
470 }
471 }
472
473 if (comp == EXR_COMPRESSION_B44 || comp == EXR_COMPRESSION_B44A)
474 {
475 uint16_t orig[4][4], unc[4][4];
476 for (int y = 0; y < _h; y += 4)
477 {
478 for (int x = 0; x < _w; x += 4)
479 {
480 for (int y1 = 0; y1 < 4; ++y1)
481 {
482 for (int x1 = 0; x1 < 4; ++x1)
483 {
484 int y2 = std::min (y + y1, _h - 1);
485 int x2 = std::min (x + x1, _w - 1);
486 orig[y1][x1] = o.h[y2 * _stride_x + x2];
487 unc[y1][x1] = h[y2 * _stride_x + x2];
488 }
489 }
490 EXRCORE_TEST_LOCATION (
491 withinB44ErrorBounds (orig, unc), x, y)
492 for (int c = 0; c < 4; ++c)
493 {
494
495 for (int y1 = 0; y1 < 4; ++y1)
496 {
497 for (int x1 = 0; x1 < 4; ++x1)
498 {
499 int y2 = std::min (y + y1, _h - 1);
500 int x2 = std::min (x + x1, _w - 1);
501 orig[y1][x1] = o.rgba[c][y2 * _stride_x + x2];
502 unc[y1][x1] = rgba[c][y2 * _stride_x + x2];
503 }
504 }
505 EXRCORE_TEST_LOCATION (
506 withinB44ErrorBounds (orig, unc), x, y)
507 }
508 }
509 }
510 }
511 else if (comp == EXR_COMPRESSION_PXR24)
512 {
513 for (int y = 0; y < _h; ++y)
514 {
515 for (int x = 0; x < _w; ++x)
516 {
517 size_t idx = y * _stride_x + x;
518 compareExact (o.h[idx], h[idx], x, y, otag, selftag, "H");
519 compareExact (
520 o.rgba[0][idx], rgba[0][idx], x, y, otag, selftag, "R");
521 compareExact (
522 o.rgba[1][idx], rgba[1][idx], x, y, otag, selftag, "G");
523 compareExact (
524 o.rgba[2][idx], rgba[2][idx], x, y, otag, selftag, "B");
525 compareExact (
526 o.rgba[3][idx], rgba[3][idx], x, y, otag, selftag, "A");
527 }
528 }
529 }
530 else
531 {
532 for (int y = 0; y < _h; ++y)
533 {
534 for (int x = 0; x < _w; ++x)
535 {
536 size_t idx = y * _stride_x + x;
537 EXRCORE_TEST (o.h[idx] == h[idx]);
538 EXRCORE_TEST (o.rgba[0][idx] == rgba[0][idx]);
539 EXRCORE_TEST (o.rgba[1][idx] == rgba[1][idx]);
540 EXRCORE_TEST (o.rgba[2][idx] == rgba[2][idx]);
541 EXRCORE_TEST (o.rgba[3][idx] == rgba[3][idx]);
542 }
543 }
544 }
545 }
546 };
547 static const int IMG_WIDTH = 1371;
548 static const int IMG_HEIGHT = 159;
549 static const int IMG_STRIDE_X = 1376;
550 static const int IMG_DATA_X = 17;
551 static const int IMG_DATA_Y = 29;
552
553 ////////////////////////////////////////
554
555 static void
fill_pointers(pixels & p,const exr_coding_channel_info_t & curchan,int32_t idxoffset,void ** ptr,int32_t * pixelstride,int32_t * linestride)556 fill_pointers (
557 pixels& p,
558 const exr_coding_channel_info_t& curchan,
559 int32_t idxoffset,
560 void** ptr,
561 int32_t* pixelstride,
562 int32_t* linestride)
563 {
564 if (!strcmp (curchan.channel_name, "A"))
565 {
566 *ptr = p.rgba[3].data () + idxoffset;
567 *pixelstride = 2;
568 *linestride = 2 * p._stride_x;
569 }
570 else if (!strcmp (curchan.channel_name, "B"))
571 {
572 *ptr = p.rgba[2].data () + idxoffset;
573 *pixelstride = 2;
574 *linestride = 2 * p._stride_x;
575 }
576 else if (!strcmp (curchan.channel_name, "G"))
577 {
578 *ptr = p.rgba[1].data () + idxoffset;
579 *pixelstride = 2;
580 *linestride = 2 * p._stride_x;
581 }
582 else if (!strcmp (curchan.channel_name, "R"))
583 {
584 *ptr = p.rgba[0].data () + idxoffset;
585 *pixelstride = 2;
586 *linestride = 2 * p._stride_x;
587 }
588 else if (!strcmp (curchan.channel_name, "H"))
589 {
590 *ptr = p.h.data () + idxoffset;
591 *pixelstride = 2;
592 *linestride = 2 * p._stride_x;
593 }
594 else if (!strcmp (curchan.channel_name, "F"))
595 {
596 *ptr = p.f.data () + idxoffset;
597 *pixelstride = 4;
598 *linestride = 4 * p._stride_x;
599 }
600 else if (!strcmp (curchan.channel_name, "I"))
601 {
602 *ptr = p.i.data () + idxoffset;
603 *pixelstride = 4;
604 *linestride = 4 * p._stride_x;
605 }
606 else
607 {
608 std::cerr << "Unknown channel name '" << curchan.channel_name << "'"
609 << std::endl;
610 EXRCORE_TEST (false);
611 *ptr = nullptr;
612 *pixelstride = -1;
613 *linestride = -1;
614 }
615 }
616
617 ////////////////////////////////////////
618
619 static void
doEncodeScan(exr_context_t f,pixels & p,int xs,int ys)620 doEncodeScan (exr_context_t f, pixels& p, int xs, int ys)
621 {
622 int32_t scansperchunk = 0;
623 int y, starty, endy;
624 exr_chunk_info_t cinfo;
625 exr_encode_pipeline_t encoder;
626 bool first = true;
627
628 EXRCORE_TEST_RVAL (exr_get_scanlines_per_chunk (f, 0, &scansperchunk));
629 starty = IMG_DATA_Y * ys;
630 endy = starty + IMG_HEIGHT * ys;
631 for (y = starty; y < endy; y += scansperchunk)
632 {
633 EXRCORE_TEST_RVAL (exr_write_scanline_chunk_info (f, 0, y, &cinfo));
634 if (first)
635 {
636 EXRCORE_TEST_RVAL (
637 exr_encoding_initialize (f, 0, &cinfo, &encoder));
638 }
639 else
640 {
641 EXRCORE_TEST_RVAL (exr_encoding_update (f, 0, &cinfo, &encoder));
642 }
643
644 int32_t idxoffset = ((y - starty) / ys) * p._stride_x;
645
646 for (int c = 0; c < encoder.channel_count; ++c)
647 {
648 const exr_coding_channel_info_t& curchan = encoder.channels[c];
649 void* ptr;
650 int32_t pixelstride;
651 int32_t linestride;
652
653 if (curchan.height == 0)
654 {
655 encoder.channels[c].encode_from_ptr = NULL;
656 encoder.channels[c].user_pixel_stride = 0;
657 encoder.channels[c].user_line_stride = 0;
658 continue;
659 }
660
661 fill_pointers (
662 p, curchan, idxoffset, &ptr, &pixelstride, &linestride);
663
664 // make sure the setup has initialized our bytes for us
665 EXRCORE_TEST (curchan.user_bytes_per_element == pixelstride);
666
667 encoder.channels[c].encode_from_ptr = (const uint8_t*) ptr;
668 encoder.channels[c].user_pixel_stride = pixelstride;
669 encoder.channels[c].user_line_stride = linestride;
670 }
671
672 if (first)
673 {
674 EXRCORE_TEST_RVAL (
675 exr_encoding_choose_default_routines (f, 0, &encoder));
676 }
677 EXRCORE_TEST_RVAL (exr_encoding_run (f, 0, &encoder));
678
679 first = false;
680 }
681 EXRCORE_TEST_RVAL (exr_encoding_destroy (f, &encoder));
682 }
683
684 ////////////////////////////////////////
685
686 static void
doEncodeTile(exr_context_t f,pixels & p,int xs,int ys)687 doEncodeTile (exr_context_t f, pixels& p, int xs, int ys)
688 {
689 int32_t tlevx, tlevy;
690 int32_t tilew, tileh;
691 int32_t tilex, tiley;
692 int y, endy;
693 int x, endx;
694 exr_chunk_info_t cinfo;
695 exr_encode_pipeline_t encoder;
696 bool first = true;
697
698 EXRCORE_TEST (xs == 1 && ys == 1);
699 EXRCORE_TEST_RVAL (exr_get_tile_levels (f, 0, &tlevx, &tlevy));
700 EXRCORE_TEST (tlevx == 1 && tlevy == 1);
701
702 EXRCORE_TEST_RVAL (exr_get_tile_sizes (f, 0, 0, 0, &tilew, &tileh));
703 EXRCORE_TEST (tilew == 32 && tileh == 32);
704
705 y = IMG_DATA_Y * ys;
706 endy = y + IMG_HEIGHT * ys;
707 tiley = 0;
708 for (; y < endy; y += tileh, ++tiley)
709 {
710 tilex = 0;
711
712 x = IMG_DATA_X * xs;
713 endx = x + IMG_WIDTH * xs;
714 for (; x < endx; x += tilew, ++tilex)
715 {
716 EXRCORE_TEST_RVAL (
717 exr_write_tile_chunk_info (f, 0, tilex, tiley, 0, 0, &cinfo));
718 if (first)
719 {
720 EXRCORE_TEST_RVAL (
721 exr_encoding_initialize (f, 0, &cinfo, &encoder));
722 }
723 else
724 {
725 EXRCORE_TEST_RVAL (
726 exr_encoding_update (f, 0, &cinfo, &encoder));
727 }
728
729 int32_t idxoffset = tiley * tileh * p._stride_x + tilex * tilew;
730
731 for (int c = 0; c < encoder.channel_count; ++c)
732 {
733 const exr_coding_channel_info_t& curchan = encoder.channels[c];
734 void* ptr;
735 int32_t pixelstride;
736 int32_t linestride;
737
738 fill_pointers (
739 p, curchan, idxoffset, &ptr, &pixelstride, &linestride);
740
741 // make sure the setup has initialized our bytes for us
742 EXRCORE_TEST (curchan.user_bytes_per_element == pixelstride);
743
744 encoder.channels[c].encode_from_ptr = (const uint8_t*) ptr;
745 encoder.channels[c].user_pixel_stride = pixelstride;
746 encoder.channels[c].user_line_stride = linestride;
747 }
748
749 if (first)
750 {
751 EXRCORE_TEST_RVAL (
752 exr_encoding_choose_default_routines (f, 0, &encoder));
753 }
754 EXRCORE_TEST_RVAL (exr_encoding_run (f, 0, &encoder));
755 first = false;
756 }
757 }
758 EXRCORE_TEST_RVAL (exr_encoding_destroy (f, &encoder));
759 }
760
761 ////////////////////////////////////////
762
763 static void
doDecodeScan(exr_context_t f,pixels & p,int xs,int ys)764 doDecodeScan (exr_context_t f, pixels& p, int xs, int ys)
765 {
766 exr_chunk_info_t cinfo;
767 exr_decode_pipeline_t decoder;
768 int32_t scansperchunk;
769 exr_attr_box2i_t dw;
770 bool first = true;
771
772 EXRCORE_TEST_RVAL (exr_get_data_window (f, 0, &dw));
773 EXRCORE_TEST (dw.min.x == IMG_DATA_X * xs);
774 EXRCORE_TEST (dw.max.x == IMG_DATA_X * xs + IMG_WIDTH * xs - 1);
775 EXRCORE_TEST (dw.min.y == IMG_DATA_Y * ys);
776 EXRCORE_TEST (dw.max.y == IMG_DATA_Y * ys + IMG_HEIGHT * ys - 1);
777
778 EXRCORE_TEST_RVAL (exr_get_scanlines_per_chunk (f, 0, &scansperchunk));
779
780 exr_storage_t stortype;
781 EXRCORE_TEST_RVAL (exr_get_storage (f, 0, &stortype));
782 EXRCORE_TEST (stortype == EXR_STORAGE_SCANLINE);
783
784 //const uint8_t* tmp;
785 for (int y = dw.min.y; y <= dw.max.y; y += scansperchunk)
786 {
787 EXRCORE_TEST_RVAL (exr_read_scanline_chunk_info (f, 0, y, &cinfo));
788 if (first)
789 {
790 EXRCORE_TEST_RVAL (
791 exr_decoding_initialize (f, 0, &cinfo, &decoder));
792 }
793 else
794 {
795 EXRCORE_TEST_RVAL (exr_decoding_update (f, 0, &cinfo, &decoder));
796 }
797 int32_t idxoffset = ((y - dw.min.y) / ys) * p._stride_x;
798
799 for (int c = 0; c < decoder.channel_count; ++c)
800 {
801 const exr_coding_channel_info_t& curchan = decoder.channels[c];
802 void* ptr;
803 int32_t pixelstride;
804 int32_t linestride;
805
806 if (curchan.height == 0)
807 {
808 decoder.channels[c].decode_to_ptr = NULL;
809 decoder.channels[c].user_pixel_stride = 0;
810 decoder.channels[c].user_line_stride = 0;
811 continue;
812 }
813
814 fill_pointers (
815 p, curchan, idxoffset, &ptr, &pixelstride, &linestride);
816
817 // make sure the setup has initialized our bytes for us
818 EXRCORE_TEST (curchan.user_bytes_per_element == pixelstride);
819
820 decoder.channels[c].decode_to_ptr = (uint8_t*) ptr;
821 decoder.channels[c].user_pixel_stride = pixelstride;
822 decoder.channels[c].user_line_stride = linestride;
823 }
824
825 if (first)
826 {
827 EXRCORE_TEST_RVAL (
828 exr_decoding_choose_default_routines (f, 0, &decoder));
829 }
830 EXRCORE_TEST_RVAL (exr_decoding_run (f, 0, &decoder));
831
832 first = false;
833 }
834 EXRCORE_TEST_RVAL (exr_decoding_destroy (f, &decoder));
835 }
836
837 ////////////////////////////////////////
838
839 static void
doDecodeTile(exr_context_t f,pixels & p,int xs,int ys)840 doDecodeTile (exr_context_t f, pixels& p, int xs, int ys)
841 {
842 int32_t tlevx, tlevy;
843 int32_t tilew, tileh;
844 int32_t tilex, tiley;
845 int y, endy;
846 int x, endx;
847 exr_chunk_info_t cinfo;
848 exr_decode_pipeline_t decoder;
849 bool first = true;
850
851 EXRCORE_TEST (xs == 1 && ys == 1);
852 EXRCORE_TEST_RVAL (exr_get_tile_levels (f, 0, &tlevx, &tlevy));
853 EXRCORE_TEST (tlevx == 1 && tlevy == 1);
854
855 EXRCORE_TEST_RVAL (exr_get_tile_sizes (f, 0, 0, 0, &tilew, &tileh));
856 EXRCORE_TEST (tilew == 32 && tileh == 32);
857
858 y = IMG_DATA_Y * ys;
859 endy = y + IMG_HEIGHT * ys;
860 tiley = 0;
861 for (; y < endy; y += tileh, ++tiley)
862 {
863 tilex = 0;
864
865 x = IMG_DATA_X * xs;
866 endx = x + IMG_WIDTH * xs;
867 for (; x < endx; x += tilew, ++tilex)
868 {
869 EXRCORE_TEST_RVAL (
870 exr_read_tile_chunk_info (f, 0, tilex, tiley, 0, 0, &cinfo));
871 if (first)
872 {
873 EXRCORE_TEST_RVAL (
874 exr_decoding_initialize (f, 0, &cinfo, &decoder));
875 }
876 else
877 {
878 EXRCORE_TEST_RVAL (
879 exr_decoding_update (f, 0, &cinfo, &decoder));
880 }
881
882 int32_t idxoffset = tiley * tileh * p._stride_x + tilex * tilew;
883
884 for (int c = 0; c < decoder.channel_count; ++c)
885 {
886 const exr_coding_channel_info_t& curchan = decoder.channels[c];
887 void* ptr;
888 int32_t pixelstride;
889 int32_t linestride;
890
891 fill_pointers (
892 p, curchan, idxoffset, &ptr, &pixelstride, &linestride);
893
894 // make sure the setup has initialized our bytes for us
895 EXRCORE_TEST (curchan.user_bytes_per_element == pixelstride);
896
897 decoder.channels[c].decode_to_ptr = (uint8_t*) ptr;
898 decoder.channels[c].user_pixel_stride = pixelstride;
899 decoder.channels[c].user_line_stride = linestride;
900 }
901
902 if (first)
903 {
904 EXRCORE_TEST_RVAL (
905 exr_decoding_choose_default_routines (f, 0, &decoder));
906 }
907 EXRCORE_TEST_RVAL (exr_decoding_run (f, 0, &decoder));
908 first = false;
909 }
910 }
911 EXRCORE_TEST_RVAL (exr_decoding_destroy (f, &decoder));
912 }
913
914 ////////////////////////////////////////
915
916 static const char* channels[] = { "R", "G", "B", "A", "H" };
917
918 static void
saveCPP(pixels & p,const std::string & cppfilename,bool tiled,int xs,int ys,exr_compression_t comp,int fw,int fh,int dwx,int dwy)919 saveCPP (
920 pixels& p,
921 const std::string& cppfilename,
922 bool tiled,
923 int xs,
924 int ys,
925 exr_compression_t comp,
926 int fw,
927 int fh,
928 int dwx,
929 int dwy)
930 {
931 Header hdr (
932 (Box2i (V2i (0, 0), V2i (fw - 1, fh - 1))),
933 (Box2i (V2i (dwx, dwy), V2i (dwx + fw - 1, dwy + fh - 1))));
934
935 hdr.compression () = (IMF::Compression) ((int) comp);
936 hdr.zipCompressionLevel () = 3;
937 EXRCORE_TEST (((const Header&) hdr).zipCompressionLevel () == 3);
938
939 hdr.channels ().insert ("I", Channel (IMF::UINT, xs, ys));
940 for (int c = 0; c < 5; ++c)
941 hdr.channels ().insert (channels[c], Channel (IMF::HALF, xs, ys));
942 hdr.channels ().insert ("F", Channel (IMF::FLOAT, xs, ys));
943 {
944 FrameBuffer fb;
945 V2i origin{ dwx, dwy };
946 fb.insert (
947 "I",
948 Slice::Make (
949 IMF::UINT,
950 p.i.data (),
951 origin,
952 fw,
953 fh,
954 0,
955 4 * p._stride_x,
956 xs,
957 ys,
958 0.0,
959 false,
960 false));
961 fb.insert (
962 "H",
963 Slice::Make (
964 IMF::HALF,
965 p.h.data (),
966 origin,
967 fw,
968 fh,
969 0,
970 2 * p._stride_x,
971 xs,
972 ys,
973 0.0,
974 false,
975 false));
976 fb.insert (
977 "F",
978 Slice::Make (
979 IMF::FLOAT,
980 p.f.data (),
981 origin,
982 fw,
983 fh,
984 0,
985 4 * p._stride_x,
986 xs,
987 ys,
988 0.0,
989 false,
990 false));
991
992 for (int c = 0; c < 4; c++)
993 {
994 fb.insert (
995 channels[c],
996 Slice::Make (
997 IMF::HALF,
998 p.rgba[c].data (),
999 origin,
1000 fw,
1001 fh,
1002 0,
1003 2 * p._stride_x,
1004 xs,
1005 ys,
1006 0.0,
1007 false,
1008 false));
1009 }
1010
1011 if (tiled)
1012 {
1013 TileDescription td;
1014 hdr.setTileDescription (td);
1015 TiledOutputFile out (cppfilename.c_str (), hdr);
1016 out.setFrameBuffer (fb);
1017 out.writeTiles (
1018 0,
1019 static_cast<int> (
1020 ceil (
1021 static_cast<float> (fw) /
1022 static_cast<float> (td.xSize)) -
1023 1),
1024 0,
1025 static_cast<int> (
1026 ceil (
1027 static_cast<float> (fh) /
1028 static_cast<float> (td.ySize)) -
1029 1));
1030 }
1031 else
1032 {
1033 OutputFile out (cppfilename.c_str (), hdr);
1034 out.setFrameBuffer (fb);
1035 out.writePixels (fh);
1036 }
1037 }
1038 }
1039
1040 ////////////////////////////////////////
1041
1042 static void
loadCPP(pixels & p,const std::string & filename,bool tiled,int fw,int fh,int dwx,int dwy)1043 loadCPP (
1044 pixels& p,
1045 const std::string& filename,
1046 bool tiled,
1047 int fw,
1048 int fh,
1049 int dwx,
1050 int dwy)
1051 {
1052 InputFile in (filename.c_str ());
1053 {
1054 FrameBuffer fb;
1055 V2i origin{ dwx, dwy };
1056 fb.insert (
1057 "I",
1058 Slice::Make (
1059 IMF::UINT,
1060 p.i.data (),
1061 origin,
1062 fw,
1063 fh,
1064 0,
1065 4 * p._stride_x,
1066 in.header ().channels ()["I"].xSampling,
1067 in.header ().channels ()["I"].ySampling,
1068 0.0,
1069 false,
1070 false));
1071 fb.insert (
1072 "H",
1073 Slice::Make (
1074 IMF::HALF,
1075 p.h.data (),
1076 origin,
1077 fw,
1078 fh,
1079 0,
1080 2 * p._stride_x,
1081 in.header ().channels ()["H"].xSampling,
1082 in.header ().channels ()["H"].ySampling,
1083 0.0,
1084 false,
1085 false));
1086
1087 for (int c = 0; c < 4; c++)
1088 {
1089 fb.insert (
1090 channels[c],
1091 Slice::Make (
1092 IMF::HALF,
1093 p.rgba[c].data (),
1094 origin,
1095 fw,
1096 fh,
1097 0,
1098 2 * p._stride_x,
1099 in.header ().channels ()[channels[c]].xSampling,
1100 in.header ().channels ()[channels[c]].ySampling,
1101 0.0,
1102 false,
1103 false));
1104 }
1105 fb.insert (
1106 "F",
1107 Slice::Make (
1108 IMF::FLOAT,
1109 p.f.data (),
1110 origin,
1111 fw,
1112 fh,
1113 0,
1114 4 * p._stride_x,
1115 in.header ().channels ()["F"].xSampling,
1116 in.header ().channels ()["F"].ySampling,
1117 0.0,
1118 false,
1119 false));
1120
1121 in.setFrameBuffer (fb);
1122 in.readPixels (dwy, dwy + fh - 1);
1123 }
1124 }
1125
1126 ////////////////////////////////////////
1127
1128 static void
doWriteRead(pixels & p,const std::string & filename,const std::string & cppfilename,bool tiled,int xs,int ys,exr_compression_t comp,const char * pattern)1129 doWriteRead (
1130 pixels& p,
1131 const std::string& filename,
1132 const std::string& cppfilename,
1133 bool tiled,
1134 int xs,
1135 int ys,
1136 exr_compression_t comp,
1137 const char* pattern)
1138 {
1139 exr_context_t f;
1140 int partidx;
1141 int fw = p._w * xs;
1142 int fh = p._h * ys;
1143 int dwx = IMG_DATA_X * xs;
1144 int dwy = IMG_DATA_Y * ys;
1145 exr_context_initializer_t cinit = EXR_DEFAULT_CONTEXT_INITIALIZER;
1146 exr_attr_box2i_t dataW;
1147
1148 exr_set_default_zip_compression_level (-1);
1149 cinit.zip_level = 3;
1150
1151 dataW.min.x = dwx;
1152 dataW.min.y = dwy;
1153 dataW.max.x = dwx + fw - 1;
1154 dataW.max.y = dwy + fh - 1;
1155
1156 std::cout << " " << pattern << " tiled: " << (tiled ? "yes" : "no")
1157 << " sampling " << xs << ", " << ys << " comp " << (int) comp
1158 << std::endl;
1159
1160 EXRCORE_TEST_RVAL (exr_start_write (
1161 &f, filename.c_str (), EXR_WRITE_FILE_DIRECTLY, &cinit));
1162 if (tiled)
1163 {
1164 EXRCORE_TEST_RVAL (
1165 exr_add_part (f, "tiled", EXR_STORAGE_TILED, &partidx));
1166 }
1167 else
1168 {
1169 EXRCORE_TEST_RVAL (
1170 exr_add_part (f, "scan", EXR_STORAGE_SCANLINE, &partidx));
1171 }
1172
1173 EXRCORE_TEST_RVAL (
1174 exr_initialize_required_attr_simple (f, partidx, fw, fh, comp));
1175 EXRCORE_TEST_RVAL (exr_set_data_window (f, partidx, &dataW));
1176
1177 int zlev;
1178 EXRCORE_TEST_RVAL (exr_get_zip_compression_level (f, partidx, &zlev));
1179 EXRCORE_TEST (zlev == 3);
1180 EXRCORE_TEST_RVAL (exr_set_zip_compression_level (f, partidx, 4));
1181 if (tiled)
1182 {
1183 EXRCORE_TEST_RVAL (exr_set_tile_descriptor (
1184 f, partidx, 32, 32, EXR_TILE_ONE_LEVEL, EXR_TILE_ROUND_UP));
1185 }
1186
1187 EXRCORE_TEST_RVAL (exr_add_channel (
1188 f, partidx, "I", EXR_PIXEL_UINT, EXR_PERCEPTUALLY_LOGARITHMIC, xs, ys));
1189
1190 for (int c = 0; c < 5; ++c)
1191 {
1192 EXRCORE_TEST_RVAL (exr_add_channel (
1193 f,
1194 partidx,
1195 channels[c],
1196 EXR_PIXEL_HALF,
1197 EXR_PERCEPTUALLY_LOGARITHMIC,
1198 xs,
1199 ys));
1200 }
1201 EXRCORE_TEST_RVAL (exr_add_channel (
1202 f,
1203 partidx,
1204 "F",
1205 EXR_PIXEL_FLOAT,
1206 EXR_PERCEPTUALLY_LOGARITHMIC,
1207 xs,
1208 ys));
1209
1210 EXRCORE_TEST_RVAL (exr_write_header (f));
1211 if (tiled)
1212 doEncodeTile (f, p, xs, ys);
1213 else
1214 doEncodeScan (f, p, xs, ys);
1215 EXRCORE_TEST_RVAL (exr_finish (&f));
1216
1217 try
1218 {
1219 saveCPP (p, cppfilename, tiled, xs, ys, comp, fw, fh, dwx, dwy);
1220 }
1221 catch (std::exception& e)
1222 {
1223 std::cerr << "ERROR saving " << cppfilename << ": " << e.what ()
1224 << std::endl;
1225 EXRCORE_TEST_FAIL (saveCPP);
1226 }
1227
1228 pixels restore = p;
1229 pixels cpprestore = p;
1230 pixels cpploadc = p;
1231 pixels cpploadcpp = p;
1232
1233 restore.fillDead ();
1234 cpprestore.fillDead ();
1235 cpploadc.fillDead ();
1236 cpploadcpp.fillDead ();
1237
1238 EXRCORE_TEST_RVAL (exr_start_read (&f, filename.c_str (), &cinit));
1239 if (tiled)
1240 doDecodeTile (f, restore, xs, ys);
1241 else
1242 doDecodeScan (f, restore, xs, ys);
1243 EXRCORE_TEST_RVAL (exr_finish (&f));
1244
1245 EXRCORE_TEST_RVAL (exr_start_read (&f, cppfilename.c_str (), &cinit));
1246 if (tiled)
1247 doDecodeTile (f, cpprestore, xs, ys);
1248 else
1249 doDecodeScan (f, cpprestore, xs, ys);
1250 EXRCORE_TEST_RVAL (exr_finish (&f));
1251
1252 try
1253 {
1254 loadCPP (cpploadcpp, cppfilename, tiled, fw, fh, dwx, dwy);
1255 }
1256 catch (std::exception& e)
1257 {
1258 std::cerr << "ERROR loading " << cppfilename << ": " << e.what ()
1259 << std::endl;
1260 EXRCORE_TEST_FAIL (loadCPP);
1261 }
1262
1263 try
1264 {
1265 loadCPP (cpploadc, filename, tiled, fw, fh, dwx, dwy);
1266 }
1267 catch (std::exception& e)
1268 {
1269 std::cerr << "ERROR loading " << filename << ": " << e.what ()
1270 << std::endl;
1271 EXRCORE_TEST_FAIL (loadCPP);
1272 }
1273
1274 cpploadcpp.compareExact (cpploadc, "C++ loaded C", "C++ loaded C++");
1275 restore.compareExact (cpprestore, "C loaded C++", "C loaded C");
1276 restore.compareExact (cpploadc, "C++ loaded C", "C loaded C");
1277 restore.compareExact (cpploadcpp, "C++ loaded C++", "C loaded C");
1278
1279 switch (comp)
1280 {
1281 case EXR_COMPRESSION_NONE:
1282 case EXR_COMPRESSION_RLE:
1283 case EXR_COMPRESSION_ZIP:
1284 case EXR_COMPRESSION_ZIPS:
1285 restore.compareExact (p, "orig", "C loaded C");
1286 break;
1287 case EXR_COMPRESSION_PIZ:
1288 case EXR_COMPRESSION_PXR24:
1289 case EXR_COMPRESSION_B44:
1290 case EXR_COMPRESSION_B44A:
1291 case EXR_COMPRESSION_DWAA:
1292 case EXR_COMPRESSION_DWAB:
1293 restore.compareClose (p, comp, "orig", "C loaded C");
1294 break;
1295 case EXR_COMPRESSION_LAST_TYPE:
1296 default:
1297 std::cerr << "Unknown compression type " << (int) (comp)
1298 << std::endl;
1299 EXRCORE_TEST (false);
1300 break;
1301 }
1302 remove (filename.c_str ());
1303 remove (cppfilename.c_str ());
1304 }
1305
1306 ////////////////////////////////////////
1307
1308 static void
testWriteRead(pixels & p,const std::string & tempdir,exr_compression_t comp,const char * pattern)1309 testWriteRead (
1310 pixels& p,
1311 const std::string& tempdir,
1312 exr_compression_t comp,
1313 const char* pattern)
1314 {
1315 std::string filename =
1316 tempdir + pattern + std::string ("_imf_test_comp.exr");
1317 std::string cppfilename =
1318 tempdir + pattern + std::string ("_imf_test_comp_cpp.exr");
1319 const int maxsampling = 2;
1320 for (int xs = 1; xs <= maxsampling; ++xs)
1321 {
1322 for (int ys = 1; ys <= maxsampling; ++ys)
1323 {
1324 doWriteRead (
1325 p, filename, cppfilename, false, xs, ys, comp, pattern);
1326 if (xs == 1 && ys == 1)
1327 doWriteRead (
1328 p, filename, cppfilename, true, xs, ys, comp, pattern);
1329 }
1330 }
1331 }
1332
1333 ////////////////////////////////////////
1334
1335 static void
testComp(const std::string & tempdir,exr_compression_t comp)1336 testComp (const std::string& tempdir, exr_compression_t comp)
1337 {
1338 pixels p{ IMG_WIDTH, IMG_HEIGHT, IMG_STRIDE_X };
1339
1340 p.fillZero ();
1341 testWriteRead (p, tempdir, comp, "zeroes");
1342 p.fillPattern1 ();
1343 testWriteRead (p, tempdir, comp, "pattern1");
1344 p.fillPattern2 ();
1345 testWriteRead (p, tempdir, comp, "pattern2");
1346 p.fillRandom ();
1347 testWriteRead (p, tempdir, comp, "random");
1348 }
1349
1350 ////////////////////////////////////////
1351
1352 void
testHUF(const std::string & tempdir)1353 testHUF (const std::string& tempdir)
1354 {
1355 uint64_t esize = internal_exr_huf_compress_spare_bytes ();
1356 uint64_t dsize = internal_exr_huf_decompress_spare_bytes ();
1357 EXRCORE_TEST (esize == 65537 * (8 + 8 + sizeof (uint64_t*) + 4));
1358 EXRCORE_TEST (
1359 dsize == (65537 * 8 + (1 << 14) * (sizeof (uint32_t*) + 4 + 4)));
1360
1361 std::vector<uint8_t> hspare;
1362
1363 hspare.resize (std::max (esize, dsize));
1364 pixels p{ IMG_WIDTH, 1, IMG_STRIDE_X };
1365
1366 p.fillZero ();
1367 std::vector<uint8_t> encoded;
1368 encoded.resize (IMG_WIDTH * 2 * 3 + 65536);
1369 uint64_t ebytes;
1370 EXRCORE_TEST_RVAL (internal_huf_compress (
1371 &ebytes,
1372 encoded.data (),
1373 encoded.size (),
1374 p.h.data (),
1375 IMG_WIDTH,
1376 hspare.data (),
1377 esize));
1378 std::vector<uint8_t> cppencoded;
1379 cppencoded.resize (IMG_WIDTH * 2 * 3 + 65536);
1380
1381 uint64_t cppebytes =
1382 hufCompress (p.h.data (), IMG_WIDTH, (char*) (&cppencoded[0]));
1383 EXRCORE_TEST (ebytes == cppebytes);
1384 for (size_t i = 0; i < ebytes; ++i)
1385 {
1386 if (encoded[i] != cppencoded[i])
1387 {
1388 std::cerr << "Error: byte " << i << " differs between new (0x"
1389 << std::hex << (int) encoded[i] << std::dec
1390 << ") and old (0x" << std::hex << (int) cppencoded[i]
1391 << std::dec << ")" << std::endl;
1392 EXRCORE_TEST (encoded[i] == cppencoded[i]);
1393 }
1394 }
1395
1396 pixels decode = p;
1397 EXRCORE_TEST_RVAL (internal_huf_decompress (
1398 encoded.data (),
1399 ebytes,
1400 decode.h.data (),
1401 IMG_WIDTH,
1402 hspare.data (),
1403 dsize));
1404 for (size_t i = 0; i < IMG_WIDTH; ++i)
1405 {
1406 EXRCORE_TEST (decode.h[i] == p.h[i]);
1407 }
1408
1409 p.fillPattern1 ();
1410 EXRCORE_TEST_RVAL (internal_huf_compress (
1411 &ebytes,
1412 encoded.data (),
1413 encoded.size (),
1414 p.h.data (),
1415 IMG_WIDTH,
1416 hspare.data (),
1417 esize));
1418 cppebytes = hufCompress (p.h.data (), IMG_WIDTH, (char*) (&cppencoded[0]));
1419 EXRCORE_TEST (ebytes == cppebytes);
1420 for (size_t i = 0; i < ebytes; ++i)
1421 {
1422 if (encoded[i] != cppencoded[i])
1423 {
1424 std::cerr << "Error: byte " << i << " differs between new (0x"
1425 << std::hex << (int) encoded[i] << std::dec
1426 << ") and old (0x" << std::hex << (int) cppencoded[i]
1427 << std::dec << ")" << std::endl;
1428 EXRCORE_TEST (encoded[i] == cppencoded[i]);
1429 }
1430 }
1431 EXRCORE_TEST_RVAL (internal_huf_decompress (
1432 encoded.data (),
1433 ebytes,
1434 decode.h.data (),
1435 IMG_WIDTH,
1436 hspare.data (),
1437 dsize));
1438 for (size_t i = 0; i < IMG_WIDTH; ++i)
1439 {
1440 EXRCORE_TEST (decode.h[i] == p.h[i]);
1441 }
1442
1443 p.fillRandom ();
1444 EXRCORE_TEST_RVAL (internal_huf_compress (
1445 &ebytes,
1446 encoded.data (),
1447 encoded.size (),
1448 p.h.data (),
1449 IMG_WIDTH,
1450 hspare.data (),
1451 esize));
1452 cppebytes = hufCompress (p.h.data (), IMG_WIDTH, (char*) (&cppencoded[0]));
1453 EXRCORE_TEST (ebytes == cppebytes);
1454 for (size_t i = 0; i < ebytes; ++i)
1455 {
1456 if (encoded[i] != cppencoded[i])
1457 {
1458 std::cerr << "Error: byte " << i << " differs between new (0x"
1459 << std::hex << (int) encoded[i] << std::dec
1460 << ") and old (0x" << std::hex << (int) cppencoded[i]
1461 << std::dec << ")" << std::endl;
1462 EXRCORE_TEST (encoded[i] == cppencoded[i]);
1463 }
1464 }
1465 EXRCORE_TEST_RVAL (internal_huf_decompress (
1466 encoded.data (),
1467 ebytes,
1468 decode.h.data (),
1469 IMG_WIDTH,
1470 hspare.data (),
1471 dsize));
1472 for (size_t i = 0; i < IMG_WIDTH; ++i)
1473 {
1474 EXRCORE_TEST (decode.h[i] == p.h[i]);
1475 }
1476 }
1477
1478 ////////////////////////////////////////
1479
1480 void
testNoCompression(const std::string & tempdir)1481 testNoCompression (const std::string& tempdir)
1482 {
1483 testComp (tempdir, EXR_COMPRESSION_NONE);
1484 }
1485
1486 void
testRLECompression(const std::string & tempdir)1487 testRLECompression (const std::string& tempdir)
1488 {
1489 testComp (tempdir, EXR_COMPRESSION_RLE);
1490 }
1491
1492 void
testZIPCompression(const std::string & tempdir)1493 testZIPCompression (const std::string& tempdir)
1494 {
1495 testComp (tempdir, EXR_COMPRESSION_ZIP);
1496 }
1497
1498 void
testZIPSCompression(const std::string & tempdir)1499 testZIPSCompression (const std::string& tempdir)
1500 {
1501 testComp (tempdir, EXR_COMPRESSION_ZIPS);
1502 }
1503
1504 void
testPIZCompression(const std::string & tempdir)1505 testPIZCompression (const std::string& tempdir)
1506 {
1507 //testComp (tempdir, EXR_COMPRESSION_PIZ);
1508 }
1509
1510 void
testPXR24Compression(const std::string & tempdir)1511 testPXR24Compression (const std::string& tempdir)
1512 {
1513 testComp (tempdir, EXR_COMPRESSION_PXR24);
1514 }
1515
1516 void
testB44Compression(const std::string & tempdir)1517 testB44Compression (const std::string& tempdir)
1518 {
1519 testComp (tempdir, EXR_COMPRESSION_B44);
1520 }
1521
1522 void
testB44ACompression(const std::string & tempdir)1523 testB44ACompression (const std::string& tempdir)
1524 {
1525 testComp (tempdir, EXR_COMPRESSION_B44A);
1526 }
1527
1528 void
testDWAACompression(const std::string & tempdir)1529 testDWAACompression (const std::string& tempdir)
1530 {
1531 //testComp (tempdir, EXR_COMPRESSION_DWAA);
1532 }
1533
1534 void
testDWABCompression(const std::string & tempdir)1535 testDWABCompression (const std::string& tempdir)
1536 {
1537 //testComp (tempdir, EXR_COMPRESSION_DWAB);
1538 }
1539
1540 void
testDeepNoCompression(const std::string & tempdir)1541 testDeepNoCompression (const std::string& tempdir)
1542 {}
1543
1544 void
testDeepZIPCompression(const std::string & tempdir)1545 testDeepZIPCompression (const std::string& tempdir)
1546 {}
1547
1548 void
testDeepZIPSCompression(const std::string & tempdir)1549 testDeepZIPSCompression (const std::string& tempdir)
1550 {}
1551