1
///////////////////////////////////////////////////////////////////////////
3
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
6
// All rights reserved.
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions are
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
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.
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.
33
///////////////////////////////////////////////////////////////////////////
35
//-----------------------------------------------------------------------------
37
// class TiledRgbaOutputFile
38
// class TiledRgbaInputFile
40
//-----------------------------------------------------------------------------
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>
51
#include "IlmThreadMutex.h"
58
using namespace Imath;
59
using namespace RgbaYca;
60
using namespace IlmThread;
65
insertChannels (Header &header,
66
RgbaChannels rgbaChannels,
67
const char fileName[])
71
if (rgbaChannels & (WRITE_Y | WRITE_C))
73
if (rgbaChannels & WRITE_Y)
75
ch.insert ("Y", Channel (HALF, 1, 1));
78
if (rgbaChannels & WRITE_C)
80
THROW (Iex::ArgExc, "Cannot open file \"" << fileName << "\" "
81
"for writing. Tiled image files do not "
82
"support subsampled chroma channels.");
87
if (rgbaChannels & WRITE_R)
88
ch.insert ("R", Channel (HALF, 1, 1));
90
if (rgbaChannels & WRITE_G)
91
ch.insert ("G", Channel (HALF, 1, 1));
93
if (rgbaChannels & WRITE_B)
94
ch.insert ("B", Channel (HALF, 1, 1));
97
if (rgbaChannels & WRITE_A)
98
ch.insert ("A", Channel (HALF, 1, 1));
100
header.channels() = ch;
105
rgbaChannels (const ChannelList &ch, const string &channelNamePrefix = "")
109
if (ch.findChannel (channelNamePrefix + "R"))
112
if (ch.findChannel (channelNamePrefix + "G"))
115
if (ch.findChannel (channelNamePrefix + "B"))
118
if (ch.findChannel (channelNamePrefix + "A"))
121
if (ch.findChannel (channelNamePrefix + "Y"))
124
return RgbaChannels (i);
129
prefixFromLayerName (const string &layerName, const Header &header)
131
if (layerName.empty())
134
if (hasMultiView (header) && multiView(header)[0] == layerName)
137
return layerName + ".";
142
ywFromHeader (const Header &header)
146
if (hasChromaticities (header))
147
cr = chromaticities (header);
149
return computeYw (cr);
155
class TiledRgbaOutputFile::ToYa: public Mutex
159
ToYa (TiledOutputFile &outputFile, RgbaChannels rgbaChannels);
161
void setFrameBuffer (const Rgba *base,
165
void writeTile (int dx, int dy, int lx, int ly);
169
TiledOutputFile & _outputFile;
171
unsigned int _tileXSize;
172
unsigned int _tileYSize;
175
const Rgba * _fbBase;
181
TiledRgbaOutputFile::ToYa::ToYa (TiledOutputFile &outputFile,
182
RgbaChannels rgbaChannels)
184
_outputFile (outputFile)
186
_writeA = (rgbaChannels & WRITE_A)? true: false;
188
const TileDescription &td = outputFile.header().tileDescription();
190
_tileXSize = td.xSize;
191
_tileYSize = td.ySize;
192
_yw = ywFromHeader (_outputFile.header());
193
_buf.resizeErase (_tileYSize, _tileXSize);
201
TiledRgbaOutputFile::ToYa::setFrameBuffer (const Rgba *base,
206
_fbXStride = xStride;
207
_fbYStride = yStride;
212
TiledRgbaOutputFile::ToYa::writeTile (int dx, int dy, int lx, int ly)
216
THROW (Iex::ArgExc, "No frame buffer was specified as the "
217
"pixel data source for image file "
218
"\"" << _outputFile.fileName() << "\".");
222
// Copy the tile's RGBA pixels into _buf and convert
223
// them to luminance/alpha format
226
Box2i dw = _outputFile.dataWindowForTile (dx, dy, lx, ly);
227
int width = dw.max.x - dw.min.x + 1;
229
for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
231
for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
232
_buf[y1][x1] = _fbBase[x * _fbXStride + y * _fbYStride];
234
RGBAtoYCA (_yw, width, _writeA, _buf[y1], _buf[y1]);
238
// Store the contents of _buf in the output file
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
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
253
_outputFile.setFrameBuffer (fb);
254
_outputFile.writeTile (dx, dy, lx, ly);
258
TiledRgbaOutputFile::TiledRgbaOutputFile
260
const Header &header,
261
RgbaChannels rgbaChannels,
265
LevelRoundingMode rmode,
272
insertChannels (hd, rgbaChannels, name);
273
hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
274
_outputFile = new TiledOutputFile (name, hd, numThreads);
276
if (rgbaChannels & WRITE_Y)
277
_toYa = new ToYa (*_outputFile, rgbaChannels);
282
TiledRgbaOutputFile::TiledRgbaOutputFile
284
const Header &header,
285
RgbaChannels rgbaChannels,
289
LevelRoundingMode rmode,
296
insertChannels (hd, rgbaChannels, os.fileName());
297
hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
298
_outputFile = new TiledOutputFile (os, hd, numThreads);
300
if (rgbaChannels & WRITE_Y)
301
_toYa = new ToYa (*_outputFile, rgbaChannels);
306
TiledRgbaOutputFile::TiledRgbaOutputFile
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,
319
Compression compression,
325
Header hd (displayWindow,
326
dataWindow.isEmpty()? displayWindow: dataWindow,
333
insertChannels (hd, rgbaChannels, name);
334
hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
335
_outputFile = new TiledOutputFile (name, hd, numThreads);
337
if (rgbaChannels & WRITE_Y)
338
_toYa = new ToYa (*_outputFile, rgbaChannels);
342
TiledRgbaOutputFile::TiledRgbaOutputFile
349
LevelRoundingMode rmode,
350
RgbaChannels rgbaChannels,
351
float pixelAspectRatio,
352
const Imath::V2f screenWindowCenter,
353
float screenWindowWidth,
355
Compression compression,
369
insertChannels (hd, rgbaChannels, name);
370
hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
371
_outputFile = new TiledOutputFile (name, hd, numThreads);
373
if (rgbaChannels & WRITE_Y)
374
_toYa = new ToYa (*_outputFile, rgbaChannels);
378
TiledRgbaOutputFile::~TiledRgbaOutputFile ()
386
TiledRgbaOutputFile::setFrameBuffer (const Rgba *base,
393
_toYa->setFrameBuffer (base, xStride, yStride);
397
size_t xs = xStride * sizeof (Rgba);
398
size_t ys = yStride * sizeof (Rgba);
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));
407
_outputFile->setFrameBuffer (fb);
413
TiledRgbaOutputFile::header () const
415
return _outputFile->header();
420
TiledRgbaOutputFile::frameBuffer () const
422
return _outputFile->frameBuffer();
427
TiledRgbaOutputFile::displayWindow () const
429
return _outputFile->header().displayWindow();
434
TiledRgbaOutputFile::dataWindow () const
436
return _outputFile->header().dataWindow();
441
TiledRgbaOutputFile::pixelAspectRatio () const
443
return _outputFile->header().pixelAspectRatio();
448
TiledRgbaOutputFile::screenWindowCenter () const
450
return _outputFile->header().screenWindowCenter();
455
TiledRgbaOutputFile::screenWindowWidth () const
457
return _outputFile->header().screenWindowWidth();
462
TiledRgbaOutputFile::lineOrder () const
464
return _outputFile->header().lineOrder();
469
TiledRgbaOutputFile::compression () const
471
return _outputFile->header().compression();
476
TiledRgbaOutputFile::channels () const
478
return rgbaChannels (_outputFile->header().channels());
483
TiledRgbaOutputFile::tileXSize () const
485
return _outputFile->tileXSize();
490
TiledRgbaOutputFile::tileYSize () const
492
return _outputFile->tileYSize();
497
TiledRgbaOutputFile::levelMode () const
499
return _outputFile->levelMode();
504
TiledRgbaOutputFile::levelRoundingMode () const
506
return _outputFile->levelRoundingMode();
511
TiledRgbaOutputFile::numLevels () const
513
return _outputFile->numLevels();
518
TiledRgbaOutputFile::numXLevels () const
520
return _outputFile->numXLevels();
525
TiledRgbaOutputFile::numYLevels () const
527
return _outputFile->numYLevels();
532
TiledRgbaOutputFile::isValidLevel (int lx, int ly) const
534
return _outputFile->isValidLevel (lx, ly);
539
TiledRgbaOutputFile::levelWidth (int lx) const
541
return _outputFile->levelWidth (lx);
546
TiledRgbaOutputFile::levelHeight (int ly) const
548
return _outputFile->levelHeight (ly);
553
TiledRgbaOutputFile::numXTiles (int lx) const
555
return _outputFile->numXTiles (lx);
560
TiledRgbaOutputFile::numYTiles (int ly) const
562
return _outputFile->numYTiles (ly);
567
TiledRgbaOutputFile::dataWindowForLevel (int l) const
569
return _outputFile->dataWindowForLevel (l);
574
TiledRgbaOutputFile::dataWindowForLevel (int lx, int ly) const
576
return _outputFile->dataWindowForLevel (lx, ly);
581
TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int l) const
583
return _outputFile->dataWindowForTile (dx, dy, l);
588
TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
590
return _outputFile->dataWindowForTile (dx, dy, lx, ly);
595
TiledRgbaOutputFile::writeTile (int dx, int dy, int l)
600
_toYa->writeTile (dx, dy, l, l);
604
_outputFile->writeTile (dx, dy, l);
610
TiledRgbaOutputFile::writeTile (int dx, int dy, int lx, int ly)
615
_toYa->writeTile (dx, dy, lx, ly);
619
_outputFile->writeTile (dx, dy, lx, ly);
625
TiledRgbaOutputFile::writeTiles
626
(int dxMin, int dxMax, int dyMin, int dyMax, int lx, int ly)
632
for (int dy = dyMin; dy <= dyMax; dy++)
633
for (int dx = dxMin; dx <= dxMax; dx++)
634
_toYa->writeTile (dx, dy, lx, ly);
638
_outputFile->writeTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
643
TiledRgbaOutputFile::writeTiles
644
(int dxMin, int dxMax, int dyMin, int dyMax, int l)
646
writeTiles (dxMin, dxMax, dyMin, dyMax, l, l);
650
class TiledRgbaInputFile::FromYa: public Mutex
654
FromYa (TiledInputFile &inputFile);
656
void setFrameBuffer (Rgba *base,
659
const string &channelNamePrefix);
661
void readTile (int dx, int dy, int lx, int ly);
665
TiledInputFile & _inputFile;
666
unsigned int _tileXSize;
667
unsigned int _tileYSize;
676
TiledRgbaInputFile::FromYa::FromYa (TiledInputFile &inputFile)
678
_inputFile (inputFile)
680
const TileDescription &td = inputFile.header().tileDescription();
682
_tileXSize = td.xSize;
683
_tileYSize = td.ySize;
684
_yw = ywFromHeader (_inputFile.header());
685
_buf.resizeErase (_tileYSize, _tileXSize);
693
TiledRgbaInputFile::FromYa::setFrameBuffer (Rgba *base,
696
const string &channelNamePrefix)
702
fb.insert (channelNamePrefix + "Y",
704
(char *) &_buf[0][0].g, // base
705
sizeof (Rgba), // xStride
706
sizeof (Rgba) * _tileXSize, // yStride
709
true, true)); // tileCoordinates
711
fb.insert (channelNamePrefix + "A",
713
(char *) &_buf[0][0].a, // base
714
sizeof (Rgba), // xStride
715
sizeof (Rgba) * _tileXSize, // yStride
718
true, true)); // tileCoordinates
720
_inputFile.setFrameBuffer (fb);
724
_fbXStride = xStride;
725
_fbYStride = yStride;
730
TiledRgbaInputFile::FromYa::readTile (int dx, int dy, int lx, int ly)
734
THROW (Iex::ArgExc, "No frame buffer was specified as the "
735
"pixel data destination for image file "
736
"\"" << _inputFile.fileName() << "\".");
740
// Read the tile requested by the caller into _buf.
743
_inputFile.readTile (dx, dy, lx, ly);
746
// Convert the luminance/alpha pixels to RGBA
747
// and copy them into the caller's frame buffer.
750
Box2i dw = _inputFile.dataWindowForTile (dx, dy, lx, ly);
751
int width = dw.max.x - dw.min.x + 1;
753
for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
755
for (int x1 = 0; x1 < width; ++x1)
761
YCAtoRGBA (_yw, width, _buf[y1], _buf[y1]);
763
for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
765
_fbBase[x * _fbXStride + y * _fbYStride] = _buf[y1][x1];
771
TiledRgbaInputFile::TiledRgbaInputFile (const char name[], int numThreads):
772
_inputFile (new TiledInputFile (name, numThreads)),
774
_channelNamePrefix ("")
776
if (channels() & WRITE_Y)
777
_fromYa = new FromYa (*_inputFile);
781
TiledRgbaInputFile::TiledRgbaInputFile (IStream &is, int numThreads):
782
_inputFile (new TiledInputFile (is, numThreads)),
784
_channelNamePrefix ("")
786
if (channels() & WRITE_Y)
787
_fromYa = new FromYa (*_inputFile);
791
TiledRgbaInputFile::TiledRgbaInputFile (const char name[],
792
const string &layerName,
795
_inputFile (new TiledInputFile (name, numThreads)),
797
_channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
799
if (channels() & WRITE_Y)
800
_fromYa = new FromYa (*_inputFile);
804
TiledRgbaInputFile::TiledRgbaInputFile (IStream &is,
805
const string &layerName,
808
_inputFile (new TiledInputFile (is, numThreads)),
810
_channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
812
if (channels() & WRITE_Y)
813
_fromYa = new FromYa (*_inputFile);
817
TiledRgbaInputFile::~TiledRgbaInputFile ()
825
TiledRgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
829
Lock lock (*_fromYa);
830
_fromYa->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
834
size_t xs = xStride * sizeof (Rgba);
835
size_t ys = yStride * sizeof (Rgba);
839
fb.insert (_channelNamePrefix + "R",
843
1, 1, // xSampling, ySampling
846
fb.insert (_channelNamePrefix + "G",
850
1, 1, // xSampling, ySampling
853
fb.insert (_channelNamePrefix + "B",
857
1, 1, // xSampling, ySampling
860
fb.insert (_channelNamePrefix + "A",
864
1, 1, // xSampling, ySampling
867
_inputFile->setFrameBuffer (fb);
873
TiledRgbaInputFile::setLayerName (const std::string &layerName)
878
_channelNamePrefix = prefixFromLayerName (layerName, _inputFile->header());
880
if (channels() & WRITE_Y)
881
_fromYa = new FromYa (*_inputFile);
884
_inputFile->setFrameBuffer (fb);
889
TiledRgbaInputFile::header () const
891
return _inputFile->header();
896
TiledRgbaInputFile::fileName () const
898
return _inputFile->fileName();
903
TiledRgbaInputFile::frameBuffer () const
905
return _inputFile->frameBuffer();
910
TiledRgbaInputFile::displayWindow () const
912
return _inputFile->header().displayWindow();
917
TiledRgbaInputFile::dataWindow () const
919
return _inputFile->header().dataWindow();
924
TiledRgbaInputFile::pixelAspectRatio () const
926
return _inputFile->header().pixelAspectRatio();
931
TiledRgbaInputFile::screenWindowCenter () const
933
return _inputFile->header().screenWindowCenter();
938
TiledRgbaInputFile::screenWindowWidth () const
940
return _inputFile->header().screenWindowWidth();
945
TiledRgbaInputFile::lineOrder () const
947
return _inputFile->header().lineOrder();
952
TiledRgbaInputFile::compression () const
954
return _inputFile->header().compression();
959
TiledRgbaInputFile::channels () const
961
return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
966
TiledRgbaInputFile::version () const
968
return _inputFile->version();
973
TiledRgbaInputFile::isComplete () const
975
return _inputFile->isComplete();
980
TiledRgbaInputFile::tileXSize () const
982
return _inputFile->tileXSize();
987
TiledRgbaInputFile::tileYSize () const
989
return _inputFile->tileYSize();
994
TiledRgbaInputFile::levelMode () const
996
return _inputFile->levelMode();
1001
TiledRgbaInputFile::levelRoundingMode () const
1003
return _inputFile->levelRoundingMode();
1008
TiledRgbaInputFile::numLevels () const
1010
return _inputFile->numLevels();
1015
TiledRgbaInputFile::numXLevels () const
1017
return _inputFile->numXLevels();
1022
TiledRgbaInputFile::numYLevels () const
1024
return _inputFile->numYLevels();
1029
TiledRgbaInputFile::isValidLevel (int lx, int ly) const
1031
return _inputFile->isValidLevel (lx, ly);
1036
TiledRgbaInputFile::levelWidth (int lx) const
1038
return _inputFile->levelWidth (lx);
1043
TiledRgbaInputFile::levelHeight (int ly) const
1045
return _inputFile->levelHeight (ly);
1050
TiledRgbaInputFile::numXTiles (int lx) const
1052
return _inputFile->numXTiles(lx);
1057
TiledRgbaInputFile::numYTiles (int ly) const
1059
return _inputFile->numYTiles(ly);
1064
TiledRgbaInputFile::dataWindowForLevel (int l) const
1066
return _inputFile->dataWindowForLevel (l);
1071
TiledRgbaInputFile::dataWindowForLevel (int lx, int ly) const
1073
return _inputFile->dataWindowForLevel (lx, ly);
1078
TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int l) const
1080
return _inputFile->dataWindowForTile (dx, dy, l);
1085
TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
1087
return _inputFile->dataWindowForTile (dx, dy, lx, ly);
1092
TiledRgbaInputFile::readTile (int dx, int dy, int l)
1096
Lock lock (*_fromYa);
1097
_fromYa->readTile (dx, dy, l, l);
1101
_inputFile->readTile (dx, dy, l);
1107
TiledRgbaInputFile::readTile (int dx, int dy, int lx, int ly)
1111
Lock lock (*_fromYa);
1112
_fromYa->readTile (dx, dy, lx, ly);
1116
_inputFile->readTile (dx, dy, lx, ly);
1122
TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
1127
Lock lock (*_fromYa);
1129
for (int dy = dyMin; dy <= dyMax; dy++)
1130
for (int dx = dxMin; dx <= dxMax; dx++)
1131
_fromYa->readTile (dx, dy, lx, ly);
1135
_inputFile->readTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
1140
TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
1143
readTiles (dxMin, dxMax, dyMin, dyMax, l, l);
1148
TiledRgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
1150
_outputFile->updatePreviewImage (newPixels);
1155
TiledRgbaOutputFile::breakTile (int dx, int dy, int lx, int ly,
1156
int offset, int length, char c)
1158
_outputFile->breakTile (dx, dy, lx, ly, offset, length, c);