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