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 <ImfRgbaFile.h>
11 #include <ImfTiledRgbaFile.h>
12 #include <ImfMultiPartInputFile.h>
13 #include <ImfMultiPartOutputFile.h>
14 #include <ImfPartType.h>
15 #include <ImfInputPart.h>
16 #include <ImfOutputPart.h>
17 #include <ImfStdIO.h>
18 #include <ImfArray.h>
19
20 #include <stdio.h>
21 #include <assert.h>
22 #include "Iex.h"
23 #include <errno.h>
24
25 #include <vector>
26 #include <ImfChannelList.h>
27
28 #include "TestUtilFStream.h"
29
30 using namespace OPENEXR_IMF_NAMESPACE;
31 using namespace std;
32 using namespace IMATH_NAMESPACE;
33
34 namespace {
35
36 void
fillPixels1(Array2D<Rgba> & pixels,int w,int h)37 fillPixels1 (Array2D<Rgba> &pixels, int w, int h)
38 {
39 for (int y = 0; y < h; ++y)
40 {
41 for (int x = 0; x < w; ++x)
42 {
43 Rgba &p = pixels[y][x];
44
45 p.r = (x & 1);
46 p.g = ((x + y) & 1);
47 p.b = (y & 1);
48 p.a = (p.r + p.b + p.g) / 3.0;
49 }
50 }
51 }
52
53
54 void
fillPixels2(Array2D<Rgba> & pixels,int w,int h)55 fillPixels2 (Array2D<Rgba> &pixels, int w, int h)
56 {
57 for (int y = 0; y < h; ++y)
58 {
59 for (int x = 0; x < w; ++x)
60 {
61 Rgba &p = pixels[y][x];
62
63 p.r = (x & 2);
64 p.g = ((x + y) & 2);
65 p.b = (y & 2);
66 p.a = (p.r + p.b + p.g) / 3.0;
67 }
68 }
69 }
70
71
72 //
73 // class MMIFStream -- a memory-mapped implementation of
74 // class IStream based on class std::ifstream
75 //
76
77 class MMIFStream: public OPENEXR_IMF_NAMESPACE::IStream
78 {
79 public:
80
81 //-------------------------------------------------------
82 // A constructor that opens the file with the given name.
83 // It reads the whole file into an internal buffer and
84 // then immediately closes the file.
85 //-------------------------------------------------------
86
87 MMIFStream (const char fileName[]);
88
89 virtual ~MMIFStream ();
90
isMemoryMapped() const91 virtual bool isMemoryMapped () const {return true;}
92
93 virtual bool read (char c[/*n*/], int n);
94 virtual char* readMemoryMapped (int n);
tellg()95 virtual uint64_t tellg () {return _pos;}
seekg(uint64_t pos)96 virtual void seekg (uint64_t pos) {_pos = pos;}
clear()97 virtual void clear () {}
98
99 private:
100
101 char* _buffer;
102 uint64_t _length;
103 uint64_t _pos;
104 };
105
106
107
MMIFStream(const char fileName[])108 MMIFStream::MMIFStream (const char fileName[]):
109 OPENEXR_IMF_NAMESPACE::IStream (fileName),
110 _buffer (0),
111 _length (0),
112 _pos (0)
113 {
114 std::ifstream ifs;
115 testutil::OpenStreamWithUTF8Name (
116 ifs, fileName, ios::in | ios_base::binary);
117
118 //
119 // Get length of file
120 //
121
122 ifs.seekg (0, ios::end);
123 _length = ifs.tellg();
124 ifs.seekg (0, ios::beg);
125
126 //
127 // Allocate memory
128 //
129
130 _buffer = new char [_length];
131
132 //
133 // Read the entire file
134 //
135
136 ifs.read (_buffer, _length);
137 ifs.close();
138 }
139
140
~MMIFStream()141 MMIFStream::~MMIFStream ()
142 {
143 delete [] _buffer;
144 }
145
146
147 bool
read(char c[],int n)148 MMIFStream::read (char c[/*n*/], int n)
149 {
150 if (_pos >= _length && n != 0)
151 throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
152
153 uint64_t n2 = n;
154 bool retVal = true;
155
156 if (_length - _pos <= n2)
157 {
158 n2 = _length - _pos;
159 retVal = false;
160 }
161
162 memcpy (c, &(_buffer[_pos]), n2);
163 _pos += n2;
164 return retVal;
165 }
166
167
168 char*
readMemoryMapped(int n)169 MMIFStream::readMemoryMapped (int n)
170 {
171 if (_pos >= _length)
172 throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
173
174 if (_pos + n > _length)
175 throw IEX_NAMESPACE::InputExc ("Reading past end of file.");
176
177 char* retVal = &(_buffer[_pos]);
178 _pos += n;
179 return retVal;
180 }
181
182
183 void
writeReadScanLines(const char fileName[],int width,int height,const Array2D<Rgba> & p1)184 writeReadScanLines (const char fileName[],
185 int width,
186 int height,
187 const Array2D<Rgba> &p1)
188 {
189 //
190 // Save a scanline-based RGBA image, but instead of
191 // letting the RgbaOutputFile object open the file,
192 // make the RgbaOutputFile object use an existing
193 // StdOFStream. Read the image back, using an
194 // existing StdIFStream, and compare the pixels
195 // with the original data. Then read the image
196 // back a second time using a memory-mapped
197 // MMIFStream (see above).
198 //
199
200 cout << "scan-line based file:" << endl;
201
202 {
203 cout << "writing";
204 remove (fileName);
205 std::ofstream os;
206 testutil::OpenStreamWithUTF8Name (
207 os, fileName, ios::out | ios_base::binary);
208 StdOFStream ofs (os, fileName);
209 Header header (width, height);
210 RgbaOutputFile out (ofs, header, WRITE_RGBA);
211 out.setFrameBuffer (&p1[0][0], 1, width);
212 out.writePixels (height);
213 }
214
215 {
216 cout << ", reading";
217 std::ifstream is;
218 testutil::OpenStreamWithUTF8Name (
219 is, fileName, ios::in | ios_base::binary);
220 StdIFStream ifs (is, fileName);
221 RgbaInputFile in (ifs);
222
223 const Box2i &dw = in.dataWindow();
224 int w = dw.max.x - dw.min.x + 1;
225 int h = dw.max.y - dw.min.y + 1;
226 int dx = dw.min.x;
227 int dy = dw.min.y;
228
229 Array2D<Rgba> p2 (h, w);
230 in.setFrameBuffer (&p2[-dy][-dx], 1, w);
231 in.readPixels (dw.min.y, dw.max.y);
232
233 cout << ", comparing";
234 for (int y = 0; y < h; ++y)
235 {
236 for (int x = 0; x < w; ++x)
237 {
238 assert (p2[y][x].r == p1[y][x].r);
239 assert (p2[y][x].g == p1[y][x].g);
240 assert (p2[y][x].b == p1[y][x].b);
241 assert (p2[y][x].a == p1[y][x].a);
242 }
243 }
244 }
245
246 {
247 cout << ", reading (memory-mapped)";
248 MMIFStream ifs (fileName);
249 RgbaInputFile in (ifs);
250
251 const Box2i &dw = in.dataWindow();
252 int w = dw.max.x - dw.min.x + 1;
253 int h = dw.max.y - dw.min.y + 1;
254 int dx = dw.min.x;
255 int dy = dw.min.y;
256
257 Array2D<Rgba> p2 (h, w);
258 in.setFrameBuffer (&p2[-dy][-dx], 1, w);
259 in.readPixels (dw.min.y, dw.max.y);
260
261 cout << ", comparing";
262 for (int y = 0; y < h; ++y)
263 {
264 for (int x = 0; x < w; ++x)
265 {
266 assert (p2[y][x].r == p1[y][x].r);
267 assert (p2[y][x].g == p1[y][x].g);
268 assert (p2[y][x].b == p1[y][x].b);
269 assert (p2[y][x].a == p1[y][x].a);
270 }
271 }
272 }
273
274 cout << endl;
275
276 remove (fileName);
277 }
278 void
writeReadMultiPart(const char fileName[],int width,int height,const Array2D<Rgba> & p1)279 writeReadMultiPart (const char fileName[],
280 int width,
281 int height,
282 const Array2D<Rgba> &p1)
283 {
284 //
285 // Save a two scanline parts in an image, but instead of
286 // letting the MultiPartOutputFile object open the file,
287 // make the MultiPartOutputFile object use an existing
288 // StdOFStream. Read the image back, using an
289 // existing StdIFStream, and compare the pixels
290 // with the original data. Then read the image
291 // back a second time using a memory-mapped
292 // MMIFStream (see above).
293 //
294
295 cout << "scan-line based mulitpart file:" << endl;
296
297 {
298 cout << "writing";
299 remove (fileName);
300 std::ofstream os;
301 testutil::OpenStreamWithUTF8Name (
302 os, fileName, ios::out | ios_base::binary);
303 StdOFStream ofs (os, fileName);
304
305 vector<Header> headers(2);
306 headers[0] = Header(width, height);
307 headers[0].setName("part1");
308 headers[0].channels().insert("R",Channel());
309 headers[0].channels().insert("G",Channel());
310 headers[0].channels().insert("B",Channel());
311 headers[0].channels().insert("A",Channel());
312 headers[0].setType(SCANLINEIMAGE);
313
314 headers[1]=headers[0];
315 headers[1].setName("part2");
316
317 MultiPartOutputFile out (ofs, &headers[0],2);
318 FrameBuffer f;
319 f.insert("R",Slice(HALF,(char *) &p1[0][0].r,sizeof(Rgba),width*sizeof(Rgba)));
320 f.insert("G",Slice(HALF,(char *) &p1[0][0].g,sizeof(Rgba),width*sizeof(Rgba)));
321 f.insert("B",Slice(HALF,(char *) &p1[0][0].b,sizeof(Rgba),width*sizeof(Rgba)));
322 f.insert("A",Slice(HALF,(char *) &p1[0][0].a,sizeof(Rgba),width*sizeof(Rgba)));
323
324 for(int i=0;i<2;i++)
325 {
326 OutputPart p(out,i);
327 p.setFrameBuffer (f);
328 p.writePixels (height);
329 }
330 }
331
332 {
333 cout << ", reading";
334 std::ifstream is;
335 testutil::OpenStreamWithUTF8Name (
336 is, fileName, ios::in | ios_base::binary);
337 StdIFStream ifs (is, fileName);
338 MultiPartInputFile in (ifs);
339
340 assert(in.parts() == 2);
341
342 assert(in.header(0).dataWindow()==in.header(1).dataWindow());
343
344 const Box2i &dw = in.header(0).dataWindow();
345 int w = dw.max.x - dw.min.x + 1;
346 int h = dw.max.y - dw.min.y + 1;
347 int dx = dw.min.x;
348 int dy = dw.min.y;
349
350 Array2D<Rgba> p2 (h, w);
351 FrameBuffer f;
352 f.insert("R",Slice(HALF,(char *) &p2[-dy][-dx].r,sizeof(Rgba),w*sizeof(Rgba)));
353 f.insert("G",Slice(HALF,(char *) &p2[-dy][-dx].g,sizeof(Rgba),w*sizeof(Rgba)));
354 f.insert("B",Slice(HALF,(char *) &p2[-dy][-dx].b,sizeof(Rgba),w*sizeof(Rgba)));
355 f.insert("A",Slice(HALF,(char *) &p2[-dy][-dx].a,sizeof(Rgba),w*sizeof(Rgba)));
356
357 for(int part=0;part<2;part++)
358 {
359 InputPart p(in,part);
360 p.setFrameBuffer(f);
361 p.readPixels (dw.min.y, dw.max.y);
362
363 cout << ", comparing pt " << part;
364 for (int y = 0; y < h; ++y)
365 {
366 for (int x = 0; x < w; ++x)
367 {
368 assert (p2[y][x].r == p1[y][x].r);
369 assert (p2[y][x].g == p1[y][x].g);
370 assert (p2[y][x].b == p1[y][x].b);
371 assert (p2[y][x].a == p1[y][x].a);
372 }
373 }
374 }
375 }
376
377 {
378 cout << ", reading (memory-mapped)";
379 MMIFStream ifs (fileName);
380 MultiPartInputFile in (ifs);
381
382 assert(in.parts() == 2);
383
384 assert(in.header(0).dataWindow()==in.header(1).dataWindow());
385
386
387 const Box2i &dw = in.header(0).dataWindow();
388 int w = dw.max.x - dw.min.x + 1;
389 int h = dw.max.y - dw.min.y + 1;
390 int dx = dw.min.x;
391 int dy = dw.min.y;
392
393 Array2D<Rgba> p2 (h, w);
394 FrameBuffer f;
395 f.insert("R",Slice(HALF,(char *) &p2[-dy][-dx].r,sizeof(Rgba),w*sizeof(Rgba)));
396 f.insert("G",Slice(HALF,(char *) &p2[-dy][-dx].g,sizeof(Rgba),w*sizeof(Rgba)));
397 f.insert("B",Slice(HALF,(char *) &p2[-dy][-dx].b,sizeof(Rgba),w*sizeof(Rgba)));
398 f.insert("A",Slice(HALF,(char *) &p2[-dy][-dx].a,sizeof(Rgba),w*sizeof(Rgba)));
399
400 for(int part=0;part<2;part++)
401 {
402 InputPart p(in,part);
403 p.setFrameBuffer(f);
404 p.readPixels (dw.min.y, dw.max.y);
405
406 cout << ", comparing pt " << part;
407 for (int y = 0; y < h; ++y)
408 {
409 for (int x = 0; x < w; ++x)
410 {
411 assert (p2[y][x].r == p1[y][x].r);
412 assert (p2[y][x].g == p1[y][x].g);
413 assert (p2[y][x].b == p1[y][x].b);
414 assert (p2[y][x].a == p1[y][x].a);
415 }
416 }
417 }
418 }
419
420 cout << endl;
421
422 remove (fileName);
423 }
424
425
426
427 void
writeReadTiles(const char fileName[],int width,int height,const Array2D<Rgba> & p1)428 writeReadTiles (const char fileName[],
429 int width,
430 int height,
431 const Array2D<Rgba> &p1)
432 {
433 //
434 // Save a tiled RGBA image, but instead of letting
435 // the TiledRgbaOutputFile object open the file, make
436 // it use an existing StdOFStream. Read the image back,
437 // using an existing StdIFStream, and compare the pixels
438 // with the original data. Then read the image back a
439 // second time using a memory-mapped MMIFStream (see above).
440 //
441
442 cout << "tiled file:" << endl;
443
444 {
445 cout << "writing";
446 remove (fileName);
447 std::ofstream os;
448 testutil::OpenStreamWithUTF8Name (
449 os, fileName, ios_base::out | ios_base::binary);
450 StdOFStream ofs (os, fileName);
451 Header header (width, height);
452 TiledRgbaOutputFile out (ofs, header, WRITE_RGBA, 20, 20, ONE_LEVEL);
453 out.setFrameBuffer (&p1[0][0], 1, width);
454 out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1);
455 }
456
457 {
458 cout << ", reading";
459 std::ifstream is;
460 testutil::OpenStreamWithUTF8Name (
461 is, fileName, ios::in | ios_base::binary);
462 StdIFStream ifs (is, fileName);
463 TiledRgbaInputFile in (ifs);
464
465 const Box2i &dw = in.dataWindow();
466 int w = dw.max.x - dw.min.x + 1;
467 int h = dw.max.y - dw.min.y + 1;
468 int dx = dw.min.x;
469 int dy = dw.min.y;
470
471 Array2D<Rgba> p2 (h, w);
472 in.setFrameBuffer (&p2[-dy][-dx], 1, w);
473 in.readTiles (0, in.numXTiles() - 1, 0, in.numYTiles() - 1);
474
475 cout << ", comparing";
476 for (int y = 0; y < h; ++y)
477 {
478 for (int x = 0; x < w; ++x)
479 {
480 assert (p2[y][x].r == p1[y][x].r);
481 assert (p2[y][x].g == p1[y][x].g);
482 assert (p2[y][x].b == p1[y][x].b);
483 assert (p2[y][x].a == p1[y][x].a);
484 }
485 }
486 }
487
488 {
489 cout << ", reading (memory-mapped)";
490 MMIFStream ifs (fileName);
491 TiledRgbaInputFile in (ifs);
492
493 const Box2i &dw = in.dataWindow();
494 int w = dw.max.x - dw.min.x + 1;
495 int h = dw.max.y - dw.min.y + 1;
496 int dx = dw.min.x;
497 int dy = dw.min.y;
498
499 Array2D<Rgba> p2 (h, w);
500 in.setFrameBuffer (&p2[-dy][-dx], 1, w);
501 in.readTiles (0, in.numXTiles() - 1, 0, in.numYTiles() - 1);
502
503 cout << ", comparing";
504 for (int y = 0; y < h; ++y)
505 {
506 for (int x = 0; x < w; ++x)
507 {
508 assert (p2[y][x].r == p1[y][x].r);
509 assert (p2[y][x].g == p1[y][x].g);
510 assert (p2[y][x].b == p1[y][x].b);
511 assert (p2[y][x].a == p1[y][x].a);
512 }
513 }
514 }
515
516 cout << endl;
517
518 remove (fileName);
519 }
520
521
522 //
523 // stringstream version
524 //
525 void
writeReadScanLines(int width,int height,const Array2D<Rgba> & p1)526 writeReadScanLines (int width,
527 int height,
528 const Array2D<Rgba> &p1)
529 {
530 //
531 // Save a scanline-based RGBA image, but instead of
532 // letting the RgbaOutputFile object open the file,
533 // make the RgbaOutputFile object use an existing
534 // StdOSStream. Read the image back, using an
535 // existing StdISStream, and compare the pixels
536 // with the original data.
537 //
538
539 cout << "scan-line based stringstream:" << endl;
540
541 std::string strEXRFile;
542
543 {
544 cout << "writing";
545 StdOSStream oss;
546 Header header (width, height);
547 RgbaOutputFile out (oss, header, WRITE_RGBA);
548 out.setFrameBuffer (&p1[0][0], 1, width);
549 out.writePixels (height);
550 strEXRFile = oss.str();
551 }
552
553 {
554 cout << ", reading";
555 StdISStream iss;
556 iss.clear();
557 iss.str(strEXRFile);
558 RgbaInputFile in (iss);
559
560 const Box2i &dw = in.dataWindow();
561 int w = dw.max.x - dw.min.x + 1;
562 int h = dw.max.y - dw.min.y + 1;
563 int dx = dw.min.x;
564 int dy = dw.min.y;
565
566 Array2D<Rgba> p2 (h, w);
567 in.setFrameBuffer (&p2[-dy][-dx], 1, w);
568 in.readPixels (dw.min.y, dw.max.y);
569
570 cout << ", comparing";
571 for (int y = 0; y < h; ++y)
572 {
573 for (int x = 0; x < w; ++x)
574 {
575 assert (p2[y][x].r == p1[y][x].r);
576 assert (p2[y][x].g == p1[y][x].g);
577 assert (p2[y][x].b == p1[y][x].b);
578 assert (p2[y][x].a == p1[y][x].a);
579 }
580 }
581 }
582
583 cout << endl;
584 }
585
586
587 //
588 // stringstream version
589 //
590 void
writeReadMultiPart(int width,int height,const Array2D<Rgba> & p1)591 writeReadMultiPart (int width,
592 int height,
593 const Array2D<Rgba> &p1)
594 {
595 //
596 // Save a two scanline parts in an image, but instead of
597 // letting the MultiPartOutputFile object open the file,
598 // make the MultiPartOutputFile object use an existing
599 // StdOSStream. Read the image back, using an
600 // existing StdISStream, and compare the pixels
601 // with the original data.
602 //
603
604 cout << "scan-line based mulitpart stringstream:" << endl;
605
606 std::string strEXRFile;
607
608 {
609 cout << "writing";
610 StdOSStream oss;
611
612 vector<Header> headers(2);
613 headers[0] = Header(width, height);
614 headers[0].setName("part1");
615 headers[0].channels().insert("R",Channel());
616 headers[0].channels().insert("G",Channel());
617 headers[0].channels().insert("B",Channel());
618 headers[0].channels().insert("A",Channel());
619 headers[0].setType(SCANLINEIMAGE);
620
621 headers[1]=headers[0];
622 headers[1].setName("part2");
623
624 MultiPartOutputFile out (oss, &headers[0],2);
625 FrameBuffer f;
626 f.insert("R",Slice(HALF,(char *) &p1[0][0].r,sizeof(Rgba),width*sizeof(Rgba)));
627 f.insert("G",Slice(HALF,(char *) &p1[0][0].g,sizeof(Rgba),width*sizeof(Rgba)));
628 f.insert("B",Slice(HALF,(char *) &p1[0][0].b,sizeof(Rgba),width*sizeof(Rgba)));
629 f.insert("A",Slice(HALF,(char *) &p1[0][0].a,sizeof(Rgba),width*sizeof(Rgba)));
630
631 for(int i=0;i<2;i++)
632 {
633 OutputPart p(out,i);
634 p.setFrameBuffer (f);
635 p.writePixels (height);
636 }
637
638 strEXRFile = oss.str();
639 }
640
641 {
642 cout << ", reading";
643 StdISStream iss;
644 iss.clear();
645 iss.str(strEXRFile);
646 MultiPartInputFile in (iss);
647
648 assert(in.parts() == 2);
649
650 assert(in.header(0).dataWindow()==in.header(1).dataWindow());
651
652 const Box2i &dw = in.header(0).dataWindow();
653 int w = dw.max.x - dw.min.x + 1;
654 int h = dw.max.y - dw.min.y + 1;
655 int dx = dw.min.x;
656 int dy = dw.min.y;
657
658 Array2D<Rgba> p2 (h, w);
659 FrameBuffer f;
660 f.insert("R",Slice(HALF,(char *) &p2[-dy][-dx].r,sizeof(Rgba),w*sizeof(Rgba)));
661 f.insert("G",Slice(HALF,(char *) &p2[-dy][-dx].g,sizeof(Rgba),w*sizeof(Rgba)));
662 f.insert("B",Slice(HALF,(char *) &p2[-dy][-dx].b,sizeof(Rgba),w*sizeof(Rgba)));
663 f.insert("A",Slice(HALF,(char *) &p2[-dy][-dx].a,sizeof(Rgba),w*sizeof(Rgba)));
664
665 for(int part=0;part<2;part++)
666 {
667 InputPart p(in,part);
668 p.setFrameBuffer(f);
669 p.readPixels (dw.min.y, dw.max.y);
670
671 cout << ", comparing pt " << part;
672 for (int y = 0; y < h; ++y)
673 {
674 for (int x = 0; x < w; ++x)
675 {
676 assert (p2[y][x].r == p1[y][x].r);
677 assert (p2[y][x].g == p1[y][x].g);
678 assert (p2[y][x].b == p1[y][x].b);
679 assert (p2[y][x].a == p1[y][x].a);
680 }
681 }
682 }
683 }
684
685 cout << endl;
686 }
687
688 //
689 // stringstream version
690 //
691 void
writeReadTiles(int width,int height,const Array2D<Rgba> & p1)692 writeReadTiles (int width,
693 int height,
694 const Array2D<Rgba> &p1)
695 {
696 //
697 // Save a tiled RGBA image, but instead of letting
698 // the TiledRgbaOutputFile object open the file, make
699 // it use an existing StdOSStream. Read the image back,
700 // using an existing StdISStream, and compare the pixels
701 // with the original data.
702 //
703
704 cout << "tiled stringstream:" << endl;
705
706 std::string strEXRFile;
707
708 {
709 cout << "writing";
710 StdOSStream oss;
711 Header header (width, height);
712 TiledRgbaOutputFile out (oss, header, WRITE_RGBA, 20, 20, ONE_LEVEL);
713 out.setFrameBuffer (&p1[0][0], 1, width);
714 out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1);
715
716 strEXRFile = oss.str();
717 }
718
719 {
720 cout << ", reading";
721 StdISStream iss;
722 iss.clear();
723 iss.str(strEXRFile);
724 TiledRgbaInputFile in (iss);
725
726 const Box2i &dw = in.dataWindow();
727 int w = dw.max.x - dw.min.x + 1;
728 int h = dw.max.y - dw.min.y + 1;
729 int dx = dw.min.x;
730 int dy = dw.min.y;
731
732 Array2D<Rgba> p2 (h, w);
733 in.setFrameBuffer (&p2[-dy][-dx], 1, w);
734 in.readTiles (0, in.numXTiles() - 1, 0, in.numYTiles() - 1);
735
736 cout << ", comparing";
737 for (int y = 0; y < h; ++y)
738 {
739 for (int x = 0; x < w; ++x)
740 {
741 assert (p2[y][x].r == p1[y][x].r);
742 assert (p2[y][x].g == p1[y][x].g);
743 assert (p2[y][x].b == p1[y][x].b);
744 assert (p2[y][x].a == p1[y][x].a);
745 }
746 }
747 }
748
749 cout << endl;
750 }
751
752 } // namespace
753
754
755 void
testExistingStreams(const std::string & tempDir)756 testExistingStreams (const std::string &tempDir)
757 {
758 try
759 {
760 cout << "Testing reading and writing using existing streams" << endl;
761
762 const int W = 119;
763 const int H = 237;
764
765 Array2D<Rgba> p1 (H, W);
766
767 fillPixels1 (p1, W, H);
768 writeReadScanLines ((tempDir + "imf_test_streams.exr").c_str(), W, H, p1);
769 writeReadScanLines (W, H, p1);
770
771 fillPixels2 (p1, W, H);
772 writeReadTiles ((tempDir + "imf_test_streams2.exr").c_str(), W, H, p1);
773 writeReadTiles (W, H, p1);
774
775 fillPixels1 (p1, W, H);
776 writeReadMultiPart ((tempDir + "imf_test_streams3.exr").c_str(), W, H, p1);
777 writeReadMultiPart (W, H, p1);
778
779 cout << "ok\n" << endl;
780 }
781 catch (const std::exception &e)
782 {
783 cerr << "ERROR -- caught exception: " << e.what() << endl;
784 assert (false);
785 }
786 }
787