ImfTiledInputFile.cpp 40 KB

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