PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/melbyruarus/pbrt
C++ | 1021 lines | 632 code | 185 blank | 204 comment | 71 complexity | 223a169400d1729ee294f31727e100e8 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 ScanLineInputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfScanLineInputFile.h>
  40. #include <ImfChannelList.h>
  41. #include <ImfMisc.h>
  42. #include <ImfStdIO.h>
  43. #include <ImfCompressor.h>
  44. #include "ImathBox.h"
  45. #include "ImathFun.h"
  46. #include <ImfXdr.h>
  47. #include <ImfConvert.h>
  48. #include <ImfThreading.h>
  49. #include "IlmThreadPool.h"
  50. #include "IlmThreadSemaphore.h"
  51. #include "IlmThreadMutex.h"
  52. #include "Iex.h"
  53. #include <string>
  54. #include <vector>
  55. #include <assert.h>
  56. namespace Imf {
  57. using Imath::Box2i;
  58. using Imath::divp;
  59. using Imath::modp;
  60. using std::string;
  61. using std::vector;
  62. using std::ifstream;
  63. using std::min;
  64. using std::max;
  65. using IlmThread::Mutex;
  66. using IlmThread::Lock;
  67. using IlmThread::Semaphore;
  68. using IlmThread::Task;
  69. using IlmThread::TaskGroup;
  70. using IlmThread::ThreadPool;
  71. namespace {
  72. struct InSliceInfo
  73. {
  74. PixelType typeInFrameBuffer;
  75. PixelType typeInFile;
  76. char * base;
  77. size_t xStride;
  78. size_t yStride;
  79. int xSampling;
  80. int ySampling;
  81. bool fill;
  82. bool skip;
  83. double fillValue;
  84. InSliceInfo (PixelType typeInFrameBuffer = HALF,
  85. PixelType typeInFile = HALF,
  86. char *base = 0,
  87. size_t xStride = 0,
  88. size_t yStride = 0,
  89. int xSampling = 1,
  90. int ySampling = 1,
  91. bool fill = false,
  92. bool skip = false,
  93. double fillValue = 0.0);
  94. };
  95. InSliceInfo::InSliceInfo (PixelType tifb,
  96. PixelType tifl,
  97. char *b,
  98. size_t xs, size_t ys,
  99. int xsm, int ysm,
  100. bool f, bool s,
  101. double fv)
  102. :
  103. typeInFrameBuffer (tifb),
  104. typeInFile (tifl),
  105. base (b),
  106. xStride (xs),
  107. yStride (ys),
  108. xSampling (xsm),
  109. ySampling (ysm),
  110. fill (f),
  111. skip (s),
  112. fillValue (fv)
  113. {
  114. // empty
  115. }
  116. struct LineBuffer
  117. {
  118. const char * uncompressedData;
  119. char * buffer;
  120. int dataSize;
  121. int minY;
  122. int maxY;
  123. Compressor * compressor;
  124. Compressor::Format format;
  125. int number;
  126. bool hasException;
  127. string exception;
  128. LineBuffer (Compressor * const comp);
  129. ~LineBuffer ();
  130. inline void wait () {_sem.wait();}
  131. inline void post () {_sem.post();}
  132. private:
  133. Semaphore _sem;
  134. };
  135. LineBuffer::LineBuffer (Compressor *comp):
  136. uncompressedData (0),
  137. buffer (0),
  138. dataSize (0),
  139. compressor (comp),
  140. format (defaultFormat(compressor)),
  141. number (-1),
  142. hasException (false),
  143. exception (),
  144. _sem (1)
  145. {
  146. // empty
  147. }
  148. LineBuffer::~LineBuffer ()
  149. {
  150. delete compressor;
  151. }
  152. } // namespace
  153. struct ScanLineInputFile::Data: public Mutex
  154. {
  155. Header header; // the image header
  156. int version; // file's version
  157. FrameBuffer frameBuffer; // framebuffer to write into
  158. LineOrder lineOrder; // order of the scanlines in file
  159. int minX; // data window's min x coord
  160. int maxX; // data window's max x coord
  161. int minY; // data window's min y coord
  162. int maxY; // data window's max x coord
  163. vector<Int64> lineOffsets; // stores offsets in file for
  164. // each line
  165. bool fileIsComplete; // True if no scanlines are missing
  166. // in the file
  167. int nextLineBufferMinY; // minimum y of the next linebuffer
  168. vector<size_t> bytesPerLine; // combined size of a line over all
  169. // channels
  170. vector<size_t> offsetInLineBuffer; // offset for each scanline in its
  171. // linebuffer
  172. vector<InSliceInfo> slices; // info about channels in file
  173. IStream * is; // file stream to read from
  174. vector<LineBuffer*> lineBuffers; // each holds one line buffer
  175. int linesInBuffer; // number of scanlines each buffer
  176. // holds
  177. size_t lineBufferSize; // size of the line buffer
  178. Data (IStream *is, int numThreads);
  179. ~Data ();
  180. inline LineBuffer * getLineBuffer (int number); // hash function from line
  181. // buffer indices into our
  182. // vector of line buffers
  183. };
  184. ScanLineInputFile::Data::Data (IStream *is, int numThreads):
  185. is (is)
  186. {
  187. //
  188. // We need at least one lineBuffer, but if threading is used,
  189. // to keep n threads busy we need 2*n lineBuffers
  190. //
  191. lineBuffers.resize (max (1, 2 * numThreads));
  192. }
  193. ScanLineInputFile::Data::~Data ()
  194. {
  195. for (size_t i = 0; i < lineBuffers.size(); i++)
  196. delete lineBuffers[i];
  197. }
  198. inline LineBuffer *
  199. ScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
  200. {
  201. return lineBuffers[lineBufferNumber % lineBuffers.size()];
  202. }
  203. namespace {
  204. void
  205. reconstructLineOffsets (IStream &is,
  206. LineOrder lineOrder,
  207. vector<Int64> &lineOffsets)
  208. {
  209. Int64 position = is.tellg();
  210. try
  211. {
  212. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  213. {
  214. Int64 lineOffset = is.tellg();
  215. int y;
  216. Xdr::read <StreamIO> (is, y);
  217. int dataSize;
  218. Xdr::read <StreamIO> (is, dataSize);
  219. Xdr::skip <StreamIO> (is, dataSize);
  220. if (lineOrder == INCREASING_Y)
  221. lineOffsets[i] = lineOffset;
  222. else
  223. lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
  224. }
  225. }
  226. catch (...)
  227. {
  228. //
  229. // Suppress all exceptions. This functions is
  230. // called only to reconstruct the line offset
  231. // table for incomplete files, and exceptions
  232. // are likely.
  233. //
  234. }
  235. is.clear();
  236. is.seekg (position);
  237. }
  238. void
  239. readLineOffsets (IStream &is,
  240. LineOrder lineOrder,
  241. vector<Int64> &lineOffsets,
  242. bool &complete)
  243. {
  244. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  245. {
  246. Xdr::read <StreamIO> (is, lineOffsets[i]);
  247. }
  248. complete = true;
  249. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  250. {
  251. if (lineOffsets[i] <= 0)
  252. {
  253. //
  254. // Invalid data in the line offset table mean that
  255. // the file is probably incomplete (the table is
  256. // the last thing written to the file). Either
  257. // some process is still busy writing the file,
  258. // or writing the file was aborted.
  259. //
  260. // We should still be able to read the existing
  261. // parts of the file. In order to do this, we
  262. // have to make a sequential scan over the scan
  263. // line data to reconstruct the line offset table.
  264. //
  265. complete = false;
  266. reconstructLineOffsets (is, lineOrder, lineOffsets);
  267. break;
  268. }
  269. }
  270. }
  271. void
  272. readPixelData (ScanLineInputFile::Data *ifd,
  273. int minY,
  274. char *&buffer,
  275. int &dataSize)
  276. {
  277. //
  278. // Read a single line buffer from the input file.
  279. //
  280. // If the input file is not memory-mapped, we copy the pixel data into
  281. // into the array pointed to by buffer. If the file is memory-mapped,
  282. // then we change where buffer points to instead of writing into the
  283. // array (hence buffer needs to be a reference to a char *).
  284. //
  285. Int64 lineOffset =
  286. ifd->lineOffsets[(minY - ifd->minY) / ifd->linesInBuffer];
  287. if (lineOffset == 0)
  288. THROW (Iex::InputExc, "Scan line " << minY << " is missing.");
  289. //
  290. // Seek to the start of the scan line in the file,
  291. // if necessary.
  292. //
  293. if (ifd->nextLineBufferMinY != minY)
  294. ifd->is->seekg (lineOffset);
  295. //
  296. // Read the data block's header.
  297. //
  298. int yInFile;
  299. Xdr::read <StreamIO> (*ifd->is, yInFile);
  300. Xdr::read <StreamIO> (*ifd->is, dataSize);
  301. if (yInFile != minY)
  302. throw Iex::InputExc ("Unexpected data block y coordinate.");
  303. if (dataSize > (int) ifd->lineBufferSize)
  304. throw Iex::InputExc ("Unexpected data block length.");
  305. //
  306. // Read the pixel data.
  307. //
  308. if (ifd->is->isMemoryMapped ())
  309. buffer = ifd->is->readMemoryMapped (dataSize);
  310. else
  311. ifd->is->read (buffer, dataSize);
  312. //
  313. // Keep track of which scan line is the next one in
  314. // the file, so that we can avoid redundant seekg()
  315. // operations (seekg() can be fairly expensive).
  316. //
  317. if (ifd->lineOrder == INCREASING_Y)
  318. ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
  319. else
  320. ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
  321. }
  322. //
  323. // A LineBufferTask encapsulates the task uncompressing a set of
  324. // scanlines (line buffer) and copying them into the frame buffer.
  325. //
  326. class LineBufferTask : public Task
  327. {
  328. public:
  329. LineBufferTask (TaskGroup *group,
  330. ScanLineInputFile::Data *ifd,
  331. LineBuffer *lineBuffer,
  332. int scanLineMin,
  333. int scanLineMax);
  334. virtual ~LineBufferTask ();
  335. virtual void execute ();
  336. private:
  337. ScanLineInputFile::Data * _ifd;
  338. LineBuffer * _lineBuffer;
  339. int _scanLineMin;
  340. int _scanLineMax;
  341. };
  342. LineBufferTask::LineBufferTask
  343. (TaskGroup *group,
  344. ScanLineInputFile::Data *ifd,
  345. LineBuffer *lineBuffer,
  346. int scanLineMin,
  347. int scanLineMax)
  348. :
  349. Task (group),
  350. _ifd (ifd),
  351. _lineBuffer (lineBuffer),
  352. _scanLineMin (scanLineMin),
  353. _scanLineMax (scanLineMax)
  354. {
  355. // empty
  356. }
  357. LineBufferTask::~LineBufferTask ()
  358. {
  359. //
  360. // Signal that the line buffer is now free
  361. //
  362. _lineBuffer->post ();
  363. }
  364. void
  365. LineBufferTask::execute ()
  366. {
  367. try
  368. {
  369. //
  370. // Uncompress the data, if necessary
  371. //
  372. if (_lineBuffer->uncompressedData == 0)
  373. {
  374. int uncompressedSize = 0;
  375. int maxY = min (_lineBuffer->maxY, _ifd->maxY);
  376. for (int i = _lineBuffer->minY - _ifd->minY;
  377. i <= maxY - _ifd->minY;
  378. ++i)
  379. {
  380. uncompressedSize += (int) _ifd->bytesPerLine[i];
  381. }
  382. if (_lineBuffer->compressor &&
  383. _lineBuffer->dataSize < uncompressedSize)
  384. {
  385. _lineBuffer->format = _lineBuffer->compressor->format();
  386. _lineBuffer->dataSize = _lineBuffer->compressor->uncompress
  387. (_lineBuffer->buffer, _lineBuffer->dataSize,
  388. _lineBuffer->minY, _lineBuffer->uncompressedData);
  389. }
  390. else
  391. {
  392. //
  393. // If the line is uncompressed, it's in XDR format,
  394. // regardless of the compressor's output format.
  395. //
  396. _lineBuffer->format = Compressor::XDR;
  397. _lineBuffer->uncompressedData = _lineBuffer->buffer;
  398. }
  399. }
  400. int yStart, yStop, dy;
  401. if (_ifd->lineOrder == INCREASING_Y)
  402. {
  403. yStart = _scanLineMin;
  404. yStop = _scanLineMax + 1;
  405. dy = 1;
  406. }
  407. else
  408. {
  409. yStart = _scanLineMax;
  410. yStop = _scanLineMin - 1;
  411. dy = -1;
  412. }
  413. for (int y = yStart; y != yStop; y += dy)
  414. {
  415. //
  416. // Convert one scan line's worth of pixel data back
  417. // from the machine-independent representation, and
  418. // store the result in the frame buffer.
  419. //
  420. const char *readPtr = _lineBuffer->uncompressedData +
  421. _ifd->offsetInLineBuffer[y - _ifd->minY];
  422. //
  423. // Iterate over all image channels.
  424. //
  425. for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
  426. {
  427. //
  428. // Test if scan line y of this channel contains any data
  429. // (the scan line contains data only if y % ySampling == 0).
  430. //
  431. const InSliceInfo &slice = _ifd->slices[i];
  432. if (modp (y, slice.ySampling) != 0)
  433. continue;
  434. //
  435. // Find the x coordinates of the leftmost and rightmost
  436. // sampled pixels (i.e. pixels within the data window
  437. // for which x % xSampling == 0).
  438. //
  439. int dMinX = divp (_ifd->minX, slice.xSampling);
  440. int dMaxX = divp (_ifd->maxX, slice.xSampling);
  441. //
  442. // Fill the frame buffer with pixel data.
  443. //
  444. if (slice.skip)
  445. {
  446. //
  447. // The file contains data for this channel, but
  448. // the frame buffer contains no slice for this channel.
  449. //
  450. skipChannel (readPtr, slice.typeInFile, dMaxX - dMinX + 1);
  451. }
  452. else
  453. {
  454. //
  455. // The frame buffer contains a slice for this channel.
  456. //
  457. char *linePtr = slice.base +
  458. divp (y, slice.ySampling) *
  459. slice.yStride;
  460. char *writePtr = linePtr + dMinX * slice.xStride;
  461. char *endPtr = linePtr + dMaxX * slice.xStride;
  462. copyIntoFrameBuffer (readPtr, writePtr, endPtr,
  463. slice.xStride, slice.fill,
  464. slice.fillValue, _lineBuffer->format,
  465. slice.typeInFrameBuffer,
  466. slice.typeInFile);
  467. }
  468. }
  469. }
  470. }
  471. catch (std::exception &e)
  472. {
  473. if (!_lineBuffer->hasException)
  474. {
  475. _lineBuffer->exception = e.what();
  476. _lineBuffer->hasException = true;
  477. }
  478. }
  479. catch (...)
  480. {
  481. if (!_lineBuffer->hasException)
  482. {
  483. _lineBuffer->exception = "unrecognized exception";
  484. _lineBuffer->hasException = true;
  485. }
  486. }
  487. }
  488. LineBufferTask *
  489. newLineBufferTask
  490. (TaskGroup *group,
  491. ScanLineInputFile::Data *ifd,
  492. int number,
  493. int scanLineMin,
  494. int scanLineMax)
  495. {
  496. //
  497. // Wait for a line buffer to become available, fill the line
  498. // buffer with raw data from the file if necessary, and create
  499. // a new LineBufferTask whose execute() method will uncompress
  500. // the contents of the buffer and copy the pixels into the
  501. // frame buffer.
  502. //
  503. LineBuffer *lineBuffer = ifd->getLineBuffer (number);
  504. try
  505. {
  506. lineBuffer->wait ();
  507. if (lineBuffer->number != number)
  508. {
  509. lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
  510. lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
  511. lineBuffer->number = number;
  512. lineBuffer->uncompressedData = 0;
  513. readPixelData (ifd, lineBuffer->minY,
  514. lineBuffer->buffer,
  515. lineBuffer->dataSize);
  516. }
  517. }
  518. catch (std::exception &e)
  519. {
  520. if (!lineBuffer->hasException)
  521. {
  522. lineBuffer->exception = e.what();
  523. lineBuffer->hasException = true;
  524. }
  525. lineBuffer->number = -1;
  526. lineBuffer->post();\
  527. throw;
  528. }
  529. catch (...)
  530. {
  531. //
  532. // Reading from the file caused an exception.
  533. // Signal that the line buffer is free, and
  534. // re-throw the exception.
  535. //
  536. lineBuffer->exception = "unrecognized exception";
  537. lineBuffer->hasException = true;
  538. lineBuffer->number = -1;
  539. lineBuffer->post();
  540. throw;
  541. }
  542. scanLineMin = max (lineBuffer->minY, scanLineMin);
  543. scanLineMax = min (lineBuffer->maxY, scanLineMax);
  544. return new LineBufferTask (group, ifd, lineBuffer,
  545. scanLineMin, scanLineMax);
  546. }
  547. } // namespace
  548. ScanLineInputFile::ScanLineInputFile
  549. (const Header &header,
  550. IStream *is,
  551. int numThreads)
  552. :
  553. _data (new Data (is, numThreads))
  554. {
  555. try
  556. {
  557. _data->header = header;
  558. _data->lineOrder = _data->header.lineOrder();
  559. const Box2i &dataWindow = _data->header.dataWindow();
  560. _data->minX = dataWindow.min.x;
  561. _data->maxX = dataWindow.max.x;
  562. _data->minY = dataWindow.min.y;
  563. _data->maxY = dataWindow.max.y;
  564. size_t maxBytesPerLine = bytesPerLineTable (_data->header,
  565. _data->bytesPerLine);
  566. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  567. {
  568. _data->lineBuffers[i] = new LineBuffer (newCompressor
  569. (_data->header.compression(),
  570. maxBytesPerLine,
  571. _data->header));
  572. }
  573. _data->linesInBuffer =
  574. numLinesInBuffer (_data->lineBuffers[0]->compressor);
  575. _data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
  576. if (!_data->is->isMemoryMapped())
  577. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  578. _data->lineBuffers[i]->buffer = new char[_data->lineBufferSize];
  579. _data->nextLineBufferMinY = _data->minY - 1;
  580. offsetInLineBufferTable (_data->bytesPerLine,
  581. _data->linesInBuffer,
  582. _data->offsetInLineBuffer);
  583. int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
  584. _data->linesInBuffer) / _data->linesInBuffer;
  585. _data->lineOffsets.resize (lineOffsetSize);
  586. readLineOffsets (*_data->is,
  587. _data->lineOrder,
  588. _data->lineOffsets,
  589. _data->fileIsComplete);
  590. }
  591. catch (...)
  592. {
  593. delete _data;
  594. throw;
  595. }
  596. }
  597. ScanLineInputFile::~ScanLineInputFile ()
  598. {
  599. if (!_data->is->isMemoryMapped())
  600. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  601. delete [] _data->lineBuffers[i]->buffer;
  602. delete _data;
  603. }
  604. const char *
  605. ScanLineInputFile::fileName () const
  606. {
  607. return _data->is->fileName();
  608. }
  609. const Header &
  610. ScanLineInputFile::header () const
  611. {
  612. return _data->header;
  613. }
  614. int
  615. ScanLineInputFile::version () const
  616. {
  617. return _data->version;
  618. }
  619. void
  620. ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
  621. {
  622. Lock lock (*_data);
  623. //
  624. // Check if the new frame buffer descriptor is
  625. // compatible with the image file header.
  626. //
  627. const ChannelList &channels = _data->header.channels();
  628. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  629. j != frameBuffer.end();
  630. ++j)
  631. {
  632. ChannelList::ConstIterator i = channels.find (j.name());
  633. if (i == channels.end())
  634. continue;
  635. if (i.channel().xSampling != j.slice().xSampling ||
  636. i.channel().ySampling != j.slice().ySampling)
  637. THROW (Iex::ArgExc, "X and/or y subsampling factors "
  638. "of \"" << i.name() << "\" channel "
  639. "of input file \"" << fileName() << "\" are "
  640. "not compatible with the frame buffer's "
  641. "subsampling factors.");
  642. }
  643. //
  644. // Initialize the slice table for readPixels().
  645. //
  646. vector<InSliceInfo> slices;
  647. ChannelList::ConstIterator i = channels.begin();
  648. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  649. j != frameBuffer.end();
  650. ++j)
  651. {
  652. while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
  653. {
  654. //
  655. // Channel i is present in the file but not
  656. // in the frame buffer; data for channel i
  657. // will be skipped during readPixels().
  658. //
  659. slices.push_back (InSliceInfo (i.channel().type,
  660. i.channel().type,
  661. 0, // base
  662. 0, // xStride
  663. 0, // yStride
  664. i.channel().xSampling,
  665. i.channel().ySampling,
  666. false, // fill
  667. true, // skip
  668. 0.0)); // fillValue
  669. ++i;
  670. }
  671. bool fill = false;
  672. if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
  673. {
  674. //
  675. // Channel i is present in the frame buffer, but not in the file.
  676. // In the frame buffer, slice j will be filled with a default value.
  677. //
  678. fill = true;
  679. }
  680. slices.push_back (InSliceInfo (j.slice().type,
  681. fill? j.slice().type:
  682. i.channel().type,
  683. j.slice().base,
  684. j.slice().xStride,
  685. j.slice().yStride,
  686. j.slice().xSampling,
  687. j.slice().ySampling,
  688. fill,
  689. false, // skip
  690. j.slice().fillValue));
  691. if (i != channels.end() && !fill)
  692. ++i;
  693. }
  694. //
  695. // Store the new frame buffer.
  696. //
  697. _data->frameBuffer = frameBuffer;
  698. _data->slices = slices;
  699. }
  700. const FrameBuffer &
  701. ScanLineInputFile::frameBuffer () const
  702. {
  703. Lock lock (*_data);
  704. return _data->frameBuffer;
  705. }
  706. bool
  707. ScanLineInputFile::isComplete () const
  708. {
  709. return _data->fileIsComplete;
  710. }
  711. void
  712. ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
  713. {
  714. try
  715. {
  716. Lock lock (*_data);
  717. if (_data->slices.size() == 0)
  718. throw Iex::ArgExc ("No frame buffer specified "
  719. "as pixel data destination.");
  720. int scanLineMin = min (scanLine1, scanLine2);
  721. int scanLineMax = max (scanLine1, scanLine2);
  722. if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
  723. throw Iex::ArgExc ("Tried to read scan line outside "
  724. "the image file's data window.");
  725. //
  726. // We impose a numbering scheme on the lineBuffers where the first
  727. // scanline is contained in lineBuffer 1.
  728. //
  729. // Determine the first and last lineBuffer numbers in this scanline
  730. // range. We always attempt to read the scanlines in the order that
  731. // they are stored in the file.
  732. //
  733. int start, stop, dl;
  734. if (_data->lineOrder == INCREASING_Y)
  735. {
  736. start = (scanLineMin - _data->minY) / _data->linesInBuffer;
  737. stop = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
  738. dl = 1;
  739. }
  740. else
  741. {
  742. start = (scanLineMax - _data->minY) / _data->linesInBuffer;
  743. stop = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
  744. dl = -1;
  745. }
  746. //
  747. // Create a task group for all line buffer tasks. When the
  748. // task group goes out of scope, the destructor waits until
  749. // all tasks are complete.
  750. //
  751. {
  752. TaskGroup taskGroup;
  753. //
  754. // Add the line buffer tasks.
  755. //
  756. // The tasks will execute in the order that they are created
  757. // because we lock the line buffers during construction and the
  758. // constructors are called by the main thread. Hence, in order
  759. // for a successive task to execute the previous task which
  760. // used that line buffer must have completed already.
  761. //
  762. for (int l = start; l != stop; l += dl)
  763. {
  764. ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
  765. _data, l,
  766. scanLineMin,
  767. scanLineMax));
  768. }
  769. //
  770. // finish all tasks
  771. //
  772. }
  773. //
  774. // Exeption handling:
  775. //
  776. // LineBufferTask::execute() may have encountered exceptions, but
  777. // those exceptions occurred in another thread, not in the thread
  778. // that is executing this call to ScanLineInputFile::readPixels().
  779. // LineBufferTask::execute() has caught all exceptions and stored
  780. // the exceptions' what() strings in the line buffers.
  781. // Now we check if any line buffer contains a stored exception; if
  782. // this is the case then we re-throw the exception in this thread.
  783. // (It is possible that multiple line buffers contain stored
  784. // exceptions. We re-throw the first exception we find and
  785. // ignore all others.)
  786. //
  787. const string *exception = 0;
  788. for (int i = 0; i < _data->lineBuffers.size(); ++i)
  789. {
  790. LineBuffer *lineBuffer = _data->lineBuffers[i];
  791. if (lineBuffer->hasException && !exception)
  792. exception = &lineBuffer->exception;
  793. lineBuffer->hasException = false;
  794. }
  795. if (exception)
  796. throw Iex::IoExc (*exception);
  797. }
  798. catch (Iex::BaseExc &e)
  799. {
  800. REPLACE_EXC (e, "Error reading pixel data from image "
  801. "file \"" << fileName() << "\". " << e);
  802. throw;
  803. }
  804. }
  805. void
  806. ScanLineInputFile::readPixels (int scanLine)
  807. {
  808. readPixels (scanLine, scanLine);
  809. }
  810. void
  811. ScanLineInputFile::rawPixelData (int firstScanLine,
  812. const char *&pixelData,
  813. int &pixelDataSize)
  814. {
  815. try
  816. {
  817. Lock lock (*_data);
  818. if (firstScanLine < _data->minY || firstScanLine > _data->maxY)
  819. {
  820. throw Iex::ArgExc ("Tried to read scan line outside "
  821. "the image file's data window.");
  822. }
  823. int minY = lineBufferMinY
  824. (firstScanLine, _data->minY, _data->linesInBuffer);
  825. readPixelData
  826. (_data, minY, _data->lineBuffers[0]->buffer, pixelDataSize);
  827. pixelData = _data->lineBuffers[0]->buffer;
  828. }
  829. catch (Iex::BaseExc &e)
  830. {
  831. REPLACE_EXC (e, "Error reading pixel data from image "
  832. "file \"" << fileName() << "\". " << e);
  833. throw;
  834. }
  835. }
  836. } // namespace Imf