Home | History | Annotate | Download | only in IlmImf
      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
     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
    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
    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
    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 
    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
    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
    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 
    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 
    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 
    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 
    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 
    378 TiledRgbaOutputFile::~TiledRgbaOutputFile ()
    379 {
    380     delete _outputFile;
    381     delete _toYa;
    382 }
    383 
    384 
    385 void
    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 &
    413 TiledRgbaOutputFile::header () const
    414 {
    415     return _outputFile->header();
    416 }
    417 
    418 
    419 const FrameBuffer &
    420 TiledRgbaOutputFile::frameBuffer () const
    421 {
    422     return _outputFile->frameBuffer();
    423 }
    424 
    425 
    426 const Imath::Box2i &
    427 TiledRgbaOutputFile::displayWindow () const
    428 {
    429     return _outputFile->header().displayWindow();
    430 }
    431 
    432 
    433 const Imath::Box2i &
    434 TiledRgbaOutputFile::dataWindow () const
    435 {
    436     return _outputFile->header().dataWindow();
    437 }
    438 
    439 
    440 float
    441 TiledRgbaOutputFile::pixelAspectRatio () const
    442 {
    443     return _outputFile->header().pixelAspectRatio();
    444 }
    445 
    446 
    447 const Imath::V2f
    448 TiledRgbaOutputFile::screenWindowCenter () const
    449 {
    450     return _outputFile->header().screenWindowCenter();
    451 }
    452 
    453 
    454 float
    455 TiledRgbaOutputFile::screenWindowWidth () const
    456 {
    457     return _outputFile->header().screenWindowWidth();
    458 }
    459 
    460 
    461 LineOrder
    462 TiledRgbaOutputFile::lineOrder () const
    463 {
    464     return _outputFile->header().lineOrder();
    465 }
    466 
    467 
    468 Compression
    469 TiledRgbaOutputFile::compression () const
    470 {
    471     return _outputFile->header().compression();
    472 }
    473 
    474 
    475 RgbaChannels
    476 TiledRgbaOutputFile::channels () const
    477 {
    478     return rgbaChannels (_outputFile->header().channels());
    479 }
    480 
    481 
    482 unsigned int
    483 TiledRgbaOutputFile::tileXSize () const
    484 {
    485      return _outputFile->tileXSize();
    486 }
    487 
    488 
    489 unsigned int
    490 TiledRgbaOutputFile::tileYSize () const
    491 {
    492      return _outputFile->tileYSize();
    493 }
    494 
    495 
    496 LevelMode
    497 TiledRgbaOutputFile::levelMode () const
    498 {
    499      return _outputFile->levelMode();
    500 }
    501 
    502 
    503 LevelRoundingMode
    504 TiledRgbaOutputFile::levelRoundingMode () const
    505 {
    506      return _outputFile->levelRoundingMode();
    507 }
    508 
    509 
    510 int
    511 TiledRgbaOutputFile::numLevels () const
    512 {
    513      return _outputFile->numLevels();
    514 }
    515 
    516 
    517 int
    518 TiledRgbaOutputFile::numXLevels () const
    519 {
    520      return _outputFile->numXLevels();
    521 }
    522 
    523 
    524 int
    525 TiledRgbaOutputFile::numYLevels () const
    526 {
    527      return _outputFile->numYLevels();
    528 }
    529 
    530 
    531 bool
    532 TiledRgbaOutputFile::isValidLevel (int lx, int ly) const
    533 {
    534     return _outputFile->isValidLevel (lx, ly);
    535 }
    536 
    537 
    538 int
    539 TiledRgbaOutputFile::levelWidth (int lx) const
    540 {
    541      return _outputFile->levelWidth (lx);
    542 }
    543 
    544 
    545 int
    546 TiledRgbaOutputFile::levelHeight (int ly) const
    547 {
    548      return _outputFile->levelHeight (ly);
    549 }
    550 
    551 
    552 int
    553 TiledRgbaOutputFile::numXTiles (int lx) const
    554 {
    555      return _outputFile->numXTiles (lx);
    556 }
    557 
    558 
    559 int
    560 TiledRgbaOutputFile::numYTiles (int ly) const
    561 {
    562      return _outputFile->numYTiles (ly);
    563 }
    564 
    565 
    566 Imath::Box2i
    567 TiledRgbaOutputFile::dataWindowForLevel (int l) const
    568 {
    569      return _outputFile->dataWindowForLevel (l);
    570 }
    571 
    572 
    573 Imath::Box2i
    574 TiledRgbaOutputFile::dataWindowForLevel (int lx, int ly) const
    575 {
    576      return _outputFile->dataWindowForLevel (lx, ly);
    577 }
    578 
    579 
    580 Imath::Box2i
    581 TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int l) const
    582 {
    583      return _outputFile->dataWindowForTile (dx, dy, l);
    584 }
    585 
    586 
    587 Imath::Box2i
    588 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
    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
    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
    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
    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 
    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
    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
    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 
    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 
    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 
    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 
    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 
    817 TiledRgbaInputFile::~TiledRgbaInputFile ()
    818 {
    819     delete _inputFile;
    820     delete _fromYa;
    821 }
    822 
    823 
    824 void
    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
    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 &
    889 TiledRgbaInputFile::header () const
    890 {
    891     return _inputFile->header();
    892 }
    893 
    894 
    895 const char *
    896 TiledRgbaInputFile::fileName () const
    897 {
    898     return _inputFile->fileName();
    899 }
    900 
    901 
    902 const FrameBuffer &
    903 TiledRgbaInputFile::frameBuffer () const
    904 {
    905     return _inputFile->frameBuffer();
    906 }
    907 
    908 
    909 const Imath::Box2i &
    910 TiledRgbaInputFile::displayWindow () const
    911 {
    912     return _inputFile->header().displayWindow();
    913 }
    914 
    915 
    916 const Imath::Box2i &
    917 TiledRgbaInputFile::dataWindow () const
    918 {
    919     return _inputFile->header().dataWindow();
    920 }
    921 
    922 
    923 float
    924 TiledRgbaInputFile::pixelAspectRatio () const
    925 {
    926     return _inputFile->header().pixelAspectRatio();
    927 }
    928 
    929 
    930 const Imath::V2f
    931 TiledRgbaInputFile::screenWindowCenter () const
    932 {
    933     return _inputFile->header().screenWindowCenter();
    934 }
    935 
    936 
    937 float
    938 TiledRgbaInputFile::screenWindowWidth () const
    939 {
    940     return _inputFile->header().screenWindowWidth();
    941 }
    942 
    943 
    944 LineOrder
    945 TiledRgbaInputFile::lineOrder () const
    946 {
    947     return _inputFile->header().lineOrder();
    948 }
    949 
    950 
    951 Compression
    952 TiledRgbaInputFile::compression () const
    953 {
    954     return _inputFile->header().compression();
    955 }
    956 
    957 
    958 RgbaChannels
    959 TiledRgbaInputFile::channels () const
    960 {
    961     return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
    962 }
    963 
    964 
    965 int
    966 TiledRgbaInputFile::version () const
    967 {
    968     return _inputFile->version();
    969 }
    970 
    971 
    972 bool
    973 TiledRgbaInputFile::isComplete () const
    974 {
    975     return _inputFile->isComplete();
    976 }
    977 
    978 
    979 unsigned int
    980 TiledRgbaInputFile::tileXSize () const
    981 {
    982      return _inputFile->tileXSize();
    983 }
    984 
    985 
    986 unsigned int
    987 TiledRgbaInputFile::tileYSize () const
    988 {
    989      return _inputFile->tileYSize();
    990 }
    991 
    992 
    993 LevelMode
    994 TiledRgbaInputFile::levelMode () const
    995 {
    996      return _inputFile->levelMode();
    997 }
    998 
    999 
   1000 LevelRoundingMode
   1001 TiledRgbaInputFile::levelRoundingMode () const
   1002 {
   1003      return _inputFile->levelRoundingMode();
   1004 }
   1005 
   1006 
   1007 int
   1008 TiledRgbaInputFile::numLevels () const
   1009 {
   1010      return _inputFile->numLevels();
   1011 }
   1012 
   1013 
   1014 int
   1015 TiledRgbaInputFile::numXLevels () const
   1016 {
   1017      return _inputFile->numXLevels();
   1018 }
   1019 
   1020 
   1021 int
   1022 TiledRgbaInputFile::numYLevels () const
   1023 {
   1024      return _inputFile->numYLevels();
   1025 }
   1026 
   1027 
   1028 bool
   1029 TiledRgbaInputFile::isValidLevel (int lx, int ly) const
   1030 {
   1031     return _inputFile->isValidLevel (lx, ly);
   1032 }
   1033 
   1034 
   1035 int
   1036 TiledRgbaInputFile::levelWidth (int lx) const
   1037 {
   1038      return _inputFile->levelWidth (lx);
   1039 }
   1040 
   1041 
   1042 int
   1043 TiledRgbaInputFile::levelHeight (int ly) const
   1044 {
   1045      return _inputFile->levelHeight (ly);
   1046 }
   1047 
   1048 
   1049 int
   1050 TiledRgbaInputFile::numXTiles (int lx) const
   1051 {
   1052      return _inputFile->numXTiles(lx);
   1053 }
   1054 
   1055 
   1056 int
   1057 TiledRgbaInputFile::numYTiles (int ly) const
   1058 {
   1059      return _inputFile->numYTiles(ly);
   1060 }
   1061 
   1062 
   1063 Imath::Box2i
   1064 TiledRgbaInputFile::dataWindowForLevel (int l) const
   1065 {
   1066      return _inputFile->dataWindowForLevel (l);
   1067 }
   1068 
   1069 
   1070 Imath::Box2i
   1071 TiledRgbaInputFile::dataWindowForLevel (int lx, int ly) const
   1072 {
   1073      return _inputFile->dataWindowForLevel (lx, ly);
   1074 }
   1075 
   1076 
   1077 Imath::Box2i
   1078 TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int l) const
   1079 {
   1080      return _inputFile->dataWindowForTile (dx, dy, l);
   1081 }
   1082 
   1083 
   1084 Imath::Box2i
   1085 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
   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
   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
   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
   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
   1148 TiledRgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
   1149 {
   1150     _outputFile->updatePreviewImage (newPixels);
   1151 }
   1152 
   1153 
   1154 void
   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