PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/3rdparty/openexr/IlmImf/ImfScanLineInputFile.cpp

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