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
55 namespace Imf {
56
57 using namespace std;
58 using namespace Imath;
59 using namespace RgbaYca;
60 using namespace IlmThread;
61
62 namespace {
63
64 void
insertChannels(Header & header,RgbaChannels rgbaChannels,const char fileName[])65 insertChannels (Header &header,
66 RgbaChannels rgbaChannels,
67 const char fileName[])
68 {
69 ChannelList ch;
70
71 if (rgbaChannels & (WRITE_Y | WRITE_C))
72 {
73 if (rgbaChannels & WRITE_Y)
74 {
75 ch.insert ("Y", Channel (HALF, 1, 1));
76 }
77
78 if (rgbaChannels & WRITE_C)
79 {
80 THROW (Iex::ArgExc, "Cannot open file \"" << fileName << "\" "
81 "for writing. Tiled image files do not "
82 "support subsampled chroma channels.");
83 }
84 }
85 else
86 {
87 if (rgbaChannels & WRITE_R)
88 ch.insert ("R", Channel (HALF, 1, 1));
89
90 if (rgbaChannels & WRITE_G)
91 ch.insert ("G", Channel (HALF, 1, 1));
92
93 if (rgbaChannels & WRITE_B)
94 ch.insert ("B", Channel (HALF, 1, 1));
95 }
96
97 if (rgbaChannels & WRITE_A)
98 ch.insert ("A", Channel (HALF, 1, 1));
99
100 header.channels() = ch;
101 }
102
103
104 RgbaChannels
rgbaChannels(const ChannelList & ch,const string & channelNamePrefix="")105 rgbaChannels (const ChannelList &ch, const string &channelNamePrefix = "")
106 {
107 int i = 0;
108
109 if (ch.findChannel (channelNamePrefix + "R"))
110 i |= WRITE_R;
111
112 if (ch.findChannel (channelNamePrefix + "G"))
113 i |= WRITE_G;
114
115 if (ch.findChannel (channelNamePrefix + "B"))
116 i |= WRITE_B;
117
118 if (ch.findChannel (channelNamePrefix + "A"))
119 i |= WRITE_A;
120
121 if (ch.findChannel (channelNamePrefix + "Y"))
122 i |= WRITE_Y;
123
124 return RgbaChannels (i);
125 }
126
127
128 string
prefixFromLayerName(const string & layerName,const Header & header)129 prefixFromLayerName (const string &layerName, const Header &header)
130 {
131 if (layerName.empty())
132 return "";
133
134 if (hasMultiView (header) && multiView(header)[0] == layerName)
135 return "";
136
137 return layerName + ".";
138 }
139
140
141 V3f
ywFromHeader(const Header & header)142 ywFromHeader (const Header &header)
143 {
144 Chromaticities cr;
145
146 if (hasChromaticities (header))
147 cr = chromaticities (header);
148
149 return computeYw (cr);
150 }
151
152 } // namespace
153
154
155 class TiledRgbaOutputFile::ToYa: public Mutex
156 {
157 public:
158
159 ToYa (TiledOutputFile &outputFile, RgbaChannels rgbaChannels);
160
161 void setFrameBuffer (const Rgba *base,
162 size_t xStride,
163 size_t yStride);
164
165 void writeTile (int dx, int dy, int lx, int ly);
166
167 private:
168
169 TiledOutputFile & _outputFile;
170 bool _writeA;
171 unsigned int _tileXSize;
172 unsigned int _tileYSize;
173 V3f _yw;
174 Array2D <Rgba> _buf;
175 const Rgba * _fbBase;
176 size_t _fbXStride;
177 size_t _fbYStride;
178 };
179
180
ToYa(TiledOutputFile & outputFile,RgbaChannels rgbaChannels)181 TiledRgbaOutputFile::ToYa::ToYa (TiledOutputFile &outputFile,
182 RgbaChannels rgbaChannels)
183 :
184 _outputFile (outputFile)
185 {
186 _writeA = (rgbaChannels & WRITE_A)? true: false;
187
188 const TileDescription &td = outputFile.header().tileDescription();
189
190 _tileXSize = td.xSize;
191 _tileYSize = td.ySize;
192 _yw = ywFromHeader (_outputFile.header());
193 _buf.resizeErase (_tileYSize, _tileXSize);
194 _fbBase = 0;
195 _fbXStride = 0;
196 _fbYStride = 0;
197 }
198
199
200 void
setFrameBuffer(const Rgba * base,size_t xStride,size_t yStride)201 TiledRgbaOutputFile::ToYa::setFrameBuffer (const Rgba *base,
202 size_t xStride,
203 size_t yStride)
204 {
205 _fbBase = base;
206 _fbXStride = xStride;
207 _fbYStride = yStride;
208 }
209
210
211 void
writeTile(int dx,int dy,int lx,int ly)212 TiledRgbaOutputFile::ToYa::writeTile (int dx, int dy, int lx, int ly)
213 {
214 if (_fbBase == 0)
215 {
216 THROW (Iex::ArgExc, "No frame buffer was specified as the "
217 "pixel data source for image file "
218 "\"" << _outputFile.fileName() << "\".");
219 }
220
221 //
222 // Copy the tile's RGBA pixels into _buf and convert
223 // them to luminance/alpha format
224 //
225
226 Box2i dw = _outputFile.dataWindowForTile (dx, dy, lx, ly);
227 int width = dw.max.x - dw.min.x + 1;
228
229 for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
230 {
231 for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
232 _buf[y1][x1] = _fbBase[x * _fbXStride + y * _fbYStride];
233
234 RGBAtoYCA (_yw, width, _writeA, _buf[y1], _buf[y1]);
235 }
236
237 //
238 // Store the contents of _buf in the output file
239 //
240
241 FrameBuffer fb;
242
243 fb.insert ("Y", Slice (HALF, // type
244 (char *) &_buf[-dw.min.y][-dw.min.x].g, // base
245 sizeof (Rgba), // xStride
246 sizeof (Rgba) * _tileXSize)); // yStride
247
248 fb.insert ("A", Slice (HALF, // type
249 (char *) &_buf[-dw.min.y][-dw.min.x].a, // base
250 sizeof (Rgba), // xStride
251 sizeof (Rgba) * _tileXSize)); // yStride
252
253 _outputFile.setFrameBuffer (fb);
254 _outputFile.writeTile (dx, dy, lx, ly);
255 }
256
257
TiledRgbaOutputFile(const char name[],const Header & header,RgbaChannels rgbaChannels,int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,int numThreads)258 TiledRgbaOutputFile::TiledRgbaOutputFile
259 (const char name[],
260 const Header &header,
261 RgbaChannels rgbaChannels,
262 int tileXSize,
263 int tileYSize,
264 LevelMode mode,
265 LevelRoundingMode rmode,
266 int numThreads)
267 :
268 _outputFile (0),
269 _toYa (0)
270 {
271 Header hd (header);
272 insertChannels (hd, rgbaChannels, name);
273 hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
274 _outputFile = new TiledOutputFile (name, hd, numThreads);
275
276 if (rgbaChannels & WRITE_Y)
277 _toYa = new ToYa (*_outputFile, rgbaChannels);
278 }
279
280
281
TiledRgbaOutputFile(OStream & os,const Header & header,RgbaChannels rgbaChannels,int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,int numThreads)282 TiledRgbaOutputFile::TiledRgbaOutputFile
283 (OStream &os,
284 const Header &header,
285 RgbaChannels rgbaChannels,
286 int tileXSize,
287 int tileYSize,
288 LevelMode mode,
289 LevelRoundingMode rmode,
290 int numThreads)
291 :
292 _outputFile (0),
293 _toYa (0)
294 {
295 Header hd (header);
296 insertChannels (hd, rgbaChannels, os.fileName());
297 hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
298 _outputFile = new TiledOutputFile (os, hd, numThreads);
299
300 if (rgbaChannels & WRITE_Y)
301 _toYa = new ToYa (*_outputFile, rgbaChannels);
302 }
303
304
305
TiledRgbaOutputFile(const char name[],int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,const Imath::Box2i & displayWindow,const Imath::Box2i & dataWindow,RgbaChannels rgbaChannels,float pixelAspectRatio,const Imath::V2f screenWindowCenter,float screenWindowWidth,LineOrder lineOrder,Compression compression,int numThreads)306 TiledRgbaOutputFile::TiledRgbaOutputFile
307 (const char name[],
308 int tileXSize,
309 int tileYSize,
310 LevelMode mode,
311 LevelRoundingMode rmode,
312 const Imath::Box2i &displayWindow,
313 const Imath::Box2i &dataWindow,
314 RgbaChannels rgbaChannels,
315 float pixelAspectRatio,
316 const Imath::V2f screenWindowCenter,
317 float screenWindowWidth,
318 LineOrder lineOrder,
319 Compression compression,
320 int numThreads)
321 :
322 _outputFile (0),
323 _toYa (0)
324 {
325 Header hd (displayWindow,
326 dataWindow.isEmpty()? displayWindow: dataWindow,
327 pixelAspectRatio,
328 screenWindowCenter,
329 screenWindowWidth,
330 lineOrder,
331 compression);
332
333 insertChannels (hd, rgbaChannels, name);
334 hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
335 _outputFile = new TiledOutputFile (name, hd, numThreads);
336
337 if (rgbaChannels & WRITE_Y)
338 _toYa = new ToYa (*_outputFile, rgbaChannels);
339 }
340
341
TiledRgbaOutputFile(const char name[],int width,int height,int tileXSize,int tileYSize,LevelMode mode,LevelRoundingMode rmode,RgbaChannels rgbaChannels,float pixelAspectRatio,const Imath::V2f screenWindowCenter,float screenWindowWidth,LineOrder lineOrder,Compression compression,int numThreads)342 TiledRgbaOutputFile::TiledRgbaOutputFile
343 (const char name[],
344 int width,
345 int height,
346 int tileXSize,
347 int tileYSize,
348 LevelMode mode,
349 LevelRoundingMode rmode,
350 RgbaChannels rgbaChannels,
351 float pixelAspectRatio,
352 const Imath::V2f screenWindowCenter,
353 float screenWindowWidth,
354 LineOrder lineOrder,
355 Compression compression,
356 int numThreads)
357 :
358 _outputFile (0),
359 _toYa (0)
360 {
361 Header hd (width,
362 height,
363 pixelAspectRatio,
364 screenWindowCenter,
365 screenWindowWidth,
366 lineOrder,
367 compression);
368
369 insertChannels (hd, rgbaChannels, name);
370 hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
371 _outputFile = new TiledOutputFile (name, hd, numThreads);
372
373 if (rgbaChannels & WRITE_Y)
374 _toYa = new ToYa (*_outputFile, rgbaChannels);
375 }
376
377
~TiledRgbaOutputFile()378 TiledRgbaOutputFile::~TiledRgbaOutputFile ()
379 {
380 delete _outputFile;
381 delete _toYa;
382 }
383
384
385 void
setFrameBuffer(const Rgba * base,size_t xStride,size_t yStride)386 TiledRgbaOutputFile::setFrameBuffer (const Rgba *base,
387 size_t xStride,
388 size_t yStride)
389 {
390 if (_toYa)
391 {
392 Lock lock (*_toYa);
393 _toYa->setFrameBuffer (base, xStride, yStride);
394 }
395 else
396 {
397 size_t xs = xStride * sizeof (Rgba);
398 size_t ys = yStride * sizeof (Rgba);
399
400 FrameBuffer fb;
401
402 fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
403 fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
404 fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
405 fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
406
407 _outputFile->setFrameBuffer (fb);
408 }
409 }
410
411
412 const Header &
header() const413 TiledRgbaOutputFile::header () const
414 {
415 return _outputFile->header();
416 }
417
418
419 const FrameBuffer &
frameBuffer() const420 TiledRgbaOutputFile::frameBuffer () const
421 {
422 return _outputFile->frameBuffer();
423 }
424
425
426 const Imath::Box2i &
displayWindow() const427 TiledRgbaOutputFile::displayWindow () const
428 {
429 return _outputFile->header().displayWindow();
430 }
431
432
433 const Imath::Box2i &
dataWindow() const434 TiledRgbaOutputFile::dataWindow () const
435 {
436 return _outputFile->header().dataWindow();
437 }
438
439
440 float
pixelAspectRatio() const441 TiledRgbaOutputFile::pixelAspectRatio () const
442 {
443 return _outputFile->header().pixelAspectRatio();
444 }
445
446
447 const Imath::V2f
screenWindowCenter() const448 TiledRgbaOutputFile::screenWindowCenter () const
449 {
450 return _outputFile->header().screenWindowCenter();
451 }
452
453
454 float
screenWindowWidth() const455 TiledRgbaOutputFile::screenWindowWidth () const
456 {
457 return _outputFile->header().screenWindowWidth();
458 }
459
460
461 LineOrder
lineOrder() const462 TiledRgbaOutputFile::lineOrder () const
463 {
464 return _outputFile->header().lineOrder();
465 }
466
467
468 Compression
compression() const469 TiledRgbaOutputFile::compression () const
470 {
471 return _outputFile->header().compression();
472 }
473
474
475 RgbaChannels
channels() const476 TiledRgbaOutputFile::channels () const
477 {
478 return rgbaChannels (_outputFile->header().channels());
479 }
480
481
482 unsigned int
tileXSize() const483 TiledRgbaOutputFile::tileXSize () const
484 {
485 return _outputFile->tileXSize();
486 }
487
488
489 unsigned int
tileYSize() const490 TiledRgbaOutputFile::tileYSize () const
491 {
492 return _outputFile->tileYSize();
493 }
494
495
496 LevelMode
levelMode() const497 TiledRgbaOutputFile::levelMode () const
498 {
499 return _outputFile->levelMode();
500 }
501
502
503 LevelRoundingMode
levelRoundingMode() const504 TiledRgbaOutputFile::levelRoundingMode () const
505 {
506 return _outputFile->levelRoundingMode();
507 }
508
509
510 int
numLevels() const511 TiledRgbaOutputFile::numLevels () const
512 {
513 return _outputFile->numLevels();
514 }
515
516
517 int
numXLevels() const518 TiledRgbaOutputFile::numXLevels () const
519 {
520 return _outputFile->numXLevels();
521 }
522
523
524 int
numYLevels() const525 TiledRgbaOutputFile::numYLevels () const
526 {
527 return _outputFile->numYLevels();
528 }
529
530
531 bool
isValidLevel(int lx,int ly) const532 TiledRgbaOutputFile::isValidLevel (int lx, int ly) const
533 {
534 return _outputFile->isValidLevel (lx, ly);
535 }
536
537
538 int
levelWidth(int lx) const539 TiledRgbaOutputFile::levelWidth (int lx) const
540 {
541 return _outputFile->levelWidth (lx);
542 }
543
544
545 int
levelHeight(int ly) const546 TiledRgbaOutputFile::levelHeight (int ly) const
547 {
548 return _outputFile->levelHeight (ly);
549 }
550
551
552 int
numXTiles(int lx) const553 TiledRgbaOutputFile::numXTiles (int lx) const
554 {
555 return _outputFile->numXTiles (lx);
556 }
557
558
559 int
numYTiles(int ly) const560 TiledRgbaOutputFile::numYTiles (int ly) const
561 {
562 return _outputFile->numYTiles (ly);
563 }
564
565
566 Imath::Box2i
dataWindowForLevel(int l) const567 TiledRgbaOutputFile::dataWindowForLevel (int l) const
568 {
569 return _outputFile->dataWindowForLevel (l);
570 }
571
572
573 Imath::Box2i
dataWindowForLevel(int lx,int ly) const574 TiledRgbaOutputFile::dataWindowForLevel (int lx, int ly) const
575 {
576 return _outputFile->dataWindowForLevel (lx, ly);
577 }
578
579
580 Imath::Box2i
dataWindowForTile(int dx,int dy,int l) const581 TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int l) const
582 {
583 return _outputFile->dataWindowForTile (dx, dy, l);
584 }
585
586
587 Imath::Box2i
dataWindowForTile(int dx,int dy,int lx,int ly) const588 TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
589 {
590 return _outputFile->dataWindowForTile (dx, dy, lx, ly);
591 }
592
593
594 void
writeTile(int dx,int dy,int l)595 TiledRgbaOutputFile::writeTile (int dx, int dy, int l)
596 {
597 if (_toYa)
598 {
599 Lock lock (*_toYa);
600 _toYa->writeTile (dx, dy, l, l);
601 }
602 else
603 {
604 _outputFile->writeTile (dx, dy, l);
605 }
606 }
607
608
609 void
writeTile(int dx,int dy,int lx,int ly)610 TiledRgbaOutputFile::writeTile (int dx, int dy, int lx, int ly)
611 {
612 if (_toYa)
613 {
614 Lock lock (*_toYa);
615 _toYa->writeTile (dx, dy, lx, ly);
616 }
617 else
618 {
619 _outputFile->writeTile (dx, dy, lx, ly);
620 }
621 }
622
623
624 void
writeTiles(int dxMin,int dxMax,int dyMin,int dyMax,int lx,int ly)625 TiledRgbaOutputFile::writeTiles
626 (int dxMin, int dxMax, int dyMin, int dyMax, int lx, int ly)
627 {
628 if (_toYa)
629 {
630 Lock lock (*_toYa);
631
632 for (int dy = dyMin; dy <= dyMax; dy++)
633 for (int dx = dxMin; dx <= dxMax; dx++)
634 _toYa->writeTile (dx, dy, lx, ly);
635 }
636 else
637 {
638 _outputFile->writeTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
639 }
640 }
641
642 void
writeTiles(int dxMin,int dxMax,int dyMin,int dyMax,int l)643 TiledRgbaOutputFile::writeTiles
644 (int dxMin, int dxMax, int dyMin, int dyMax, int l)
645 {
646 writeTiles (dxMin, dxMax, dyMin, dyMax, l, l);
647 }
648
649
650 class TiledRgbaInputFile::FromYa: public Mutex
651 {
652 public:
653
654 FromYa (TiledInputFile &inputFile);
655
656 void setFrameBuffer (Rgba *base,
657 size_t xStride,
658 size_t yStride,
659 const string &channelNamePrefix);
660
661 void readTile (int dx, int dy, int lx, int ly);
662
663 private:
664
665 TiledInputFile & _inputFile;
666 unsigned int _tileXSize;
667 unsigned int _tileYSize;
668 V3f _yw;
669 Array2D <Rgba> _buf;
670 Rgba * _fbBase;
671 size_t _fbXStride;
672 size_t _fbYStride;
673 };
674
675
FromYa(TiledInputFile & inputFile)676 TiledRgbaInputFile::FromYa::FromYa (TiledInputFile &inputFile)
677 :
678 _inputFile (inputFile)
679 {
680 const TileDescription &td = inputFile.header().tileDescription();
681
682 _tileXSize = td.xSize;
683 _tileYSize = td.ySize;
684 _yw = ywFromHeader (_inputFile.header());
685 _buf.resizeErase (_tileYSize, _tileXSize);
686 _fbBase = 0;
687 _fbXStride = 0;
688 _fbYStride = 0;
689 }
690
691
692 void
setFrameBuffer(Rgba * base,size_t xStride,size_t yStride,const string & channelNamePrefix)693 TiledRgbaInputFile::FromYa::setFrameBuffer (Rgba *base,
694 size_t xStride,
695 size_t yStride,
696 const string &channelNamePrefix)
697 {
698 if (_fbBase == 0)
699 {
700 FrameBuffer fb;
701
702 fb.insert (channelNamePrefix + "Y",
703 Slice (HALF, // type
704 (char *) &_buf[0][0].g, // base
705 sizeof (Rgba), // xStride
706 sizeof (Rgba) * _tileXSize, // yStride
707 1, 1, // sampling
708 0.0, // fillValue
709 true, true)); // tileCoordinates
710
711 fb.insert (channelNamePrefix + "A",
712 Slice (HALF, // type
713 (char *) &_buf[0][0].a, // base
714 sizeof (Rgba), // xStride
715 sizeof (Rgba) * _tileXSize, // yStride
716 1, 1, // sampling
717 1.0, // fillValue
718 true, true)); // tileCoordinates
719
720 _inputFile.setFrameBuffer (fb);
721 }
722
723 _fbBase = base;
724 _fbXStride = xStride;
725 _fbYStride = yStride;
726 }
727
728
729 void
readTile(int dx,int dy,int lx,int ly)730 TiledRgbaInputFile::FromYa::readTile (int dx, int dy, int lx, int ly)
731 {
732 if (_fbBase == 0)
733 {
734 THROW (Iex::ArgExc, "No frame buffer was specified as the "
735 "pixel data destination for image file "
736 "\"" << _inputFile.fileName() << "\".");
737 }
738
739 //
740 // Read the tile requested by the caller into _buf.
741 //
742
743 _inputFile.readTile (dx, dy, lx, ly);
744
745 //
746 // Convert the luminance/alpha pixels to RGBA
747 // and copy them into the caller's frame buffer.
748 //
749
750 Box2i dw = _inputFile.dataWindowForTile (dx, dy, lx, ly);
751 int width = dw.max.x - dw.min.x + 1;
752
753 for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
754 {
755 for (int x1 = 0; x1 < width; ++x1)
756 {
757 _buf[y1][x1].r = 0;
758 _buf[y1][x1].b = 0;
759 }
760
761 YCAtoRGBA (_yw, width, _buf[y1], _buf[y1]);
762
763 for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
764 {
765 _fbBase[x * _fbXStride + y * _fbYStride] = _buf[y1][x1];
766 }
767 }
768 }
769
770
TiledRgbaInputFile(const char name[],int numThreads)771 TiledRgbaInputFile::TiledRgbaInputFile (const char name[], int numThreads):
772 _inputFile (new TiledInputFile (name, numThreads)),
773 _fromYa (0),
774 _channelNamePrefix ("")
775 {
776 if (channels() & WRITE_Y)
777 _fromYa = new FromYa (*_inputFile);
778 }
779
780
TiledRgbaInputFile(IStream & is,int numThreads)781 TiledRgbaInputFile::TiledRgbaInputFile (IStream &is, int numThreads):
782 _inputFile (new TiledInputFile (is, numThreads)),
783 _fromYa (0),
784 _channelNamePrefix ("")
785 {
786 if (channels() & WRITE_Y)
787 _fromYa = new FromYa (*_inputFile);
788 }
789
790
TiledRgbaInputFile(const char name[],const string & layerName,int numThreads)791 TiledRgbaInputFile::TiledRgbaInputFile (const char name[],
792 const string &layerName,
793 int numThreads)
794 :
795 _inputFile (new TiledInputFile (name, numThreads)),
796 _fromYa (0),
797 _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
798 {
799 if (channels() & WRITE_Y)
800 _fromYa = new FromYa (*_inputFile);
801 }
802
803
TiledRgbaInputFile(IStream & is,const string & layerName,int numThreads)804 TiledRgbaInputFile::TiledRgbaInputFile (IStream &is,
805 const string &layerName,
806 int numThreads)
807 :
808 _inputFile (new TiledInputFile (is, numThreads)),
809 _fromYa (0),
810 _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
811 {
812 if (channels() & WRITE_Y)
813 _fromYa = new FromYa (*_inputFile);
814 }
815
816
~TiledRgbaInputFile()817 TiledRgbaInputFile::~TiledRgbaInputFile ()
818 {
819 delete _inputFile;
820 delete _fromYa;
821 }
822
823
824 void
setFrameBuffer(Rgba * base,size_t xStride,size_t yStride)825 TiledRgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
826 {
827 if (_fromYa)
828 {
829 Lock lock (*_fromYa);
830 _fromYa->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
831 }
832 else
833 {
834 size_t xs = xStride * sizeof (Rgba);
835 size_t ys = yStride * sizeof (Rgba);
836
837 FrameBuffer fb;
838
839 fb.insert (_channelNamePrefix + "R",
840 Slice (HALF,
841 (char *) &base[0].r,
842 xs, ys,
843 1, 1, // xSampling, ySampling
844 0.0)); // fillValue
845
846 fb.insert (_channelNamePrefix + "G",
847 Slice (HALF,
848 (char *) &base[0].g,
849 xs, ys,
850 1, 1, // xSampling, ySampling
851 0.0)); // fillValue
852
853 fb.insert (_channelNamePrefix + "B",
854 Slice (HALF,
855 (char *) &base[0].b,
856 xs, ys,
857 1, 1, // xSampling, ySampling
858 0.0)); // fillValue
859
860 fb.insert (_channelNamePrefix + "A",
861 Slice (HALF,
862 (char *) &base[0].a,
863 xs, ys,
864 1, 1, // xSampling, ySampling
865 1.0)); // fillValue
866
867 _inputFile->setFrameBuffer (fb);
868 }
869 }
870
871
872 void
setLayerName(const std::string & layerName)873 TiledRgbaInputFile::setLayerName (const std::string &layerName)
874 {
875 delete _fromYa;
876 _fromYa = 0;
877
878 _channelNamePrefix = prefixFromLayerName (layerName, _inputFile->header());
879
880 if (channels() & WRITE_Y)
881 _fromYa = new FromYa (*_inputFile);
882
883 FrameBuffer fb;
884 _inputFile->setFrameBuffer (fb);
885 }
886
887
888 const Header &
header() const889 TiledRgbaInputFile::header () const
890 {
891 return _inputFile->header();
892 }
893
894
895 const char *
fileName() const896 TiledRgbaInputFile::fileName () const
897 {
898 return _inputFile->fileName();
899 }
900
901
902 const FrameBuffer &
frameBuffer() const903 TiledRgbaInputFile::frameBuffer () const
904 {
905 return _inputFile->frameBuffer();
906 }
907
908
909 const Imath::Box2i &
displayWindow() const910 TiledRgbaInputFile::displayWindow () const
911 {
912 return _inputFile->header().displayWindow();
913 }
914
915
916 const Imath::Box2i &
dataWindow() const917 TiledRgbaInputFile::dataWindow () const
918 {
919 return _inputFile->header().dataWindow();
920 }
921
922
923 float
pixelAspectRatio() const924 TiledRgbaInputFile::pixelAspectRatio () const
925 {
926 return _inputFile->header().pixelAspectRatio();
927 }
928
929
930 const Imath::V2f
screenWindowCenter() const931 TiledRgbaInputFile::screenWindowCenter () const
932 {
933 return _inputFile->header().screenWindowCenter();
934 }
935
936
937 float
screenWindowWidth() const938 TiledRgbaInputFile::screenWindowWidth () const
939 {
940 return _inputFile->header().screenWindowWidth();
941 }
942
943
944 LineOrder
lineOrder() const945 TiledRgbaInputFile::lineOrder () const
946 {
947 return _inputFile->header().lineOrder();
948 }
949
950
951 Compression
compression() const952 TiledRgbaInputFile::compression () const
953 {
954 return _inputFile->header().compression();
955 }
956
957
958 RgbaChannels
channels() const959 TiledRgbaInputFile::channels () const
960 {
961 return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
962 }
963
964
965 int
version() const966 TiledRgbaInputFile::version () const
967 {
968 return _inputFile->version();
969 }
970
971
972 bool
isComplete() const973 TiledRgbaInputFile::isComplete () const
974 {
975 return _inputFile->isComplete();
976 }
977
978
979 unsigned int
tileXSize() const980 TiledRgbaInputFile::tileXSize () const
981 {
982 return _inputFile->tileXSize();
983 }
984
985
986 unsigned int
tileYSize() const987 TiledRgbaInputFile::tileYSize () const
988 {
989 return _inputFile->tileYSize();
990 }
991
992
993 LevelMode
levelMode() const994 TiledRgbaInputFile::levelMode () const
995 {
996 return _inputFile->levelMode();
997 }
998
999
1000 LevelRoundingMode
levelRoundingMode() const1001 TiledRgbaInputFile::levelRoundingMode () const
1002 {
1003 return _inputFile->levelRoundingMode();
1004 }
1005
1006
1007 int
numLevels() const1008 TiledRgbaInputFile::numLevels () const
1009 {
1010 return _inputFile->numLevels();
1011 }
1012
1013
1014 int
numXLevels() const1015 TiledRgbaInputFile::numXLevels () const
1016 {
1017 return _inputFile->numXLevels();
1018 }
1019
1020
1021 int
numYLevels() const1022 TiledRgbaInputFile::numYLevels () const
1023 {
1024 return _inputFile->numYLevels();
1025 }
1026
1027
1028 bool
isValidLevel(int lx,int ly) const1029 TiledRgbaInputFile::isValidLevel (int lx, int ly) const
1030 {
1031 return _inputFile->isValidLevel (lx, ly);
1032 }
1033
1034
1035 int
levelWidth(int lx) const1036 TiledRgbaInputFile::levelWidth (int lx) const
1037 {
1038 return _inputFile->levelWidth (lx);
1039 }
1040
1041
1042 int
levelHeight(int ly) const1043 TiledRgbaInputFile::levelHeight (int ly) const
1044 {
1045 return _inputFile->levelHeight (ly);
1046 }
1047
1048
1049 int
numXTiles(int lx) const1050 TiledRgbaInputFile::numXTiles (int lx) const
1051 {
1052 return _inputFile->numXTiles(lx);
1053 }
1054
1055
1056 int
numYTiles(int ly) const1057 TiledRgbaInputFile::numYTiles (int ly) const
1058 {
1059 return _inputFile->numYTiles(ly);
1060 }
1061
1062
1063 Imath::Box2i
dataWindowForLevel(int l) const1064 TiledRgbaInputFile::dataWindowForLevel (int l) const
1065 {
1066 return _inputFile->dataWindowForLevel (l);
1067 }
1068
1069
1070 Imath::Box2i
dataWindowForLevel(int lx,int ly) const1071 TiledRgbaInputFile::dataWindowForLevel (int lx, int ly) const
1072 {
1073 return _inputFile->dataWindowForLevel (lx, ly);
1074 }
1075
1076
1077 Imath::Box2i
dataWindowForTile(int dx,int dy,int l) const1078 TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int l) const
1079 {
1080 return _inputFile->dataWindowForTile (dx, dy, l);
1081 }
1082
1083
1084 Imath::Box2i
dataWindowForTile(int dx,int dy,int lx,int ly) const1085 TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
1086 {
1087 return _inputFile->dataWindowForTile (dx, dy, lx, ly);
1088 }
1089
1090
1091 void
readTile(int dx,int dy,int l)1092 TiledRgbaInputFile::readTile (int dx, int dy, int l)
1093 {
1094 if (_fromYa)
1095 {
1096 Lock lock (*_fromYa);
1097 _fromYa->readTile (dx, dy, l, l);
1098 }
1099 else
1100 {
1101 _inputFile->readTile (dx, dy, l);
1102 }
1103 }
1104
1105
1106 void
readTile(int dx,int dy,int lx,int ly)1107 TiledRgbaInputFile::readTile (int dx, int dy, int lx, int ly)
1108 {
1109 if (_fromYa)
1110 {
1111 Lock lock (*_fromYa);
1112 _fromYa->readTile (dx, dy, lx, ly);
1113 }
1114 else
1115 {
1116 _inputFile->readTile (dx, dy, lx, ly);
1117 }
1118 }
1119
1120
1121 void
readTiles(int dxMin,int dxMax,int dyMin,int dyMax,int lx,int ly)1122 TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
1123 int lx, int ly)
1124 {
1125 if (_fromYa)
1126 {
1127 Lock lock (*_fromYa);
1128
1129 for (int dy = dyMin; dy <= dyMax; dy++)
1130 for (int dx = dxMin; dx <= dxMax; dx++)
1131 _fromYa->readTile (dx, dy, lx, ly);
1132 }
1133 else
1134 {
1135 _inputFile->readTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
1136 }
1137 }
1138
1139 void
readTiles(int dxMin,int dxMax,int dyMin,int dyMax,int l)1140 TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
1141 int l)
1142 {
1143 readTiles (dxMin, dxMax, dyMin, dyMax, l, l);
1144 }
1145
1146
1147 void
updatePreviewImage(const PreviewRgba newPixels[])1148 TiledRgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
1149 {
1150 _outputFile->updatePreviewImage (newPixels);
1151 }
1152
1153
1154 void
breakTile(int dx,int dy,int lx,int ly,int offset,int length,char c)1155 TiledRgbaOutputFile::breakTile (int dx, int dy, int lx, int ly,
1156 int offset, int length, char c)
1157 {
1158 _outputFile->breakTile (dx, dy, lx, ly, offset, length, c);
1159 }
1160
1161
1162 } // namespace Imf
1163