PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/3rdparty/openexr-1.7.0/ImfTiledInputFile.cpp

https://bitbucket.org/melbyruarus/pbrt
C++ | 1302 lines | 813 code | 259 blank | 230 comment | 83 complexity | 7727a6f1da00416ff90dd698e8463548 MD5 | raw file
  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. // class TiledInputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfTiledInputFile.h>
  40. #include <ImfTileDescriptionAttribute.h>
  41. #include <ImfChannelList.h>
  42. #include <ImfMisc.h>
  43. #include <ImfTiledMisc.h>
  44. #include <ImfStdIO.h>
  45. #include <ImfCompressor.h>
  46. #include "ImathBox.h"
  47. #include <ImfXdr.h>
  48. #include <ImfConvert.h>
  49. #include <ImfVersion.h>
  50. #include <ImfTileOffsets.h>
  51. #include <ImfThreading.h>
  52. #include "IlmThreadPool.h"
  53. #include "IlmThreadSemaphore.h"
  54. #include "IlmThreadMutex.h"
  55. #include "ImathVec.h"
  56. #include "Iex.h"
  57. #include <string>
  58. #include <vector>
  59. #include <algorithm>
  60. #include <assert.h>
  61. namespace Imf {
  62. using Imath::Box2i;
  63. using Imath::V2i;
  64. using std::string;
  65. using std::vector;
  66. using std::min;
  67. using std::max;
  68. using IlmThread::Mutex;
  69. using IlmThread::Lock;
  70. using IlmThread::Semaphore;
  71. using IlmThread::Task;
  72. using IlmThread::TaskGroup;
  73. using IlmThread::ThreadPool;
  74. namespace {
  75. struct TInSliceInfo
  76. {
  77. PixelType typeInFrameBuffer;
  78. PixelType typeInFile;
  79. char * base;
  80. size_t xStride;
  81. size_t yStride;
  82. bool fill;
  83. bool skip;
  84. double fillValue;
  85. int xTileCoords;
  86. int yTileCoords;
  87. TInSliceInfo (PixelType typeInFrameBuffer = HALF,
  88. PixelType typeInFile = HALF,
  89. char *base = 0,
  90. size_t xStride = 0,
  91. size_t yStride = 0,
  92. bool fill = false,
  93. bool skip = false,
  94. double fillValue = 0.0,
  95. int xTileCoords = 0,
  96. int yTileCoords = 0);
  97. };
  98. TInSliceInfo::TInSliceInfo (PixelType tifb,
  99. PixelType tifl,
  100. char *b,
  101. size_t xs, size_t ys,
  102. bool f, bool s,
  103. double fv,
  104. int xtc,
  105. int ytc)
  106. :
  107. typeInFrameBuffer (tifb),
  108. typeInFile (tifl),
  109. base (b),
  110. xStride (xs),
  111. yStride (ys),
  112. fill (f),
  113. skip (s),
  114. fillValue (fv),
  115. xTileCoords (xtc),
  116. yTileCoords (ytc)
  117. {
  118. // empty
  119. }
  120. struct TileBuffer
  121. {
  122. const char * uncompressedData;
  123. char * buffer;
  124. int dataSize;
  125. Compressor * compressor;
  126. Compressor::Format format;
  127. int dx;
  128. int dy;
  129. int lx;
  130. int ly;
  131. bool hasException;
  132. string exception;
  133. TileBuffer (Compressor * const comp);
  134. ~TileBuffer ();
  135. inline void wait () {_sem.wait();}
  136. inline void post () {_sem.post();}
  137. protected:
  138. Semaphore _sem;
  139. };
  140. TileBuffer::TileBuffer (Compressor *comp):
  141. uncompressedData (0),
  142. dataSize (0),
  143. compressor (comp),
  144. format (defaultFormat (compressor)),
  145. dx (-1),
  146. dy (-1),
  147. lx (-1),
  148. ly (-1),
  149. hasException (false),
  150. exception (),
  151. _sem (1)
  152. {
  153. // empty
  154. }
  155. TileBuffer::~TileBuffer ()
  156. {
  157. delete compressor;
  158. }
  159. } // namespace
  160. //
  161. // struct TiledInputFile::Data stores things that will be
  162. // needed between calls to readTile()
  163. //
  164. struct TiledInputFile::Data: public Mutex
  165. {
  166. Header header; // the image header
  167. TileDescription tileDesc; // describes the tile layout
  168. int version; // file's version
  169. FrameBuffer frameBuffer; // framebuffer to write into
  170. LineOrder lineOrder; // the file's lineorder
  171. int minX; // data window's min x coord
  172. int maxX; // data window's max x coord
  173. int minY; // data window's min y coord
  174. int maxY; // data window's max x coord
  175. int numXLevels; // number of x levels
  176. int numYLevels; // number of y levels
  177. int * numXTiles; // number of x tiles at a level
  178. int * numYTiles; // number of y tiles at a level
  179. TileOffsets tileOffsets; // stores offsets in file for
  180. // each tile
  181. bool fileIsComplete; // True if no tiles are missing
  182. // in the file
  183. Int64 currentPosition; // file offset for current tile,
  184. // used to prevent unnecessary
  185. // seeking
  186. vector<TInSliceInfo> slices; // info about channels in file
  187. IStream * is; // file stream to read from
  188. bool deleteStream; // should we delete the stream
  189. // ourselves? or does someone
  190. // else do it?
  191. size_t bytesPerPixel; // size of an uncompressed pixel
  192. size_t maxBytesPerTileLine; // combined size of a line
  193. // over all channels
  194. vector<TileBuffer*> tileBuffers; // each holds a single tile
  195. size_t tileBufferSize; // size of the tile buffers
  196. Data (bool deleteStream, int numThreads);
  197. ~Data ();
  198. inline TileBuffer * getTileBuffer (int number);
  199. // hash function from tile indices
  200. // into our vector of tile buffers
  201. };
  202. TiledInputFile::Data::Data (bool del, int numThreads):
  203. numXTiles (0),
  204. numYTiles (0),
  205. is (0),
  206. deleteStream (del)
  207. {
  208. //
  209. // We need at least one tileBuffer, but if threading is used,
  210. // to keep n threads busy we need 2*n tileBuffers
  211. //
  212. tileBuffers.resize (max (1, 2 * numThreads));
  213. }
  214. TiledInputFile::Data::~Data ()
  215. {
  216. delete [] numXTiles;
  217. delete [] numYTiles;
  218. if (deleteStream)
  219. delete is;
  220. for (size_t i = 0; i < tileBuffers.size(); i++)
  221. delete tileBuffers[i];
  222. }
  223. TileBuffer*
  224. TiledInputFile::Data::getTileBuffer (int number)
  225. {
  226. return tileBuffers[number % tileBuffers.size()];
  227. }
  228. namespace {
  229. void
  230. readTileData (TiledInputFile::Data *ifd,
  231. int dx, int dy,
  232. int lx, int ly,
  233. char *&buffer,
  234. int &dataSize)
  235. {
  236. //
  237. // Read a single tile block from the file and into the array pointed
  238. // to by buffer. If the file is memory-mapped, then we change where
  239. // buffer points instead of writing into the array (hence buffer needs
  240. // to be a reference to a char *).
  241. //
  242. //
  243. // Look up the location for this tile in the Index and
  244. // seek to that position if necessary
  245. //
  246. Int64 tileOffset = ifd->tileOffsets (dx, dy, lx, ly);
  247. if (tileOffset == 0)
  248. {
  249. THROW (Iex::InputExc, "Tile (" << dx << ", " << dy << ", " <<
  250. lx << ", " << ly << ") is missing.");
  251. }
  252. if (ifd->currentPosition != tileOffset)
  253. ifd->is->seekg (tileOffset);
  254. //
  255. // Read the first few bytes of the tile (the header).
  256. // Verify that the tile coordinates and the level number
  257. // are correct.
  258. //
  259. int tileXCoord, tileYCoord, levelX, levelY;
  260. Xdr::read <StreamIO> (*ifd->is, tileXCoord);
  261. Xdr::read <StreamIO> (*ifd->is, tileYCoord);
  262. Xdr::read <StreamIO> (*ifd->is, levelX);
  263. Xdr::read <StreamIO> (*ifd->is, levelY);
  264. Xdr::read <StreamIO> (*ifd->is, dataSize);
  265. if (tileXCoord != dx)
  266. throw Iex::InputExc ("Unexpected tile x coordinate.");
  267. if (tileYCoord != dy)
  268. throw Iex::InputExc ("Unexpected tile y coordinate.");
  269. if (levelX != lx)
  270. throw Iex::InputExc ("Unexpected tile x level number coordinate.");
  271. if (levelY != ly)
  272. throw Iex::InputExc ("Unexpected tile y level number coordinate.");
  273. if (dataSize > (int) ifd->tileBufferSize)
  274. throw Iex::InputExc ("Unexpected tile block length.");
  275. //
  276. // Read the pixel data.
  277. //
  278. if (ifd->is->isMemoryMapped ())
  279. buffer = ifd->is->readMemoryMapped (dataSize);
  280. else
  281. ifd->is->read (buffer, dataSize);
  282. //
  283. // Keep track of which tile is the next one in
  284. // the file, so that we can avoid redundant seekg()
  285. // operations (seekg() can be fairly expensive).
  286. //
  287. ifd->currentPosition = tileOffset + 5 * Xdr::size<int>() + dataSize;
  288. }
  289. void
  290. readNextTileData (TiledInputFile::Data *ifd,
  291. int &dx, int &dy,
  292. int &lx, int &ly,
  293. char * & buffer,
  294. int &dataSize)
  295. {
  296. //
  297. // Read the next tile block from the file
  298. //
  299. //
  300. // Read the first few bytes of the tile (the header).
  301. //
  302. Xdr::read <StreamIO> (*ifd->is, dx);
  303. Xdr::read <StreamIO> (*ifd->is, dy);
  304. Xdr::read <StreamIO> (*ifd->is, lx);
  305. Xdr::read <StreamIO> (*ifd->is, ly);
  306. Xdr::read <StreamIO> (*ifd->is, dataSize);
  307. if (dataSize > (int) ifd->tileBufferSize)
  308. throw Iex::InputExc ("Unexpected tile block length.");
  309. //
  310. // Read the pixel data.
  311. //
  312. ifd->is->read (buffer, dataSize);
  313. //
  314. // Keep track of which tile is the next one in
  315. // the file, so that we can avoid redundant seekg()
  316. // operations (seekg() can be fairly expensive).
  317. //
  318. ifd->currentPosition += 5 * Xdr::size<int>() + dataSize;
  319. }
  320. //
  321. // A TileBufferTask encapsulates the task of uncompressing
  322. // a single tile and copying it into the frame buffer.
  323. //
  324. class TileBufferTask : public Task
  325. {
  326. public:
  327. TileBufferTask (TaskGroup *group,
  328. TiledInputFile::Data *ifd,
  329. TileBuffer *tileBuffer);
  330. virtual ~TileBufferTask ();
  331. virtual void execute ();
  332. private:
  333. TiledInputFile::Data * _ifd;
  334. TileBuffer * _tileBuffer;
  335. };
  336. TileBufferTask::TileBufferTask
  337. (TaskGroup *group,
  338. TiledInputFile::Data *ifd,
  339. TileBuffer *tileBuffer)
  340. :
  341. Task (group),
  342. _ifd (ifd),
  343. _tileBuffer (tileBuffer)
  344. {
  345. // empty
  346. }
  347. TileBufferTask::~TileBufferTask ()
  348. {
  349. //
  350. // Signal that the tile buffer is now free
  351. //
  352. _tileBuffer->post ();
  353. }
  354. void
  355. TileBufferTask::execute ()
  356. {
  357. try
  358. {
  359. //
  360. // Calculate information about the tile
  361. //
  362. Box2i tileRange = Imf::dataWindowForTile (_ifd->tileDesc,
  363. _ifd->minX, _ifd->maxX,
  364. _ifd->minY, _ifd->maxY,
  365. _tileBuffer->dx,
  366. _tileBuffer->dy,
  367. _tileBuffer->lx,
  368. _tileBuffer->ly);
  369. int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1;
  370. int numPixelsInTile = numPixelsPerScanLine *
  371. (tileRange.max.y - tileRange.min.y + 1);
  372. int sizeOfTile = _ifd->bytesPerPixel * numPixelsInTile;
  373. //
  374. // Uncompress the data, if necessary
  375. //
  376. if (_tileBuffer->compressor && _tileBuffer->dataSize < sizeOfTile)
  377. {
  378. _tileBuffer->format = _tileBuffer->compressor->format();
  379. _tileBuffer->dataSize = _tileBuffer->compressor->uncompressTile
  380. (_tileBuffer->buffer, _tileBuffer->dataSize,
  381. tileRange, _tileBuffer->uncompressedData);
  382. }
  383. else
  384. {
  385. //
  386. // If the line is uncompressed, it's in XDR format,
  387. // regardless of the compressor's output format.
  388. //
  389. _tileBuffer->format = Compressor::XDR;
  390. _tileBuffer->uncompressedData = _tileBuffer->buffer;
  391. }
  392. //
  393. // Convert the tile of pixel data back from the machine-independent
  394. // representation, and store the result in the frame buffer.
  395. //
  396. const char *readPtr = _tileBuffer->uncompressedData;
  397. // points to where we
  398. // read from in the
  399. // tile block
  400. //
  401. // Iterate over the scan lines in the tile.
  402. //
  403. for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
  404. {
  405. //
  406. // Iterate over all image channels.
  407. //
  408. for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
  409. {
  410. const TInSliceInfo &slice = _ifd->slices[i];
  411. //
  412. // These offsets are used to facilitate both
  413. // absolute and tile-relative pixel coordinates.
  414. //
  415. int xOffset = slice.xTileCoords * tileRange.min.x;
  416. int yOffset = slice.yTileCoords * tileRange.min.y;
  417. //
  418. // Fill the frame buffer with pixel data.
  419. //
  420. if (slice.skip)
  421. {
  422. //
  423. // The file contains data for this channel, but
  424. // the frame buffer contains no slice for this channel.
  425. //
  426. skipChannel (readPtr, slice.typeInFile,
  427. numPixelsPerScanLine);
  428. }
  429. else
  430. {
  431. //
  432. // The frame buffer contains a slice for this channel.
  433. //
  434. char *writePtr = slice.base +
  435. (y - yOffset) * slice.yStride +
  436. (tileRange.min.x - xOffset) *
  437. slice.xStride;
  438. char *endPtr = writePtr +
  439. (numPixelsPerScanLine - 1) * slice.xStride;
  440. copyIntoFrameBuffer (readPtr, writePtr, endPtr,
  441. slice.xStride,
  442. slice.fill, slice.fillValue,
  443. _tileBuffer->format,
  444. slice.typeInFrameBuffer,
  445. slice.typeInFile);
  446. }
  447. }
  448. }
  449. }
  450. catch (std::exception &e)
  451. {
  452. if (!_tileBuffer->hasException)
  453. {
  454. _tileBuffer->exception = e.what ();
  455. _tileBuffer->hasException = true;
  456. }
  457. }
  458. catch (...)
  459. {
  460. if (!_tileBuffer->hasException)
  461. {
  462. _tileBuffer->exception = "unrecognized exception";
  463. _tileBuffer->hasException = true;
  464. }
  465. }
  466. }
  467. TileBufferTask *
  468. newTileBufferTask
  469. (TaskGroup *group,
  470. TiledInputFile::Data *ifd,
  471. int number,
  472. int dx, int dy,
  473. int lx, int ly)
  474. {
  475. //
  476. // Wait for a tile buffer to become available,
  477. // fill the buffer with raw data from the file,
  478. // and create a new TileBufferTask whose execute()
  479. // method will uncompress the tile and copy the
  480. // tile's pixels into the frame buffer.
  481. //
  482. TileBuffer *tileBuffer = ifd->getTileBuffer (number);
  483. try
  484. {
  485. tileBuffer->wait();
  486. tileBuffer->dx = dx;
  487. tileBuffer->dy = dy;
  488. tileBuffer->lx = lx;
  489. tileBuffer->ly = ly;
  490. tileBuffer->uncompressedData = 0;
  491. readTileData (ifd, dx, dy, lx, ly,
  492. tileBuffer->buffer,
  493. tileBuffer->dataSize);
  494. }
  495. catch (...)
  496. {
  497. //
  498. // Reading from the file caused an exception.
  499. // Signal that the tile buffer is free, and
  500. // re-throw the exception.
  501. //
  502. tileBuffer->post();
  503. throw;
  504. }
  505. return new TileBufferTask (group, ifd, tileBuffer);
  506. }
  507. } // namespace
  508. TiledInputFile::TiledInputFile (const char fileName[], int numThreads):
  509. _data (new Data (true, numThreads))
  510. {
  511. //
  512. // This constructor is called when a user
  513. // explicitly wants to read a tiled file.
  514. //
  515. try
  516. {
  517. _data->is = new StdIFStream (fileName);
  518. _data->header.readFrom (*_data->is, _data->version);
  519. initialize();
  520. }
  521. catch (Iex::BaseExc &e)
  522. {
  523. delete _data;
  524. REPLACE_EXC (e, "Cannot open image file "
  525. "\"" << fileName << "\". " << e);
  526. throw;
  527. }
  528. catch (...)
  529. {
  530. delete _data;
  531. throw;
  532. }
  533. }
  534. TiledInputFile::TiledInputFile (IStream &is, int numThreads):
  535. _data (new Data (false, numThreads))
  536. {
  537. //
  538. // This constructor is called when a user
  539. // explicitly wants to read a tiled file.
  540. //
  541. try
  542. {
  543. _data->is = &is;
  544. _data->header.readFrom (*_data->is, _data->version);
  545. initialize();
  546. }
  547. catch (Iex::BaseExc &e)
  548. {
  549. delete _data;
  550. REPLACE_EXC (e, "Cannot open image file "
  551. "\"" << is.fileName() << "\". " << e);
  552. throw;
  553. }
  554. catch (...)
  555. {
  556. delete _data;
  557. throw;
  558. }
  559. }
  560. TiledInputFile::TiledInputFile
  561. (const Header &header,
  562. IStream *is,
  563. int version,
  564. int numThreads)
  565. :
  566. _data (new Data (false, numThreads))
  567. {
  568. //
  569. // This constructor called by class Imf::InputFile
  570. // when a user wants to just read an image file, and
  571. // doesn't care or know if the file is tiled.
  572. //
  573. _data->is = is;
  574. _data->header = header;
  575. _data->version = version;
  576. initialize();
  577. }
  578. void
  579. TiledInputFile::initialize ()
  580. {
  581. if (!isTiled (_data->version))
  582. throw Iex::ArgExc ("Expected a tiled file but the file is not tiled.");
  583. _data->header.sanityCheck (true);
  584. _data->tileDesc = _data->header.tileDescription();
  585. _data->lineOrder = _data->header.lineOrder();
  586. //
  587. // Save the dataWindow information
  588. //
  589. const Box2i &dataWindow = _data->header.dataWindow();
  590. _data->minX = dataWindow.min.x;
  591. _data->maxX = dataWindow.max.x;
  592. _data->minY = dataWindow.min.y;
  593. _data->maxY = dataWindow.max.y;
  594. //
  595. // Precompute level and tile information to speed up utility functions
  596. //
  597. precalculateTileInfo (_data->tileDesc,
  598. _data->minX, _data->maxX,
  599. _data->minY, _data->maxY,
  600. _data->numXTiles, _data->numYTiles,
  601. _data->numXLevels, _data->numYLevels);
  602. _data->bytesPerPixel = calculateBytesPerPixel (_data->header);
  603. _data->maxBytesPerTileLine = _data->bytesPerPixel * _data->tileDesc.xSize;
  604. _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize;
  605. //
  606. // Create all the TileBuffers and allocate their internal buffers
  607. //
  608. for (size_t i = 0; i < _data->tileBuffers.size(); i++)
  609. {
  610. _data->tileBuffers[i] = new TileBuffer (newTileCompressor
  611. (_data->header.compression(),
  612. _data->maxBytesPerTileLine,
  613. _data->tileDesc.ySize,
  614. _data->header));
  615. if (!_data->is->isMemoryMapped ())
  616. _data->tileBuffers[i]->buffer = new char [_data->tileBufferSize];
  617. }
  618. _data->tileOffsets = TileOffsets (_data->tileDesc.mode,
  619. _data->numXLevels,
  620. _data->numYLevels,
  621. _data->numXTiles,
  622. _data->numYTiles);
  623. _data->tileOffsets.readFrom (*(_data->is), _data->fileIsComplete);
  624. _data->currentPosition = _data->is->tellg();
  625. }
  626. TiledInputFile::~TiledInputFile ()
  627. {
  628. if (!_data->is->isMemoryMapped())
  629. for (size_t i = 0; i < _data->tileBuffers.size(); i++)
  630. delete [] _data->tileBuffers[i]->buffer;
  631. delete _data;
  632. }
  633. const char *
  634. TiledInputFile::fileName () const
  635. {
  636. return _data->is->fileName();
  637. }
  638. const Header &
  639. TiledInputFile::header () const
  640. {
  641. return _data->header;
  642. }
  643. int
  644. TiledInputFile::version () const
  645. {
  646. return _data->version;
  647. }
  648. void
  649. TiledInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
  650. {
  651. Lock lock (*_data);
  652. //
  653. // Set the frame buffer
  654. //
  655. //
  656. // Check if the new frame buffer descriptor is
  657. // compatible with the image file header.
  658. //
  659. const ChannelList &channels = _data->header.channels();
  660. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  661. j != frameBuffer.end();
  662. ++j)
  663. {
  664. ChannelList::ConstIterator i = channels.find (j.name());
  665. if (i == channels.end())
  666. continue;
  667. if (i.channel().xSampling != j.slice().xSampling ||
  668. i.channel().ySampling != j.slice().ySampling)
  669. THROW (Iex::ArgExc, "X and/or y subsampling factors "
  670. "of \"" << i.name() << "\" channel "
  671. "of input file \"" << fileName() << "\" are "
  672. "not compatible with the frame buffer's "
  673. "subsampling factors.");
  674. }
  675. //
  676. // Initialize the slice table for readPixels().
  677. //
  678. vector<TInSliceInfo> slices;
  679. ChannelList::ConstIterator i = channels.begin();
  680. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  681. j != frameBuffer.end();
  682. ++j)
  683. {
  684. while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
  685. {
  686. //
  687. // Channel i is present in the file but not
  688. // in the frame buffer; data for channel i
  689. // will be skipped during readPixels().
  690. //
  691. slices.push_back (TInSliceInfo (i.channel().type,
  692. i.channel().type,
  693. 0, // base
  694. 0, // xStride
  695. 0, // yStride
  696. false, // fill
  697. true, // skip
  698. 0.0)); // fillValue
  699. ++i;
  700. }
  701. bool fill = false;
  702. if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
  703. {
  704. //
  705. // Channel i is present in the frame buffer, but not in the file.
  706. // In the frame buffer, slice j will be filled with a default value.
  707. //
  708. fill = true;
  709. }
  710. slices.push_back (TInSliceInfo (j.slice().type,
  711. fill? j.slice().type: i.channel().type,
  712. j.slice().base,
  713. j.slice().xStride,
  714. j.slice().yStride,
  715. fill,
  716. false, // skip
  717. j.slice().fillValue,
  718. (j.slice().xTileCoords)? 1: 0,
  719. (j.slice().yTileCoords)? 1: 0));
  720. if (i != channels.end() && !fill)
  721. ++i;
  722. }
  723. while (i != channels.end())
  724. {
  725. //
  726. // Channel i is present in the file but not
  727. // in the frame buffer; data for channel i
  728. // will be skipped during readPixels().
  729. //
  730. slices.push_back (TInSliceInfo (i.channel().type,
  731. i.channel().type,
  732. 0, // base
  733. 0, // xStride
  734. 0, // yStride
  735. false, // fill
  736. true, // skip
  737. 0.0)); // fillValue
  738. ++i;
  739. }
  740. //
  741. // Store the new frame buffer.
  742. //
  743. _data->frameBuffer = frameBuffer;
  744. _data->slices = slices;
  745. }
  746. const FrameBuffer &
  747. TiledInputFile::frameBuffer () const
  748. {
  749. Lock lock (*_data);
  750. return _data->frameBuffer;
  751. }
  752. bool
  753. TiledInputFile::isComplete () const
  754. {
  755. return _data->fileIsComplete;
  756. }
  757. void
  758. TiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int lx, int ly)
  759. {
  760. //
  761. // Read a range of tiles from the file into the framebuffer
  762. //
  763. try
  764. {
  765. Lock lock (*_data);
  766. if (_data->slices.size() == 0)
  767. throw Iex::ArgExc ("No frame buffer specified "
  768. "as pixel data destination.");
  769. //
  770. // Determine the first and last tile coordinates in both dimensions.
  771. // We always attempt to read the range of tiles in the order that
  772. // they are stored in the file.
  773. //
  774. if (dx1 > dx2)
  775. std::swap (dx1, dx2);
  776. if (dy1 > dy2)
  777. std::swap (dy1, dy2);
  778. int dyStart = dy1;
  779. int dyStop = dy2 + 1;
  780. int dY = 1;
  781. if (_data->lineOrder == DECREASING_Y)
  782. {
  783. dyStart = dy2;
  784. dyStop = dy1 - 1;
  785. dY = -1;
  786. }
  787. //
  788. // Create a task group for all tile buffer tasks. When the
  789. // task group goes out of scope, the destructor waits until
  790. // all tasks are complete.
  791. //
  792. {
  793. TaskGroup taskGroup;
  794. int tileNumber = 0;
  795. for (int dy = dyStart; dy != dyStop; dy += dY)
  796. {
  797. for (int dx = dx1; dx <= dx2; dx++)
  798. {
  799. if (!isValidTile (dx, dy, lx, ly))
  800. THROW (Iex::ArgExc,
  801. "Tile (" << dx << ", " << dy << ", " <<
  802. lx << "," << ly << ") is not a valid tile.");
  803. ThreadPool::addGlobalTask (newTileBufferTask (&taskGroup,
  804. _data,
  805. tileNumber++,
  806. dx, dy,
  807. lx, ly));
  808. }
  809. }
  810. //
  811. // finish all tasks
  812. //
  813. }
  814. //
  815. // Exeption handling:
  816. //
  817. // TileBufferTask::execute() may have encountered exceptions, but
  818. // those exceptions occurred in another thread, not in the thread
  819. // that is executing this call to TiledInputFile::readTiles().
  820. // TileBufferTask::execute() has caught all exceptions and stored
  821. // the exceptions' what() strings in the tile buffers.
  822. // Now we check if any tile buffer contains a stored exception; if
  823. // this is the case then we re-throw the exception in this thread.
  824. // (It is possible that multiple tile buffers contain stored
  825. // exceptions. We re-throw the first exception we find and
  826. // ignore all others.)
  827. //
  828. const string *exception = 0;
  829. for (int i = 0; i < _data->tileBuffers.size(); ++i)
  830. {
  831. TileBuffer *tileBuffer = _data->tileBuffers[i];
  832. if (tileBuffer->hasException && !exception)
  833. exception = &tileBuffer->exception;
  834. tileBuffer->hasException = false;
  835. }
  836. if (exception)
  837. throw Iex::IoExc (*exception);
  838. }
  839. catch (Iex::BaseExc &e)
  840. {
  841. REPLACE_EXC (e, "Error reading pixel data from image "
  842. "file \"" << fileName() << "\". " << e);
  843. throw;
  844. }
  845. }
  846. void
  847. TiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int l)
  848. {
  849. readTiles (dx1, dx2, dy1, dy2, l, l);
  850. }
  851. void
  852. TiledInputFile::readTile (int dx, int dy, int lx, int ly)
  853. {
  854. readTiles (dx, dx, dy, dy, lx, ly);
  855. }
  856. void
  857. TiledInputFile::readTile (int dx, int dy, int l)
  858. {
  859. readTile (dx, dy, l, l);
  860. }
  861. void
  862. TiledInputFile::rawTileData (int &dx, int &dy,
  863. int &lx, int &ly,
  864. const char *&pixelData,
  865. int &pixelDataSize)
  866. {
  867. try
  868. {
  869. Lock lock (*_data);
  870. if (!isValidTile (dx, dy, lx, ly))
  871. throw Iex::ArgExc ("Tried to read a tile outside "
  872. "the image file's data window.");
  873. TileBuffer *tileBuffer = _data->getTileBuffer (0);
  874. readNextTileData (_data, dx, dy, lx, ly,
  875. tileBuffer->buffer,
  876. pixelDataSize);
  877. pixelData = tileBuffer->buffer;
  878. }
  879. catch (Iex::BaseExc &e)
  880. {
  881. REPLACE_EXC (e, "Error reading pixel data from image "
  882. "file \"" << fileName() << "\". " << e);
  883. throw;
  884. }
  885. }
  886. unsigned int
  887. TiledInputFile::tileXSize () const
  888. {
  889. return _data->tileDesc.xSize;
  890. }
  891. unsigned int
  892. TiledInputFile::tileYSize () const
  893. {
  894. return _data->tileDesc.ySize;
  895. }
  896. LevelMode
  897. TiledInputFile::levelMode () const
  898. {
  899. return _data->tileDesc.mode;
  900. }
  901. LevelRoundingMode
  902. TiledInputFile::levelRoundingMode () const
  903. {
  904. return _data->tileDesc.roundingMode;
  905. }
  906. int
  907. TiledInputFile::numLevels () const
  908. {
  909. if (levelMode() == RIPMAP_LEVELS)
  910. THROW (Iex::LogicExc, "Error calling numLevels() on image "
  911. "file \"" << fileName() << "\" "
  912. "(numLevels() is not defined for files "
  913. "with RIPMAP level mode).");
  914. return _data->numXLevels;
  915. }
  916. int
  917. TiledInputFile::numXLevels () const
  918. {
  919. return _data->numXLevels;
  920. }
  921. int
  922. TiledInputFile::numYLevels () const
  923. {
  924. return _data->numYLevels;
  925. }
  926. bool
  927. TiledInputFile::isValidLevel (int lx, int ly) const
  928. {
  929. if (lx < 0 || ly < 0)
  930. return false;
  931. if (levelMode() == MIPMAP_LEVELS && lx != ly)
  932. return false;
  933. if (lx >= numXLevels() || ly >= numYLevels())
  934. return false;
  935. return true;
  936. }
  937. int
  938. TiledInputFile::levelWidth (int lx) const
  939. {
  940. try
  941. {
  942. return levelSize (_data->minX, _data->maxX, lx,
  943. _data->tileDesc.roundingMode);
  944. }
  945. catch (Iex::BaseExc &e)
  946. {
  947. REPLACE_EXC (e, "Error calling levelWidth() on image "
  948. "file \"" << fileName() << "\". " << e);
  949. throw;
  950. }
  951. }
  952. int
  953. TiledInputFile::levelHeight (int ly) const
  954. {
  955. try
  956. {
  957. return levelSize (_data->minY, _data->maxY, ly,
  958. _data->tileDesc.roundingMode);
  959. }
  960. catch (Iex::BaseExc &e)
  961. {
  962. REPLACE_EXC (e, "Error calling levelHeight() on image "
  963. "file \"" << fileName() << "\". " << e);
  964. throw;
  965. }
  966. }
  967. int
  968. TiledInputFile::numXTiles (int lx) const
  969. {
  970. if (lx < 0 || lx >= _data->numXLevels)
  971. {
  972. THROW (Iex::ArgExc, "Error calling numXTiles() on image "
  973. "file \"" << _data->is->fileName() << "\" "
  974. "(Argument is not in valid range).");
  975. }
  976. return _data->numXTiles[lx];
  977. }
  978. int
  979. TiledInputFile::numYTiles (int ly) const
  980. {
  981. if (ly < 0 || ly >= _data->numYLevels)
  982. {
  983. THROW (Iex::ArgExc, "Error calling numYTiles() on image "
  984. "file \"" << _data->is->fileName() << "\" "
  985. "(Argument is not in valid range).");
  986. }
  987. return _data->numYTiles[ly];
  988. }
  989. Box2i
  990. TiledInputFile::dataWindowForLevel (int l) const
  991. {
  992. return dataWindowForLevel (l, l);
  993. }
  994. Box2i
  995. TiledInputFile::dataWindowForLevel (int lx, int ly) const
  996. {
  997. try
  998. {
  999. return Imf::dataWindowForLevel (_data->tileDesc,
  1000. _data->minX, _data->maxX,
  1001. _data->minY, _data->maxY,
  1002. lx, ly);
  1003. }
  1004. catch (Iex::BaseExc &e)
  1005. {
  1006. REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
  1007. "file \"" << fileName() << "\". " << e);
  1008. throw;
  1009. }
  1010. }
  1011. Box2i
  1012. TiledInputFile::dataWindowForTile (int dx, int dy, int l) const
  1013. {
  1014. return dataWindowForTile (dx, dy, l, l);
  1015. }
  1016. Box2i
  1017. TiledInputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
  1018. {
  1019. try
  1020. {
  1021. if (!isValidTile (dx, dy, lx, ly))
  1022. throw Iex::ArgExc ("Arguments not in valid range.");
  1023. return Imf::dataWindowForTile (_data->tileDesc,
  1024. _data->minX, _data->maxX,
  1025. _data->minY, _data->maxY,
  1026. dx, dy, lx, ly);
  1027. }
  1028. catch (Iex::BaseExc &e)
  1029. {
  1030. REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
  1031. "file \"" << fileName() << "\". " << e);
  1032. throw;
  1033. }
  1034. }
  1035. bool
  1036. TiledInputFile::isValidTile (int dx, int dy, int lx, int ly) const
  1037. {
  1038. return ((lx < _data->numXLevels && lx >= 0) &&
  1039. (ly < _data->numYLevels && ly >= 0) &&
  1040. (dx < _data->numXTiles[lx] && dx >= 0) &&
  1041. (dy < _data->numYTiles[ly] && dy >= 0));
  1042. }
  1043. } // namespace Imf