1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright (c) Contributors to the OpenEXR Project.
4 //
5 
6 #ifdef NDEBUG
7 #    undef NDEBUG
8 #endif
9 
10 #include <iostream>
11 #include <string>
12 #include <vector>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <assert.h>
16 
17 #include "tmpDir.h"
18 #include "testCopyMultiPartFile.h"
19 #include "random.h"
20 
21 #include <IlmThreadPool.h>
22 #include <ImfMultiPartInputFile.h>
23 #include <ImfMultiPartOutputFile.h>
24 #include <ImfArray.h>
25 #include <ImfChannelList.h>
26 #include <ImfDeepFrameBuffer.h>
27 #include <ImfFrameBuffer.h>
28 #include <ImfOutputPart.h>
29 #include <ImfInputPart.h>
30 #include <ImfTiledOutputPart.h>
31 #include <ImfTiledInputPart.h>
32 #include <ImfDeepTiledOutputPart.h>
33 #include <ImfDeepScanLineOutputPart.h>
34 #include <ImfDeepTiledInputPart.h>
35 #include <ImfDeepScanLineInputPart.h>
36 #include <ImfPartType.h>
37 #include <ImfNamespace.h>
38 
39 
40 namespace IMF = OPENEXR_IMF_NAMESPACE;
41 using namespace IMF;
42 using namespace std;
43 using namespace IMATH_NAMESPACE;
44 using namespace ILMTHREAD_NAMESPACE;
45 
46 namespace
47 {
48 
49 const int height = 247;
50 const int width = 233;
51 
52 vector<Header> headers;
53 vector<int> pixelTypes;
54 vector<int> partTypes;
55 vector<int> levelModes;
56 
57 template <class T>
fillPixels(Array2D<T> & ph,int width,int height)58 void fillPixels (Array2D<T> &ph, int width, int height)
59 {
60     ph.resizeErase(height, width);
61     for (int y = 0; y < height; ++y)
62         for (int x = 0; x < width; ++x)
63         {
64             //
65             // We do this because half cannot store number bigger than 2048 exactly.
66             //
67             ph[y][x] = (y * width + x) % 2049;
68         }
69 }
70 
71 template <class T>
fillPixels(Array2D<unsigned int> & sampleCount,Array2D<T * > & ph,int width,int height)72 void fillPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph, int width, int height)
73 {
74     ph.resizeErase(height, width);
75     for (int y = 0; y < height; ++y)
76         for (int x = 0; x < width; ++x)
77         {
78             ph[y][x] = new T[sampleCount[y][x]];
79             for (unsigned int i = 0; i < sampleCount[y][x]; i++)
80             {
81                 //
82                 // We do this because half cannot store number bigger than 2048 exactly.
83                 //
84                 ph[y][x][i] = (y * width + x) % 2049;
85             }
86         }
87 }
88 
allocatePixels(int type,Array2D<unsigned int> & sampleCount,Array2D<unsigned int * > & uintData,Array2D<float * > & floatData,Array2D<half * > & halfData,int x1,int x2,int y1,int y2)89 void allocatePixels(int type, Array2D<unsigned int>& sampleCount,
90                     Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
91                     Array2D<half*>& halfData, int x1, int x2, int y1, int y2)
92 {
93     for (int y = y1; y <= y2; y++)
94         for (int x = x1; x <= x2; x++)
95         {
96             if (type == 0)
97                 uintData[y][x] = new unsigned int[sampleCount[y][x]];
98             if (type == 1)
99                 floatData[y][x] = new float[sampleCount[y][x]];
100             if (type == 2)
101                 halfData[y][x] = new half[sampleCount[y][x]];
102         }
103 }
104 
allocatePixels(int type,Array2D<unsigned int> & sampleCount,Array2D<unsigned int * > & uintData,Array2D<float * > & floatData,Array2D<half * > & halfData,int width,int height)105 void allocatePixels(int type, Array2D<unsigned int>& sampleCount,
106                     Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
107                     Array2D<half*>& halfData, int width, int height)
108 {
109     allocatePixels(type, sampleCount, uintData, floatData, halfData, 0, width - 1, 0, height - 1);
110 }
111 
releasePixels(int type,Array2D<unsigned int * > & uintData,Array2D<float * > & floatData,Array2D<half * > & halfData,int x1,int x2,int y1,int y2)112 void releasePixels(int type, Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
113                    Array2D<half*>& halfData, int x1, int x2, int y1, int y2)
114 {
115     for (int y = y1; y <= y2; y++)
116         for (int x = x1; x <= x2; x++)
117         {
118             if (type == 0)
119                 delete[] uintData[y][x];
120             if (type == 1)
121                 delete[] floatData[y][x];
122             if (type == 2)
123                 delete[] halfData[y][x];
124         }
125 }
126 
releasePixels(int type,Array2D<unsigned int * > & uintData,Array2D<float * > & floatData,Array2D<half * > & halfData,int width,int height)127 void releasePixels(int type, Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
128                    Array2D<half*>& halfData, int width, int height)
129 {
130     releasePixels(type, uintData, floatData, halfData, 0, width - 1, 0, height - 1);
131 }
132 
133 template <class T>
checkPixels(Array2D<T> & ph,int lx,int rx,int ly,int ry,int width)134 bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
135 {
136     for (int y = ly; y <= ry; ++y)
137         for (int x = lx; x <= rx; ++x)
138             if (ph[y][x] != static_cast<T>(((y * width + x) % 2049)))
139             {
140                 cout << "value at " << x << ", " << y << ": " << ph[y][x]
141                      << ", should be " << (y * width + x) % 2049 << endl << flush;
142                 return false;
143             }
144     return true;
145 }
146 
147 template <class T>
checkPixels(Array2D<T> & ph,int width,int height)148 bool checkPixels (Array2D<T> &ph, int width, int height)
149 {
150     return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
151 }
152 
153 template <class T>
checkPixels(Array2D<unsigned int> & sampleCount,Array2D<T * > & ph,int lx,int rx,int ly,int ry,int width)154 bool checkPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph,
155                   int lx, int rx, int ly, int ry, int width)
156 {
157     for (int y = ly; y <= ry; ++y)
158         for (int x = lx; x <= rx; ++x)
159         {
160             for (unsigned int i = 0; i < sampleCount[y][x]; i++)
161             {
162                 if (ph[y][x][i] != static_cast<T>(((y * width + x) % 2049)))
163                 {
164                     cout << "value at " << x << ", " << y << ", sample " << i << ": " << ph[y][x][i]
165                          << ", should be " << (y * width + x) % 2049 << endl << flush;
166                     return false;
167                 }
168             }
169         }
170     return true;
171 }
172 
173 template <class T>
checkPixels(Array2D<unsigned int> & sampleCount,Array2D<T * > & ph,int width,int height)174 bool checkPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph, int width, int height)
175 {
176     return checkPixels<T> (sampleCount, ph, 0, width - 1, 0, height - 1, width);
177 }
178 
179 #if 0
180 bool checkSampleCount(Array2D<unsigned int>& sampleCount, int x1, int x2, int y1, int y2, int width)
181 {
182     for (int i = y1; i <= y2; i++)
183         for (int j = x1; j <= x2; j++)
184         {
185             if (sampleCount[i][j] != ((i * width) + j) % 10 + 1)
186             {
187                 cout << "sample count at " << j << ", " << i << ": " << sampleCount[i][j]
188                      << ", should be " << (i * width + j) % 10 + 1 << endl << flush;
189                 return false;
190             }
191         }
192     return true;
193 }
194 
195 
196 bool checkSampleCount(Array2D<unsigned int>& sampleCount, int width, int height)
197 {
198     return checkSampleCount(sampleCount, 0, width - 1, 0, height - 1, width);
199 }
200 #endif
201 
generateRandomHeaders(int partCount,vector<Header> & headers)202 void generateRandomHeaders(int partCount, vector<Header>& headers)
203 {
204     cout << "Generating headers and data" << endl << flush;
205 
206     headers.clear();
207     for (int i = 0; i < partCount; i++)
208     {
209         Header header (width,
210                        height,
211                        1.f,
212                        IMATH_NAMESPACE::V2f (0, 0),
213                        1.f,
214                        INCREASING_Y,
215                        ZIPS_COMPRESSION);
216 
217         int pixelType = random_int(3);
218         int partType = random_int(4);
219 
220         pixelTypes[i] = pixelType;
221         partTypes[i] = partType;
222 
223         stringstream ss;
224         ss << i;
225         header.setName(ss.str());
226 
227         switch (pixelType)
228         {
229             case 0:
230                 header.channels().insert("UINT", Channel(IMF::UINT));
231                 break;
232             case 1:
233                 header.channels().insert("FLOAT", Channel(IMF::FLOAT));
234                 break;
235             case 2:
236                 header.channels().insert("HALF", Channel(IMF::HALF));
237                 break;
238         }
239 
240         switch (partType)
241         {
242             case 0:
243                 header.setType(SCANLINEIMAGE);
244                 break;
245             case 1:
246                 header.setType(TILEDIMAGE);
247                 break;
248             case 2:
249                 header.setType(DEEPSCANLINE);
250                 break;
251             case 3:
252                 header.setType(DEEPTILE);
253                 break;
254         }
255 
256         int tileX;
257         int tileY;
258         int levelMode;
259         if (partType == 1 || partType == 3)
260         {
261             tileX = random_int(width) + 1;
262             tileY = random_int(height) + 1;
263             levelMode = random_int(3);
264             levelModes[i] = levelMode;
265             LevelMode lm  = NUM_LEVELMODES;
266             switch (levelMode)
267             {
268                 case 0:
269                     lm = ONE_LEVEL;
270                     break;
271                 case 1:
272                     lm = MIPMAP_LEVELS;
273                     break;
274                 case 2:
275                     lm = RIPMAP_LEVELS;
276                     break;
277             }
278             header.setTileDescription(TileDescription(tileX, tileY, lm));
279         }
280 
281 
282         int order = random_int(NUM_LINEORDERS);
283         if(partType==0 || partType ==2)
284         {
285             // can't write random scanlines
286             order = random_int(NUM_LINEORDERS-1);
287         }
288         LineOrder l = NUM_LINEORDERS;
289         switch(order)
290         {
291              case 0 :
292                  l = INCREASING_Y;
293                  break;
294              case 1 :
295                   l = DECREASING_Y;
296                  break;
297              case 2 :
298                   l = RANDOM_Y;
299                   break;
300         }
301 
302         header.lineOrder()=l;
303 
304 
305         if (partType == 0 || partType == 2)
306         {
307             cout << "pixelType = " << pixelType << " partType = " << partType
308                  << " line order =" << header.lineOrder() << endl << flush;
309         }
310         else
311         {
312             cout << "pixelType = " << pixelType << " partType = " << partType
313                  << " tile order =" << header.lineOrder()
314                  << " levelMode = " << levelModes[i] << endl << flush;
315         }
316 
317         headers.push_back(header);
318     }
319 }
320 
setOutputFrameBuffer(FrameBuffer & frameBuffer,int pixelType,Array2D<unsigned int> & uData,Array2D<float> & fData,Array2D<half> & hData,int width)321 void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
322                           Array2D<unsigned int>& uData, Array2D<float>& fData,
323                           Array2D<half>& hData, int width)
324 {
325     switch (pixelType)
326     {
327         case 0:
328             frameBuffer.insert ("UINT",
329                                 Slice (IMF::UINT,
330                                 (char *) (&uData[0][0]),
331                                 sizeof (uData[0][0]) * 1,
332                                 sizeof (uData[0][0]) * width));
333             break;
334         case 1:
335             frameBuffer.insert ("FLOAT",
336                                 Slice (IMF::FLOAT,
337                                 (char *) (&fData[0][0]),
338                                 sizeof (fData[0][0]) * 1,
339                                 sizeof (fData[0][0]) * width));
340             break;
341         case 2:
342             frameBuffer.insert ("HALF",
343                                 Slice (IMF::HALF,
344                                 (char *) (&hData[0][0]),
345                                 sizeof (hData[0][0]) * 1,
346                                 sizeof (hData[0][0]) * width));
347             break;
348     }
349 }
350 
setOutputDeepFrameBuffer(DeepFrameBuffer & frameBuffer,int pixelType,Array2D<unsigned int * > & uData,Array2D<float * > & fData,Array2D<half * > & hData,int width)351 void setOutputDeepFrameBuffer(DeepFrameBuffer& frameBuffer, int pixelType,
352                           Array2D<unsigned int*>& uData, Array2D<float*>& fData,
353                           Array2D<half*>& hData, int width)
354 {
355     switch (pixelType)
356     {
357         case 0:
358             frameBuffer.insert ("UINT",
359                                 DeepSlice (IMF::UINT,
360                                 (char *) (&uData[0][0]),
361                                 sizeof (uData[0][0]) * 1,
362                                 sizeof (uData[0][0]) * width,
363                                 sizeof (unsigned int)));
364             break;
365         case 1:
366             frameBuffer.insert ("FLOAT",
367                                 DeepSlice (IMF::FLOAT,
368                                 (char *) (&fData[0][0]),
369                                 sizeof (fData[0][0]) * 1,
370                                 sizeof (fData[0][0]) * width,
371                                 sizeof (float)));
372             break;
373         case 2:
374             frameBuffer.insert ("HALF",
375                                 DeepSlice (IMF::HALF,
376                                 (char *) (&hData[0][0]),
377                                 sizeof (hData[0][0]) * 1,
378                                 sizeof (hData[0][0]) * width,
379                                 sizeof (half)));
380             break;
381     }
382 }
383 
setInputFrameBuffer(FrameBuffer & frameBuffer,int pixelType,Array2D<unsigned int> & uData,Array2D<float> & fData,Array2D<half> & hData,int width,int height)384 void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
385                          Array2D<unsigned int>& uData, Array2D<float>& fData,
386                          Array2D<half>& hData, int width, int height)
387 {
388     switch (pixelType)
389     {
390         case 0:
391             uData.resizeErase(height, width);
392             frameBuffer.insert ("UINT",
393                                 Slice (IMF::UINT,
394                                 (char *) (&uData[0][0]),
395                                 sizeof (uData[0][0]) * 1,
396                                 sizeof (uData[0][0]) * width,
397                                 1, 1,
398                                 0));
399             break;
400         case 1:
401             fData.resizeErase(height, width);
402             frameBuffer.insert ("FLOAT",
403                                 Slice (IMF::FLOAT,
404                                 (char *) (&fData[0][0]),
405                                 sizeof (fData[0][0]) * 1,
406                                 sizeof (fData[0][0]) * width,
407                                 1, 1,
408                                 0));
409             break;
410         case 2:
411             hData.resizeErase(height, width);
412             frameBuffer.insert ("HALF",
413                                 Slice (IMF::HALF,
414                                 (char *) (&hData[0][0]),
415                                 sizeof (hData[0][0]) * 1,
416                                 sizeof (hData[0][0]) * width,
417                                 1, 1,
418                                 0));
419             break;
420     }
421 }
422 
setInputDeepFrameBuffer(DeepFrameBuffer & frameBuffer,int pixelType,Array2D<unsigned int * > & uData,Array2D<float * > & fData,Array2D<half * > & hData,int width,int height)423 void setInputDeepFrameBuffer(DeepFrameBuffer& frameBuffer, int pixelType,
424                              Array2D<unsigned int*>& uData, Array2D<float*>& fData,
425                              Array2D<half*>& hData, int width, int height)
426 {
427     switch (pixelType)
428     {
429         case 0:
430             uData.resizeErase(height, width);
431             frameBuffer.insert ("UINT",
432                                 DeepSlice (IMF::UINT,
433                                 (char *) (&uData[0][0]),
434                                 sizeof (uData[0][0]) * 1,
435                                 sizeof (uData[0][0]) * width,
436                                 sizeof (unsigned int)));
437             break;
438         case 1:
439             fData.resizeErase(height, width);
440             frameBuffer.insert ("FLOAT",
441                                 DeepSlice (IMF::FLOAT,
442                                 (char *) (&fData[0][0]),
443                                 sizeof (fData[0][0]) * 1,
444                                 sizeof (fData[0][0]) * width,
445                                 sizeof (float)));
446             break;
447         case 2:
448             hData.resizeErase(height, width);
449             frameBuffer.insert ("HALF",
450                                 DeepSlice (IMF::HALF,
451                                 (char *) (&hData[0][0]),
452                                 sizeof (hData[0][0]) * 1,
453                                 sizeof (hData[0][0]) * width,
454                                 sizeof (half)));
455             break;
456     }
457 }
458 
459 void
generateRandomFile(int partCount,const std::string & srcFn)460 generateRandomFile (int partCount, const std::string & srcFn)
461 {
462     //
463     // Init data.
464     //
465     Array2D<half> halfData;
466     Array2D<float> floatData;
467     Array2D<unsigned int> uintData;
468 
469     Array2D<unsigned int> sampleCount;
470     Array2D<half*> deepHalfData;
471     Array2D<float*> deepFloatData;
472     Array2D<unsigned int*> deepUintData;
473 
474     vector<GenericOutputFile*> outputfiles;
475 
476     pixelTypes.resize(partCount);
477     partTypes.resize(partCount);
478     levelModes.resize(partCount);
479 
480     //
481     // Generate headers and data.
482     //
483     generateRandomHeaders(partCount, headers);
484 
485     remove(srcFn.c_str());
486     MultiPartOutputFile file(srcFn.c_str(), &headers[0],headers.size());
487 
488     //
489     // Writing files.
490     //
491     cout << "Writing files " << flush;
492 
493     //
494     // Pre-generating frameBuffers.
495     //
496     for (int i = 0; i < partCount; i++)
497     {
498         switch (partTypes[i])
499         {
500             case 0:
501             {
502                 OutputPart part(file, i);
503 
504                 FrameBuffer frameBuffer;
505 
506                 fillPixels <unsigned int> (uintData, width, height);
507                 fillPixels <float> (floatData, width, height);
508                 fillPixels <half> (halfData, width, height);
509 
510                 setOutputFrameBuffer(frameBuffer, pixelTypes[i], uintData, floatData, halfData, width);
511 
512                 part.setFrameBuffer(frameBuffer);
513 
514                 part.writePixels(height);
515 
516                 break;
517             }
518             case 1:
519             {
520                 TiledOutputPart part(file, i);
521 
522                 int numXLevels = part.numXLevels();
523                 int numYLevels = part.numYLevels();
524 
525                 for (int xLevel = 0; xLevel < numXLevels; xLevel++)
526                     for (int yLevel = 0; yLevel < numYLevels; yLevel++)
527                     {
528                         if (!part.isValidLevel(xLevel, yLevel))
529                             continue;
530 
531                         int w = part.levelWidth(xLevel);
532                         int h = part.levelHeight(yLevel);
533 
534                         FrameBuffer frameBuffer;
535 
536                         fillPixels <unsigned int> (uintData, w, h);
537                         fillPixels <float> (floatData, w, h);
538                         fillPixels <half> (halfData, w, h);
539                         setOutputFrameBuffer(frameBuffer, pixelTypes[i],
540                                              uintData, floatData, halfData,
541                                              w);
542 
543                         part.setFrameBuffer(frameBuffer);
544 
545                         part.writeTiles(0, part.numXTiles(xLevel) - 1,
546                                         0, part.numYTiles(yLevel) - 1,
547                                         xLevel, yLevel);
548                     }
549 
550                 break;
551             }
552             case 2:
553             {
554                 DeepScanLineOutputPart part(file, i);
555 
556                 DeepFrameBuffer frameBuffer;
557 
558                 sampleCount.resizeErase(height, width);
559                 for (int j = 0; j < height; j++)
560                     for (int k = 0; k < width; k++)
561                         sampleCount[j][k] = (j * width + k) % 10 + 1;
562 
563                 frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
564                                                     (char *) (&sampleCount[0][0]),
565                                                     sizeof (unsigned int) * 1,
566                                                     sizeof (unsigned int) * width));
567 
568                 if (pixelTypes[i] == 0)
569                     fillPixels <unsigned int> (sampleCount, deepUintData, width, height);
570                 if (pixelTypes[i] == 1)
571                     fillPixels <float> (sampleCount, deepFloatData, width, height);
572                 if (pixelTypes[i] == 2)
573                     fillPixels <half> (sampleCount, deepHalfData, width, height);
574                 setOutputDeepFrameBuffer(frameBuffer, pixelTypes[i],
575                                          deepUintData, deepFloatData, deepHalfData,
576                                          width);
577 
578                 part.setFrameBuffer(frameBuffer);
579 
580                 part.writePixels(height);
581 
582                 releasePixels(pixelTypes[i], deepUintData, deepFloatData, deepHalfData, width, height);
583 
584                 break;
585             }
586             case 3:
587             {
588                 DeepTiledOutputPart part(file, i);
589 
590                 int numXLevels = part.numXLevels();
591                 int numYLevels = part.numYLevels();
592 
593                 for (int xLevel = 0; xLevel < numXLevels; xLevel++)
594                     for (int yLevel = 0; yLevel < numYLevels; yLevel++)
595                     {
596                         if (!part.isValidLevel(xLevel, yLevel))
597                             continue;
598 
599                         int w = part.levelWidth(xLevel);
600                         int h = part.levelHeight(yLevel);
601 
602                         DeepFrameBuffer frameBuffer;
603 
604                         sampleCount.resizeErase(h, w);
605                         for (int j = 0; j < h; j++)
606                             for (int k = 0; k < w; k++)
607                                 sampleCount[j][k] = (j * w + k) % 10 + 1;
608 
609                         frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
610                                                             (char *) (&sampleCount[0][0]),
611                                                             sizeof (unsigned int) * 1,
612                                                             sizeof (unsigned int) * w));
613 
614                         if (pixelTypes[i] == 0)
615                             fillPixels <unsigned int> (sampleCount, deepUintData, w, h);
616                         if (pixelTypes[i] == 1)
617                             fillPixels <float> (sampleCount, deepFloatData, w, h);
618                         if (pixelTypes[i] == 2)
619                             fillPixels <half> (sampleCount, deepHalfData, w, h);
620                         setOutputDeepFrameBuffer(frameBuffer, pixelTypes[i],
621                                                  deepUintData, deepFloatData, deepHalfData,
622                                                  w);
623 
624                         part.setFrameBuffer(frameBuffer);
625 
626                         part.writeTiles(0, part.numXTiles(xLevel) - 1,
627                                         0, part.numYTiles(yLevel) - 1,
628                                         xLevel, yLevel);
629 
630                         releasePixels(pixelTypes[i], deepUintData, deepFloatData, deepHalfData, w, h);
631                     }
632 
633                 break;
634             }
635         }
636     }
637 }
638 
639 void
readWholeFiles(const std::string & cpyFn)640 readWholeFiles (const std::string & cpyFn)
641 {
642     Array2D<unsigned int> uData;
643     Array2D<float> fData;
644     Array2D<half> hData;
645 
646     Array2D<unsigned int*> deepUData;
647     Array2D<float*> deepFData;
648     Array2D<half*> deepHData;
649 
650     Array2D<unsigned int> sampleCount;
651 
652     MultiPartInputFile file(cpyFn.c_str());
653     for (int i = 0; i < file.parts(); i++)
654     {
655         const Header& header = file.header(i);
656         assert (header.displayWindow() == headers[i].displayWindow());
657         assert (header.dataWindow() == headers[i].dataWindow());
658         assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
659         assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
660         assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
661         assert (header.lineOrder() == headers[i].lineOrder());
662         assert (header.compression() == headers[i].compression());
663         assert (header.channels() == headers[i].channels());
664         assert (header.name() == headers[i].name());
665         assert (header.type() == headers[i].type());
666     }
667 
668     cout << "Reading whole files " << flush;
669 
670     //
671     // Shuffle part numbers.
672     //
673     vector<int> shuffledPartNumber;
674     int nHeaders = static_cast<int>(headers.size());
675     for (int i = 0; i < nHeaders; i++)
676         shuffledPartNumber.push_back(i);
677     for (int i = 0; i < nHeaders; i++)
678     {
679         int a = random_int(nHeaders);
680         int b = random_int(nHeaders);
681         swap (shuffledPartNumber[a], shuffledPartNumber[b]);
682     }
683 
684     //
685     // Start reading whole files.
686     //
687     int i;
688     int partNumber;
689     try
690     {
691         for (i = 0; i < nHeaders; i++)
692         {
693             partNumber = shuffledPartNumber[i];
694             switch (partTypes[partNumber])
695             {
696                 case 0:
697                 {
698                     FrameBuffer frameBuffer;
699                     setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
700                                         uData, fData, hData, width, height);
701 
702                     InputPart part(file, partNumber);
703                     part.setFrameBuffer(frameBuffer);
704                     part.readPixels(0, height - 1);
705                     switch (pixelTypes[partNumber])
706                     {
707                         case 0:
708                             assert(checkPixels<unsigned int>(uData, width, height));
709                             break;
710                         case 1:
711                             assert(checkPixels<float>(fData, width, height));
712                             break;
713                         case 2:
714                             assert(checkPixels<half>(hData, width, height));
715                             break;
716                     }
717                     break;
718                 }
719                 case 1:
720                 {
721                     TiledInputPart part(file, partNumber);
722                     int numXLevels = part.numXLevels();
723                     int numYLevels = part.numYLevels();
724                     for (int xLevel = 0; xLevel < numXLevels; xLevel++)
725                         for (int yLevel = 0; yLevel < numYLevels; yLevel++)
726                         {
727                             if (!part.isValidLevel(xLevel, yLevel))
728                                 continue;
729 
730                             int w = part.levelWidth(xLevel);
731                             int h = part.levelHeight(yLevel);
732 
733                             FrameBuffer frameBuffer;
734                             setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
735                                                 uData, fData, hData, w, h);
736 
737                             part.setFrameBuffer(frameBuffer);
738                             int numXTiles = part.numXTiles(xLevel);
739                             int numYTiles = part.numYTiles(yLevel);
740                             part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
741                             switch (pixelTypes[partNumber])
742                             {
743                                 case 0:
744                                     assert(checkPixels<unsigned int>(uData, w, h));
745                                     break;
746                                 case 1:
747                                     assert(checkPixels<float>(fData, w, h));
748                                     break;
749                                 case 2:
750                                     assert(checkPixels<half>(hData, w, h));
751                                     break;
752                             }
753                         }
754                     break;
755                 }
756                 case 2:
757                 {
758                     DeepScanLineInputPart part(file, partNumber);
759 
760                     DeepFrameBuffer frameBuffer;
761 
762                     sampleCount.resizeErase(height, width);
763                     frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
764                                                         (char *) (&sampleCount[0][0]),
765                                                         sizeof (unsigned int) * 1,
766                                                         sizeof (unsigned int) * width));
767 
768                     setInputDeepFrameBuffer(frameBuffer, pixelTypes[partNumber],
769                                             deepUData, deepFData, deepHData, width, height);
770 
771                     part.setFrameBuffer(frameBuffer);
772 
773                     part.readPixelSampleCounts(0, height - 1);
774 
775                     allocatePixels(pixelTypes[partNumber], sampleCount,
776                                    deepUData, deepFData, deepHData, width, height);
777 
778                     part.readPixels(0, height - 1);
779                     switch (pixelTypes[partNumber])
780                     {
781                         case 0:
782                             assert(checkPixels<unsigned int>(sampleCount, deepUData, width, height));
783                             break;
784                         case 1:
785                             assert(checkPixels<float>(sampleCount, deepFData, width, height));
786                             break;
787                         case 2:
788                             assert(checkPixels<half>(sampleCount, deepHData, width, height));
789                             break;
790                     }
791 
792                     releasePixels(pixelTypes[partNumber],
793                                   deepUData, deepFData, deepHData, width, height);
794 
795                     break;
796                 }
797                 case 3:
798                 {
799                     DeepTiledInputPart part(file, partNumber);
800                     int numXLevels = part.numXLevels();
801                     int numYLevels = part.numYLevels();
802                     for (int xLevel = 0; xLevel < numXLevels; xLevel++)
803                         for (int yLevel = 0; yLevel < numYLevels; yLevel++)
804                         {
805                             if (!part.isValidLevel(xLevel, yLevel))
806                                 continue;
807 
808                             int w = part.levelWidth(xLevel);
809                             int h = part.levelHeight(yLevel);
810 
811                             DeepFrameBuffer frameBuffer;
812 
813                             sampleCount.resizeErase(h, w);
814                             frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
815                                                                 (char *) (&sampleCount[0][0]),
816                                                                 sizeof (unsigned int) * 1,
817                                                                 sizeof (unsigned int) * w));
818 
819                             setInputDeepFrameBuffer(frameBuffer, pixelTypes[partNumber],
820                                                     deepUData, deepFData, deepHData, w, h);
821 
822                             part.setFrameBuffer(frameBuffer);
823 
824                             int numXTiles = part.numXTiles(xLevel);
825                             int numYTiles = part.numYTiles(yLevel);
826 
827                             part.readPixelSampleCounts(0, numXTiles - 1, 0, numYTiles - 1,
828                                                        xLevel, yLevel);
829 
830                             allocatePixels(pixelTypes[partNumber], sampleCount,
831                                            deepUData, deepFData, deepHData, w, h);
832 
833                             part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
834                             switch (pixelTypes[partNumber])
835                             {
836                                 case 0:
837                                     assert(checkPixels<unsigned int>(sampleCount, deepUData, w, h));
838                                     break;
839                                 case 1:
840                                     assert(checkPixels<float>(sampleCount, deepFData, w, h));
841                                     break;
842                                 case 2:
843                                     assert(checkPixels<half>(sampleCount, deepHData, w, h));
844                                     break;
845                             }
846 
847                             releasePixels(pixelTypes[partNumber],
848                                           deepUData, deepFData, deepHData, w, h);
849                         }
850 
851                     break;
852                 }
853             }
854         }
855     }
856     catch (...)
857     {
858         cout << "Error while reading part " << partNumber << endl << flush;
859         throw;
860     }
861 }
862 
863 
864 void
copyFile(const std::string & srcFn,const std::string & cpyFn)865 copyFile (const std::string & srcFn, const std::string & cpyFn)
866 {
867     cout << "copying ";
868     cout.flush();
869 
870     MultiPartInputFile in(srcFn.c_str());
871 
872 
873     vector<Header> in_hdr(in.parts());
874     for(int i=0;i<in.parts();i++)
875     {
876         in_hdr[i]=in.header(i);
877     }
878 
879     MultiPartOutputFile out(cpyFn.c_str(),&in_hdr[0],in.parts());
880     for(int i=0;i<in.parts();i++)
881     {
882         std::string part_type = in.header(i).type();
883         if(part_type == DEEPSCANLINE)
884         {
885             DeepScanLineInputPart partin(in,i);
886             DeepScanLineOutputPart partout(out,i);
887             partout.copyPixels(partin);
888         }
889         else if(part_type == DEEPTILE)
890         {
891             DeepTiledInputPart partin(in,i);
892             DeepTiledOutputPart partout(out,i);
893             partout.copyPixels(partin);
894         }else if(part_type== SCANLINEIMAGE)
895         {
896             InputPart partin(in,i);
897             OutputPart partout(out,i);
898             partout.copyPixels(partin);
899         }
900         else if(part_type==TILEDIMAGE)
901         {
902             TiledInputPart partin(in,i);
903             TiledOutputPart partout(out,i);
904             partout.copyPixels(partin);
905         }
906     }
907 
908 }
909 
910 void
testWriteCopyRead(int partNumber,int runCount,int randomReadCount,const std::string & tempDir)911 testWriteCopyRead (int partNumber,
912                    int runCount,
913                    int randomReadCount,
914                    const std::string & tempDir)
915 {
916     cout << "Testing file with " << partNumber << " part(s)." << endl << flush;
917 
918     std::string srcFn = tempDir +  "imf_test_copy_multipart_source.exr";
919     std::string cpyFn = tempDir +  "imf_test_copy_multipart_copy.exr";
920 
921     for (int i = 0; i < runCount; i++)
922     {
923         generateRandomFile (partNumber, srcFn);
924         copyFile (srcFn, cpyFn);
925         remove (srcFn.c_str());
926         readWholeFiles (cpyFn);
927         remove (cpyFn.c_str());
928 
929         cout << endl << flush;
930     }
931 }
932 
933 } // namespace
934 
testCopyMultiPartFile(const std::string & tempDir)935 void testCopyMultiPartFile (const std::string & tempDir)
936 {
937     try
938     {
939         cout << "Testing copying multi-part files" << endl;
940 
941         random_reseed(1);
942 
943         int numThreads = ThreadPool::globalThreadPool().numThreads();
944         ThreadPool::globalThreadPool().setNumThreads(4);
945 
946         testWriteCopyRead ( 2, 20,  10, tempDir);
947         testWriteCopyRead ( 1, 10,   5, tempDir);
948         testWriteCopyRead ( 5,  4,  25, tempDir);
949         testWriteCopyRead (50,  1, 250, tempDir);
950 
951         ThreadPool::globalThreadPool().setNumThreads(numThreads);
952 
953         cout << "ok\n" << endl;
954     }
955     catch (const std::exception &e)
956     {
957         cerr << "ERROR -- caught exception: " << e.what() << endl;
958         assert (false);
959     }
960 }
961