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