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