1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // *       Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // *       Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // *       Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34 
35 //-----------------------------------------------------------------------------
36 //
37 //	class TiledRgbaOutputFile
38 //	class TiledRgbaInputFile
39 //
40 //-----------------------------------------------------------------------------
41 
42 #include <ImfTiledRgbaFile.h>
43 #include <ImfRgbaFile.h>
44 #include <ImfTiledOutputFile.h>
45 #include <ImfTiledInputFile.h>
46 #include <ImfChannelList.h>
47 #include <ImfTileDescriptionAttribute.h>
48 #include <ImfStandardAttributes.h>
49 #include <ImfRgbaYca.h>
50 #include <ImfArray.h>
51 #include "IlmThreadMutex.h"
52 #include "Iex.h"
53 
54 #include "ImfNamespace.h"
55 
56 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
57 
58 using namespace std;
59 using namespace IMATH_NAMESPACE;
60 using namespace RgbaYca;
61 using namespace ILMTHREAD_NAMESPACE;
62 
63 namespace {
64 
65 void
insertChannels(Header & header,RgbaChannels rgbaChannels,const char fileName[])66 insertChannels (Header &header,
67 		RgbaChannels rgbaChannels,
68 		const char fileName[])
69 {
70     ChannelList ch;
71 
72     if (rgbaChannels & (WRITE_Y | WRITE_C))
73     {
74 	if (rgbaChannels & WRITE_Y)
75 	{
76 	    ch.insert ("Y", Channel (HALF, 1, 1));
77 	}
78 
79 	if (rgbaChannels & WRITE_C)
80 	{
81 	    THROW (IEX_NAMESPACE::ArgExc, "Cannot open file \"" << fileName << "\" "
82 				"for writing.  Tiled image files do not "
83 				"support subsampled chroma channels.");
84 	}
85     }
86     else
87     {
88 	if (rgbaChannels & WRITE_R)
89 	    ch.insert ("R", Channel (HALF, 1, 1));
90 
91 	if (rgbaChannels & WRITE_G)
92 	    ch.insert ("G", Channel (HALF, 1, 1));
93 
94 	if (rgbaChannels & WRITE_B)
95 	    ch.insert ("B", Channel (HALF, 1, 1));
96     }
97 
98     if (rgbaChannels & WRITE_A)
99 	ch.insert ("A", Channel (HALF, 1, 1));
100 
101     header.channels() = ch;
102 }
103 
104 
105 RgbaChannels
rgbaChannels(const ChannelList & ch,const string & channelNamePrefix="")106 rgbaChannels (const ChannelList &ch, const string &channelNamePrefix = "")
107 {
108     int i = 0;
109 
110     if (ch.findChannel (channelNamePrefix + "R"))
111 	i |= WRITE_R;
112 
113     if (ch.findChannel (channelNamePrefix + "G"))
114 	i |= WRITE_G;
115 
116     if (ch.findChannel (channelNamePrefix + "B"))
117 	i |= WRITE_B;
118 
119     if (ch.findChannel (channelNamePrefix + "A"))
120 	i |= WRITE_A;
121 
122     if (ch.findChannel (channelNamePrefix + "Y"))
123 	i |= WRITE_Y;
124 
125     return RgbaChannels (i);
126 }
127 
128 
129 string
prefixFromLayerName(const string & layerName,const Header & header)130 prefixFromLayerName (const string &layerName, const Header &header)
131 {
132     if (layerName.empty())
133 	return "";
134 
135     if (hasMultiView (header) && multiView(header)[0] == layerName)
136 	return "";
137 
138     return layerName + ".";
139 }
140 
141 
142 V3f
ywFromHeader(const Header & header)143 ywFromHeader (const Header &header)
144 {
145     Chromaticities cr;
146 
147     if (hasChromaticities (header))
148 	cr = chromaticities (header);
149 
150     return computeYw (cr);
151 }
152 
153 } // namespace
154 
155 
156 class TiledRgbaOutputFile::ToYa: public Mutex
157 {
158   public:
159 
160      ToYa (TiledOutputFile &outputFile, RgbaChannels rgbaChannels);
161 
162      void	setFrameBuffer (const Rgba *base,
163 				size_t xStride,
164 				size_t yStride);
165 
166      void	writeTile (int dx, int dy, int lx, int ly);
167 
168   private:
169 
170      TiledOutputFile &	_outputFile;
171      bool		_writeA;
172      unsigned int	_tileXSize;
173      unsigned int	_tileYSize;
174      V3f		_yw;
175      Array2D <Rgba>	_buf;
176      const Rgba *	_fbBase;
177      size_t		_fbXStride;
178      size_t		_fbYStride;
179 };
180 
181 
ToYa(TiledOutputFile & outputFile,RgbaChannels rgbaChannels)182 TiledRgbaOutputFile::ToYa::ToYa (TiledOutputFile &outputFile,
183 				 RgbaChannels rgbaChannels)
184 :
185     _outputFile (outputFile)
186 {
187     _writeA = (rgbaChannels & WRITE_A)? true: false;
188 
189     const TileDescription &td = outputFile.header().tileDescription();
190 
191     _tileXSize = td.xSize;
192     _tileYSize = td.ySize;
193     _yw = ywFromHeader (_outputFile.header());
194     _buf.resizeErase (_tileYSize, _tileXSize);
195     _fbBase = 0;
196     _fbXStride = 0;
197     _fbYStride = 0;
198 }
199 
200 
201 void
setFrameBuffer(const Rgba * base,size_t xStride,size_t yStride)202 TiledRgbaOutputFile::ToYa::setFrameBuffer (const Rgba *base,
203 					   size_t xStride,
204 					   size_t yStride)
205 {
206     _fbBase = base;
207     _fbXStride = xStride;
208     _fbYStride = yStride;
209 }
210 
211 
212 void
writeTile(int dx,int dy,int lx,int ly)213 TiledRgbaOutputFile::ToYa::writeTile (int dx, int dy, int lx, int ly)
214 {
215     if (_fbBase == 0)
216     {
217 	THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
218 			    "pixel data source for image file "
219 			    "\"" << _outputFile.fileName() << "\".");
220     }
221 
222     //
223     // Copy the tile's RGBA pixels into _buf and convert
224     // them to luminance/alpha format
225     //
226 
227     Box2i dw = _outputFile.dataWindowForTile (dx, dy, lx, ly);
228     int width = dw.max.x - dw.min.x + 1;
229 
230     for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
231     {
232 	for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
233 	    _buf[y1][x1] = _fbBase[x * _fbXStride + y * _fbYStride];
234 
235 	RGBAtoYCA (_yw, width, _writeA, _buf[y1], _buf[y1]);
236     }
237 
238     //
239     // Store the contents of _buf in the output file
240     //
241 
242     FrameBuffer fb;
243 
244     fb.insert ("Y", Slice (HALF,				   // type
245 			   (char *) &_buf[-dw.min.y][-dw.min.x].g, // base
246 			   sizeof (Rgba),			   // xStride
247 			   sizeof (Rgba) * _tileXSize));	   // yStride
248 
249     fb.insert ("A", Slice (HALF,				   // type
250 			   (char *) &_buf[-dw.min.y][-dw.min.x].a, // base
251 			   sizeof (Rgba),			   // xStride
252 			   sizeof (Rgba) * _tileXSize));	   // yStride
253 
254     _outputFile.setFrameBuffer (fb);
255     _outputFile.writeTile (dx, dy, lx, ly);
256 }
257 
258 
TiledRgbaOutputFile(const char name[],const Header & header,RgbaChannels rgbaChannels,int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,int numThreads)259 TiledRgbaOutputFile::TiledRgbaOutputFile
260     (const char name[],
261      const Header &header,
262      RgbaChannels rgbaChannels,
263      int tileXSize,
264      int tileYSize,
265      LevelMode mode,
266      LevelRoundingMode rmode,
267      int numThreads)
268 :
269     _outputFile (0),
270     _toYa (0)
271 {
272     Header hd (header);
273     insertChannels (hd, rgbaChannels, name);
274     hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
275     _outputFile = new TiledOutputFile (name, hd, numThreads);
276 
277     if (rgbaChannels & WRITE_Y)
278 	_toYa = new ToYa (*_outputFile, rgbaChannels);
279 }
280 
281 
282 
TiledRgbaOutputFile(OPENEXR_IMF_INTERNAL_NAMESPACE::OStream & os,const Header & header,RgbaChannels rgbaChannels,int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,int numThreads)283 TiledRgbaOutputFile::TiledRgbaOutputFile
284     (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
285      const Header &header,
286      RgbaChannels rgbaChannels,
287      int tileXSize,
288      int tileYSize,
289      LevelMode mode,
290      LevelRoundingMode rmode,
291      int numThreads)
292 :
293     _outputFile (0),
294     _toYa (0)
295 {
296     Header hd (header);
297     insertChannels (hd, rgbaChannels, os.fileName());
298     hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
299     _outputFile = new TiledOutputFile (os, hd, numThreads);
300 
301     if (rgbaChannels & WRITE_Y)
302 	_toYa = new ToYa (*_outputFile, rgbaChannels);
303 }
304 
305 
306 
TiledRgbaOutputFile(const char name[],int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,const IMATH_NAMESPACE::Box2i & displayWindow,const IMATH_NAMESPACE::Box2i & dataWindow,RgbaChannels rgbaChannels,float pixelAspectRatio,const IMATH_NAMESPACE::V2f screenWindowCenter,float screenWindowWidth,LineOrder lineOrder,Compression compression,int numThreads)307 TiledRgbaOutputFile::TiledRgbaOutputFile
308     (const char name[],
309      int tileXSize,
310      int tileYSize,
311      LevelMode mode,
312      LevelRoundingMode rmode,
313      const IMATH_NAMESPACE::Box2i &displayWindow,
314      const IMATH_NAMESPACE::Box2i &dataWindow,
315      RgbaChannels rgbaChannels,
316      float pixelAspectRatio,
317      const IMATH_NAMESPACE::V2f screenWindowCenter,
318      float screenWindowWidth,
319      LineOrder lineOrder,
320      Compression compression,
321      int numThreads)
322 :
323     _outputFile (0),
324     _toYa (0)
325 {
326     Header hd (displayWindow,
327 	       dataWindow.isEmpty()? displayWindow: dataWindow,
328 	       pixelAspectRatio,
329 	       screenWindowCenter,
330 	       screenWindowWidth,
331 	       lineOrder,
332 	       compression);
333 
334     insertChannels (hd, rgbaChannels, name);
335     hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
336     _outputFile = new TiledOutputFile (name, hd, numThreads);
337 
338     if (rgbaChannels & WRITE_Y)
339 	_toYa = new ToYa (*_outputFile, rgbaChannels);
340 }
341 
342 
TiledRgbaOutputFile(const char name[],int width,int height,int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,RgbaChannels rgbaChannels,float pixelAspectRatio,const IMATH_NAMESPACE::V2f screenWindowCenter,float screenWindowWidth,LineOrder lineOrder,Compression compression,int numThreads)343 TiledRgbaOutputFile::TiledRgbaOutputFile
344     (const char name[],
345      int width,
346      int height,
347      int tileXSize,
348      int tileYSize,
349      LevelMode mode,
350      LevelRoundingMode rmode,
351      RgbaChannels rgbaChannels,
352      float pixelAspectRatio,
353      const IMATH_NAMESPACE::V2f screenWindowCenter,
354      float screenWindowWidth,
355      LineOrder lineOrder,
356      Compression compression,
357      int numThreads)
358 :
359     _outputFile (0),
360     _toYa (0)
361 {
362     Header hd (width,
363 	       height,
364 	       pixelAspectRatio,
365 	       screenWindowCenter,
366 	       screenWindowWidth,
367 	       lineOrder,
368 	       compression);
369 
370     insertChannels (hd, rgbaChannels, name);
371     hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
372     _outputFile = new TiledOutputFile (name, hd, numThreads);
373 
374     if (rgbaChannels & WRITE_Y)
375 	_toYa = new ToYa (*_outputFile, rgbaChannels);
376 }
377 
378 
~TiledRgbaOutputFile()379 TiledRgbaOutputFile::~TiledRgbaOutputFile ()
380 {
381     delete _outputFile;
382     delete _toYa;
383 }
384 
385 
386 void
setFrameBuffer(const Rgba * base,size_t xStride,size_t yStride)387 TiledRgbaOutputFile::setFrameBuffer (const Rgba *base,
388 				     size_t xStride,
389 				     size_t yStride)
390 {
391     if (_toYa)
392     {
393 	Lock lock (*_toYa);
394 	_toYa->setFrameBuffer (base, xStride, yStride);
395     }
396     else
397     {
398 	size_t xs = xStride * sizeof (Rgba);
399 	size_t ys = yStride * sizeof (Rgba);
400 
401 	FrameBuffer fb;
402 
403 	fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
404 	fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
405 	fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
406 	fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
407 
408 	_outputFile->setFrameBuffer (fb);
409     }
410 }
411 
412 
413 const Header &
header() const414 TiledRgbaOutputFile::header () const
415 {
416     return _outputFile->header();
417 }
418 
419 
420 const FrameBuffer &
frameBuffer() const421 TiledRgbaOutputFile::frameBuffer () const
422 {
423     return _outputFile->frameBuffer();
424 }
425 
426 
427 const IMATH_NAMESPACE::Box2i &
displayWindow() const428 TiledRgbaOutputFile::displayWindow () const
429 {
430     return _outputFile->header().displayWindow();
431 }
432 
433 
434 const IMATH_NAMESPACE::Box2i &
dataWindow() const435 TiledRgbaOutputFile::dataWindow () const
436 {
437     return _outputFile->header().dataWindow();
438 }
439 
440 
441 float
pixelAspectRatio() const442 TiledRgbaOutputFile::pixelAspectRatio () const
443 {
444     return _outputFile->header().pixelAspectRatio();
445 }
446 
447 
448 const IMATH_NAMESPACE::V2f
screenWindowCenter() const449 TiledRgbaOutputFile::screenWindowCenter () const
450 {
451     return _outputFile->header().screenWindowCenter();
452 }
453 
454 
455 float
screenWindowWidth() const456 TiledRgbaOutputFile::screenWindowWidth () const
457 {
458     return _outputFile->header().screenWindowWidth();
459 }
460 
461 
462 LineOrder
lineOrder() const463 TiledRgbaOutputFile::lineOrder () const
464 {
465     return _outputFile->header().lineOrder();
466 }
467 
468 
469 Compression
compression() const470 TiledRgbaOutputFile::compression () const
471 {
472     return _outputFile->header().compression();
473 }
474 
475 
476 RgbaChannels
channels() const477 TiledRgbaOutputFile::channels () const
478 {
479     return rgbaChannels (_outputFile->header().channels());
480 }
481 
482 
483 unsigned int
tileXSize() const484 TiledRgbaOutputFile::tileXSize () const
485 {
486      return _outputFile->tileXSize();
487 }
488 
489 
490 unsigned int
tileYSize() const491 TiledRgbaOutputFile::tileYSize () const
492 {
493      return _outputFile->tileYSize();
494 }
495 
496 
497 LevelMode
levelMode() const498 TiledRgbaOutputFile::levelMode () const
499 {
500      return _outputFile->levelMode();
501 }
502 
503 
504 LevelRoundingMode
levelRoundingMode() const505 TiledRgbaOutputFile::levelRoundingMode () const
506 {
507      return _outputFile->levelRoundingMode();
508 }
509 
510 
511 int
numLevels() const512 TiledRgbaOutputFile::numLevels () const
513 {
514      return _outputFile->numLevels();
515 }
516 
517 
518 int
numXLevels() const519 TiledRgbaOutputFile::numXLevels () const
520 {
521      return _outputFile->numXLevels();
522 }
523 
524 
525 int
numYLevels() const526 TiledRgbaOutputFile::numYLevels () const
527 {
528      return _outputFile->numYLevels();
529 }
530 
531 
532 bool
isValidLevel(int lx,int ly) const533 TiledRgbaOutputFile::isValidLevel (int lx, int ly) const
534 {
535     return _outputFile->isValidLevel (lx, ly);
536 }
537 
538 
539 int
levelWidth(int lx) const540 TiledRgbaOutputFile::levelWidth (int lx) const
541 {
542      return _outputFile->levelWidth (lx);
543 }
544 
545 
546 int
levelHeight(int ly) const547 TiledRgbaOutputFile::levelHeight (int ly) const
548 {
549      return _outputFile->levelHeight (ly);
550 }
551 
552 
553 int
numXTiles(int lx) const554 TiledRgbaOutputFile::numXTiles (int lx) const
555 {
556      return _outputFile->numXTiles (lx);
557 }
558 
559 
560 int
numYTiles(int ly) const561 TiledRgbaOutputFile::numYTiles (int ly) const
562 {
563      return _outputFile->numYTiles (ly);
564 }
565 
566 
567 IMATH_NAMESPACE::Box2i
dataWindowForLevel(int l) const568 TiledRgbaOutputFile::dataWindowForLevel (int l) const
569 {
570      return _outputFile->dataWindowForLevel (l);
571 }
572 
573 
574 IMATH_NAMESPACE::Box2i
dataWindowForLevel(int lx,int ly) const575 TiledRgbaOutputFile::dataWindowForLevel (int lx, int ly) const
576 {
577      return _outputFile->dataWindowForLevel (lx, ly);
578 }
579 
580 
581 IMATH_NAMESPACE::Box2i
dataWindowForTile(int dx,int dy,int l) const582 TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int l) const
583 {
584      return _outputFile->dataWindowForTile (dx, dy, l);
585 }
586 
587 
588 IMATH_NAMESPACE::Box2i
dataWindowForTile(int dx,int dy,int lx,int ly) const589 TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
590 {
591      return _outputFile->dataWindowForTile (dx, dy, lx, ly);
592 }
593 
594 
595 void
writeTile(int dx,int dy,int l)596 TiledRgbaOutputFile::writeTile (int dx, int dy, int l)
597 {
598     if (_toYa)
599     {
600 	Lock lock (*_toYa);
601 	_toYa->writeTile (dx, dy, l, l);
602     }
603     else
604     {
605 	 _outputFile->writeTile (dx, dy, l);
606     }
607 }
608 
609 
610 void
writeTile(int dx,int dy,int lx,int ly)611 TiledRgbaOutputFile::writeTile (int dx, int dy, int lx, int ly)
612 {
613     if (_toYa)
614     {
615 	Lock lock (*_toYa);
616 	_toYa->writeTile (dx, dy, lx, ly);
617     }
618     else
619     {
620 	 _outputFile->writeTile (dx, dy, lx, ly);
621     }
622 }
623 
624 
625 void
writeTiles(int dxMin,int dxMax,int dyMin,int dyMax,int lx,int ly)626 TiledRgbaOutputFile::writeTiles
627     (int dxMin, int dxMax, int dyMin, int dyMax, int lx, int ly)
628 {
629     if (_toYa)
630     {
631 	Lock lock (*_toYa);
632 
633         for (int dy = dyMin; dy <= dyMax; dy++)
634             for (int dx = dxMin; dx <= dxMax; dx++)
635 	        _toYa->writeTile (dx, dy, lx, ly);
636     }
637     else
638     {
639         _outputFile->writeTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
640     }
641 }
642 
643 void
writeTiles(int dxMin,int dxMax,int dyMin,int dyMax,int l)644 TiledRgbaOutputFile::writeTiles
645     (int dxMin, int dxMax, int dyMin, int dyMax, int l)
646 {
647     writeTiles (dxMin, dxMax, dyMin, dyMax, l, l);
648 }
649 
650 
651 class TiledRgbaInputFile::FromYa: public Mutex
652 {
653   public:
654 
655      FromYa (TiledInputFile &inputFile);
656 
657      void	setFrameBuffer (Rgba *base,
658 				size_t xStride,
659 				size_t yStride,
660 				const string &channelNamePrefix);
661 
662      void	readTile (int dx, int dy, int lx, int ly);
663 
664   private:
665 
666      TiledInputFile &	_inputFile;
667      unsigned int	_tileXSize;
668      unsigned int	_tileYSize;
669      V3f		_yw;
670      Array2D <Rgba>	_buf;
671      Rgba *		_fbBase;
672      size_t		_fbXStride;
673      size_t		_fbYStride;
674 };
675 
676 
FromYa(TiledInputFile & inputFile)677 TiledRgbaInputFile::FromYa::FromYa (TiledInputFile &inputFile)
678 :
679     _inputFile (inputFile)
680 {
681     const TileDescription &td = inputFile.header().tileDescription();
682 
683     _tileXSize = td.xSize;
684     _tileYSize = td.ySize;
685     _yw = ywFromHeader (_inputFile.header());
686     _buf.resizeErase (_tileYSize, _tileXSize);
687     _fbBase = 0;
688     _fbXStride = 0;
689     _fbYStride = 0;
690 }
691 
692 
693 void
setFrameBuffer(Rgba * base,size_t xStride,size_t yStride,const string & channelNamePrefix)694 TiledRgbaInputFile::FromYa::setFrameBuffer (Rgba *base,
695 					    size_t xStride,
696 					    size_t yStride,
697 					    const string &channelNamePrefix)
698 {
699     if (_fbBase == 0)
700 {
701 	FrameBuffer fb;
702 
703 	fb.insert (channelNamePrefix + "Y",
704 		   Slice (HALF,				// type
705 			  (char *) &_buf[0][0].g,	// base
706 			  sizeof (Rgba),		// xStride
707 			  sizeof (Rgba) * _tileXSize,	// yStride
708 			  1, 1,				// sampling
709 			  0.0,				// fillValue
710 			  true, true));			// tileCoordinates
711 
712 	fb.insert (channelNamePrefix + "A",
713 		   Slice (HALF,				// type
714 			  (char *) &_buf[0][0].a,	// base
715 			  sizeof (Rgba),		// xStride
716 			  sizeof (Rgba) * _tileXSize,	// yStride
717 			  1, 1,				// sampling
718 			  1.0,				// fillValue
719 			  true, true));			// tileCoordinates
720 
721 	_inputFile.setFrameBuffer (fb);
722     }
723 
724     _fbBase = base;
725     _fbXStride = xStride;
726     _fbYStride = yStride;
727 }
728 
729 
730 void
readTile(int dx,int dy,int lx,int ly)731 TiledRgbaInputFile::FromYa::readTile (int dx, int dy, int lx, int ly)
732 {
733     if (_fbBase == 0)
734     {
735 	THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
736 			    "pixel data destination for image file "
737 			    "\"" << _inputFile.fileName() << "\".");
738     }
739 
740     //
741     // Read the tile requested by the caller into _buf.
742     //
743 
744     _inputFile.readTile (dx, dy, lx, ly);
745 
746     //
747     // Convert the luminance/alpha pixels to RGBA
748     // and copy them into the caller's frame buffer.
749     //
750 
751     Box2i dw = _inputFile.dataWindowForTile (dx, dy, lx, ly);
752     int width = dw.max.x - dw.min.x + 1;
753 
754     for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
755     {
756 	for (int x1 = 0; x1 < width; ++x1)
757 	{
758 	    _buf[y1][x1].r = 0;
759 	    _buf[y1][x1].b = 0;
760 	}
761 
762 	YCAtoRGBA (_yw, width, _buf[y1], _buf[y1]);
763 
764 	for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
765 	{
766 	    _fbBase[x * _fbXStride + y * _fbYStride] = _buf[y1][x1];
767 	}
768     }
769 }
770 
771 
TiledRgbaInputFile(const char name[],int numThreads)772 TiledRgbaInputFile::TiledRgbaInputFile (const char name[], int numThreads):
773     _inputFile (new TiledInputFile (name, numThreads)),
774     _fromYa (0),
775     _channelNamePrefix ("")
776 {
777     if (channels() & WRITE_Y)
778 	_fromYa = new FromYa (*_inputFile);
779 }
780 
781 
TiledRgbaInputFile(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream & is,int numThreads)782 TiledRgbaInputFile::TiledRgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
783     _inputFile (new TiledInputFile (is, numThreads)),
784     _fromYa (0),
785     _channelNamePrefix ("")
786 {
787     if (channels() & WRITE_Y)
788 	_fromYa = new FromYa (*_inputFile);
789 }
790 
791 
TiledRgbaInputFile(const char name[],const string & layerName,int numThreads)792 TiledRgbaInputFile::TiledRgbaInputFile (const char name[],
793 					const string &layerName,
794 					int numThreads)
795 :
796     _inputFile (new TiledInputFile (name, numThreads)),
797     _fromYa (0),
798     _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
799 {
800     if (channels() & WRITE_Y)
801 	_fromYa = new FromYa (*_inputFile);
802 }
803 
804 
TiledRgbaInputFile(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream & is,const string & layerName,int numThreads)805 TiledRgbaInputFile::TiledRgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
806 					const string &layerName,
807 					int numThreads)
808 :
809     _inputFile (new TiledInputFile (is, numThreads)),
810     _fromYa (0),
811     _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
812 {
813     if (channels() & WRITE_Y)
814 	_fromYa = new FromYa (*_inputFile);
815 }
816 
817 
~TiledRgbaInputFile()818 TiledRgbaInputFile::~TiledRgbaInputFile ()
819 {
820     delete _inputFile;
821     delete _fromYa;
822 }
823 
824 
825 void
setFrameBuffer(Rgba * base,size_t xStride,size_t yStride)826 TiledRgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
827 {
828     if (_fromYa)
829     {
830 	Lock lock (*_fromYa);
831 	_fromYa->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
832     }
833     else
834     {
835 	size_t xs = xStride * sizeof (Rgba);
836 	size_t ys = yStride * sizeof (Rgba);
837 
838 	FrameBuffer fb;
839 
840 	fb.insert (_channelNamePrefix + "R",
841 		   Slice (HALF,
842 			       (char *) &base[0].r,
843 			       xs, ys,
844 			       1, 1,	// xSampling, ySampling
845 			       0.0));	// fillValue
846 
847 	fb.insert (_channelNamePrefix + "G",
848 		   Slice (HALF,
849 			       (char *) &base[0].g,
850 			       xs, ys,
851 			       1, 1,	// xSampling, ySampling
852 			       0.0));	// fillValue
853 
854 	fb.insert (_channelNamePrefix + "B",
855 		   Slice (HALF,
856 			       (char *) &base[0].b,
857 			       xs, ys,
858 			       1, 1,	// xSampling, ySampling
859 			       0.0));	// fillValue
860 
861 	fb.insert (_channelNamePrefix + "A",
862 		   Slice (HALF,
863 			       (char *) &base[0].a,
864 			       xs, ys,
865 			       1, 1,	// xSampling, ySampling
866 			       1.0));	// fillValue
867 
868 	_inputFile->setFrameBuffer (fb);
869     }
870 }
871 
872 
873 void
setLayerName(const std::string & layerName)874 TiledRgbaInputFile::setLayerName (const std::string &layerName)
875 {
876     delete _fromYa;
877     _fromYa = 0;
878 
879     _channelNamePrefix = prefixFromLayerName (layerName, _inputFile->header());
880 
881     if (channels() & WRITE_Y)
882 	_fromYa = new FromYa (*_inputFile);
883 
884     FrameBuffer fb;
885     _inputFile->setFrameBuffer (fb);
886 }
887 
888 
889 const Header &
header() const890 TiledRgbaInputFile::header () const
891 {
892     return _inputFile->header();
893 }
894 
895 
896 const char *
fileName() const897 TiledRgbaInputFile::fileName () const
898 {
899     return _inputFile->fileName();
900 }
901 
902 
903 const FrameBuffer &
frameBuffer() const904 TiledRgbaInputFile::frameBuffer () const
905 {
906     return _inputFile->frameBuffer();
907 }
908 
909 
910 const IMATH_NAMESPACE::Box2i &
displayWindow() const911 TiledRgbaInputFile::displayWindow () const
912 {
913     return _inputFile->header().displayWindow();
914 }
915 
916 
917 const IMATH_NAMESPACE::Box2i &
dataWindow() const918 TiledRgbaInputFile::dataWindow () const
919 {
920     return _inputFile->header().dataWindow();
921 }
922 
923 
924 float
pixelAspectRatio() const925 TiledRgbaInputFile::pixelAspectRatio () const
926 {
927     return _inputFile->header().pixelAspectRatio();
928 }
929 
930 
931 const IMATH_NAMESPACE::V2f
screenWindowCenter() const932 TiledRgbaInputFile::screenWindowCenter () const
933 {
934     return _inputFile->header().screenWindowCenter();
935 }
936 
937 
938 float
screenWindowWidth() const939 TiledRgbaInputFile::screenWindowWidth () const
940 {
941     return _inputFile->header().screenWindowWidth();
942 }
943 
944 
945 LineOrder
lineOrder() const946 TiledRgbaInputFile::lineOrder () const
947 {
948     return _inputFile->header().lineOrder();
949 }
950 
951 
952 Compression
compression() const953 TiledRgbaInputFile::compression () const
954 {
955     return _inputFile->header().compression();
956 }
957 
958 
959 RgbaChannels
channels() const960 TiledRgbaInputFile::channels () const
961 {
962     return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
963 }
964 
965 
966 int
version() const967 TiledRgbaInputFile::version () const
968 {
969     return _inputFile->version();
970 }
971 
972 
973 bool
isComplete() const974 TiledRgbaInputFile::isComplete () const
975 {
976     return _inputFile->isComplete();
977 }
978 
979 
980 unsigned int
tileXSize() const981 TiledRgbaInputFile::tileXSize () const
982 {
983      return _inputFile->tileXSize();
984 }
985 
986 
987 unsigned int
tileYSize() const988 TiledRgbaInputFile::tileYSize () const
989 {
990      return _inputFile->tileYSize();
991 }
992 
993 
994 LevelMode
levelMode() const995 TiledRgbaInputFile::levelMode () const
996 {
997      return _inputFile->levelMode();
998 }
999 
1000 
1001 LevelRoundingMode
levelRoundingMode() const1002 TiledRgbaInputFile::levelRoundingMode () const
1003 {
1004      return _inputFile->levelRoundingMode();
1005 }
1006 
1007 
1008 int
numLevels() const1009 TiledRgbaInputFile::numLevels () const
1010 {
1011      return _inputFile->numLevels();
1012 }
1013 
1014 
1015 int
numXLevels() const1016 TiledRgbaInputFile::numXLevels () const
1017 {
1018      return _inputFile->numXLevels();
1019 }
1020 
1021 
1022 int
numYLevels() const1023 TiledRgbaInputFile::numYLevels () const
1024 {
1025      return _inputFile->numYLevels();
1026 }
1027 
1028 
1029 bool
isValidLevel(int lx,int ly) const1030 TiledRgbaInputFile::isValidLevel (int lx, int ly) const
1031 {
1032     return _inputFile->isValidLevel (lx, ly);
1033 }
1034 
1035 
1036 int
levelWidth(int lx) const1037 TiledRgbaInputFile::levelWidth (int lx) const
1038 {
1039      return _inputFile->levelWidth (lx);
1040 }
1041 
1042 
1043 int
levelHeight(int ly) const1044 TiledRgbaInputFile::levelHeight (int ly) const
1045 {
1046      return _inputFile->levelHeight (ly);
1047 }
1048 
1049 
1050 int
numXTiles(int lx) const1051 TiledRgbaInputFile::numXTiles (int lx) const
1052 {
1053      return _inputFile->numXTiles(lx);
1054 }
1055 
1056 
1057 int
numYTiles(int ly) const1058 TiledRgbaInputFile::numYTiles (int ly) const
1059 {
1060      return _inputFile->numYTiles(ly);
1061 }
1062 
1063 
1064 IMATH_NAMESPACE::Box2i
dataWindowForLevel(int l) const1065 TiledRgbaInputFile::dataWindowForLevel (int l) const
1066 {
1067      return _inputFile->dataWindowForLevel (l);
1068 }
1069 
1070 
1071 IMATH_NAMESPACE::Box2i
dataWindowForLevel(int lx,int ly) const1072 TiledRgbaInputFile::dataWindowForLevel (int lx, int ly) const
1073 {
1074      return _inputFile->dataWindowForLevel (lx, ly);
1075 }
1076 
1077 
1078 IMATH_NAMESPACE::Box2i
dataWindowForTile(int dx,int dy,int l) const1079 TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int l) const
1080 {
1081      return _inputFile->dataWindowForTile (dx, dy, l);
1082 }
1083 
1084 
1085 IMATH_NAMESPACE::Box2i
dataWindowForTile(int dx,int dy,int lx,int ly) const1086 TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
1087 {
1088      return _inputFile->dataWindowForTile (dx, dy, lx, ly);
1089 }
1090 
1091 
1092 void
readTile(int dx,int dy,int l)1093 TiledRgbaInputFile::readTile (int dx, int dy, int l)
1094 {
1095     if (_fromYa)
1096     {
1097 	Lock lock (*_fromYa);
1098 	_fromYa->readTile (dx, dy, l, l);
1099     }
1100     else
1101     {
1102 	 _inputFile->readTile (dx, dy, l);
1103     }
1104 }
1105 
1106 
1107 void
readTile(int dx,int dy,int lx,int ly)1108 TiledRgbaInputFile::readTile (int dx, int dy, int lx, int ly)
1109 {
1110     if (_fromYa)
1111     {
1112 	Lock lock (*_fromYa);
1113 	_fromYa->readTile (dx, dy, lx, ly);
1114     }
1115     else
1116     {
1117 	 _inputFile->readTile (dx, dy, lx, ly);
1118     }
1119 }
1120 
1121 
1122 void
readTiles(int dxMin,int dxMax,int dyMin,int dyMax,int lx,int ly)1123 TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
1124                                int lx, int ly)
1125 {
1126     if (_fromYa)
1127     {
1128 	Lock lock (*_fromYa);
1129 
1130         for (int dy = dyMin; dy <= dyMax; dy++)
1131             for (int dx = dxMin; dx <= dxMax; dx++)
1132 	        _fromYa->readTile (dx, dy, lx, ly);
1133     }
1134     else
1135     {
1136         _inputFile->readTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
1137     }
1138 }
1139 
1140 void
readTiles(int dxMin,int dxMax,int dyMin,int dyMax,int l)1141 TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
1142                                int l)
1143 {
1144     readTiles (dxMin, dxMax, dyMin, dyMax, l, l);
1145 }
1146 
1147 
1148 void
updatePreviewImage(const PreviewRgba newPixels[])1149 TiledRgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
1150 {
1151     _outputFile->updatePreviewImage (newPixels);
1152 }
1153 
1154 
1155 void
breakTile(int dx,int dy,int lx,int ly,int offset,int length,char c)1156 TiledRgbaOutputFile::breakTile  (int dx, int dy, int lx, int ly,
1157 				 int offset, int length, char c)
1158 {
1159     _outputFile->breakTile (dx, dy, lx, ly, offset, length, c);
1160 }
1161 
1162 
1163 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
1164