PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp

https://gitlab.com/seranth/FreeImage
C++ | 1562 lines | 961 code | 302 blank | 299 comment | 135 complexity | 4443cf3150fe790ef60bfcf66f723904 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2011, 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 DeepScanLineInputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfDeepScanLineInputFile.h>
  40. #include <ImfChannelList.h>
  41. #include <ImfMisc.h>
  42. #include <ImfStdIO.h>
  43. #include <ImfCompressor.h>
  44. #include <ImfXdr.h>
  45. #include <ImfConvert.h>
  46. #include <ImfThreading.h>
  47. #include <ImfPartType.h>
  48. #include <ImfVersion.h>
  49. #include "ImfMultiPartInputFile.h"
  50. #include "ImfDeepFrameBuffer.h"
  51. #include "ImfInputStreamMutex.h"
  52. #include "ImfInputPartData.h"
  53. #include "ImathBox.h"
  54. #include "ImathFun.h"
  55. #include "IlmThreadPool.h"
  56. #include "IlmThreadSemaphore.h"
  57. #include "IlmThreadMutex.h"
  58. #include "Iex.h"
  59. #include <string>
  60. #include <vector>
  61. #include <assert.h>
  62. #include <limits>
  63. #include <algorithm>
  64. #include "ImfNamespace.h"
  65. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
  66. using IMATH_NAMESPACE::Box2i;
  67. using IMATH_NAMESPACE::divp;
  68. using IMATH_NAMESPACE::modp;
  69. using std::string;
  70. using std::vector;
  71. using std::ifstream;
  72. using std::min;
  73. using std::max;
  74. using ILMTHREAD_NAMESPACE::Mutex;
  75. using ILMTHREAD_NAMESPACE::Lock;
  76. using ILMTHREAD_NAMESPACE::Semaphore;
  77. using ILMTHREAD_NAMESPACE::Task;
  78. using ILMTHREAD_NAMESPACE::TaskGroup;
  79. using ILMTHREAD_NAMESPACE::ThreadPool;
  80. namespace {
  81. struct InSliceInfo
  82. {
  83. PixelType typeInFrameBuffer;
  84. PixelType typeInFile;
  85. char * base;
  86. char* pointerArrayBase;
  87. size_t xPointerStride;
  88. size_t yPointerStride;
  89. size_t sampleStride;
  90. int xSampling;
  91. int ySampling;
  92. bool fill;
  93. bool skip;
  94. double fillValue;
  95. InSliceInfo (PixelType typeInFrameBuffer = HALF,
  96. char * base = NULL,
  97. PixelType typeInFile = HALF,
  98. size_t xPointerStride = 0,
  99. size_t yPointerStride = 0,
  100. size_t sampleStride = 0,
  101. int xSampling = 1,
  102. int ySampling = 1,
  103. bool fill = false,
  104. bool skip = false,
  105. double fillValue = 0.0);
  106. };
  107. InSliceInfo::InSliceInfo (PixelType tifb,
  108. char * b,
  109. PixelType tifl,
  110. size_t xpst,
  111. size_t ypst,
  112. size_t spst,
  113. int xsm, int ysm,
  114. bool f, bool s,
  115. double fv)
  116. :
  117. typeInFrameBuffer (tifb),
  118. typeInFile (tifl),
  119. base(b),
  120. xPointerStride (xpst),
  121. yPointerStride (ypst),
  122. sampleStride (spst),
  123. xSampling (xsm),
  124. ySampling (ysm),
  125. fill (f),
  126. skip (s),
  127. fillValue (fv)
  128. {
  129. // empty
  130. }
  131. struct LineBuffer
  132. {
  133. const char * uncompressedData;
  134. char * buffer;
  135. Int64 packedDataSize;
  136. Int64 unpackedDataSize;
  137. int minY;
  138. int maxY;
  139. Compressor * compressor;
  140. Compressor::Format format;
  141. int number;
  142. bool hasException;
  143. string exception;
  144. LineBuffer ();
  145. ~LineBuffer ();
  146. inline void wait () {_sem.wait();}
  147. inline void post () {_sem.post();}
  148. private:
  149. Semaphore _sem;
  150. };
  151. LineBuffer::LineBuffer ():
  152. uncompressedData (0),
  153. buffer (0),
  154. packedDataSize (0),
  155. compressor (0),
  156. format (defaultFormat(compressor)),
  157. number (-1),
  158. hasException (false),
  159. exception (),
  160. _sem (1)
  161. {
  162. // empty
  163. }
  164. LineBuffer::~LineBuffer ()
  165. {
  166. if (compressor != 0)
  167. delete compressor;
  168. }
  169. } // namespace
  170. struct DeepScanLineInputFile::Data: public Mutex
  171. {
  172. Header header; // the image header
  173. int version; // file's version
  174. DeepFrameBuffer frameBuffer; // framebuffer to write into
  175. LineOrder lineOrder; // order of the scanlines in file
  176. int minX; // data window's min x coord
  177. int maxX; // data window's max x coord
  178. int minY; // data window's min y coord
  179. int maxY; // data window's max x coord
  180. vector<Int64> lineOffsets; // stores offsets in file for
  181. // each line
  182. bool fileIsComplete; // True if no scanlines are missing
  183. // in the file
  184. int nextLineBufferMinY; // minimum y of the next linebuffer
  185. vector<size_t> bytesPerLine; // combined size of a line over all
  186. // channels
  187. vector<size_t> offsetInLineBuffer; // offset for each scanline in its
  188. // linebuffer
  189. vector<InSliceInfo*> slices; // info about channels in file
  190. vector<LineBuffer*> lineBuffers; // each holds one line buffer
  191. int linesInBuffer; // number of scanlines each buffer
  192. // holds
  193. int partNumber; // part number
  194. int numThreads; // number of threads
  195. bool multiPartBackwardSupport; // if we are reading a multipart file using single file API
  196. MultiPartInputFile* multiPartFile; // for multipart files opened as single part
  197. bool memoryMapped; // if the stream is memory mapped
  198. Array2D<unsigned int> sampleCount; // the number of samples
  199. // in each pixel
  200. Array<unsigned int> lineSampleCount; // the number of samples
  201. // in each line
  202. Array<bool> gotSampleCount; // for each scanline, indicating if
  203. // we have got its sample count table
  204. char* sampleCountSliceBase; // pointer to the start of
  205. // the sample count array
  206. int sampleCountXStride; // x stride of the sample count array
  207. int sampleCountYStride; // y stride of the sample count array
  208. bool frameBufferValid; // set by setFrameBuffer: excepts if readPixelSampleCounts if false
  209. Array<char> sampleCountTableBuffer;
  210. // the buffer for sample count table
  211. Compressor* sampleCountTableComp;
  212. // the decompressor for sample count table
  213. int combinedSampleSize; // total size of all channels combined: used to sanity check sample table size
  214. int maxSampleCountTableSize;
  215. // the max size in bytes for a pixel
  216. // sample count table
  217. InputStreamMutex* _streamData;
  218. bool _deleteStream;
  219. Data (int numThreads);
  220. ~Data ();
  221. inline LineBuffer * getLineBuffer (int number); // hash function from line
  222. // buffer indices into our
  223. // vector of line buffers
  224. };
  225. DeepScanLineInputFile::Data::Data (int numThreads):
  226. partNumber(-1),
  227. numThreads(numThreads),
  228. multiPartBackwardSupport(false),
  229. multiPartFile(NULL),
  230. memoryMapped(false),
  231. frameBufferValid(false),
  232. _streamData(NULL),
  233. _deleteStream(false)
  234. {
  235. //
  236. // We need at least one lineBuffer, but if threading is used,
  237. // to keep n threads busy we need 2*n lineBuffers
  238. //
  239. lineBuffers.resize (max (1, 2 * numThreads));
  240. for (size_t i = 0; i < lineBuffers.size(); i++)
  241. lineBuffers[i] = 0;
  242. sampleCountTableComp = 0;
  243. }
  244. DeepScanLineInputFile::Data::~Data ()
  245. {
  246. for (size_t i = 0; i < lineBuffers.size(); i++)
  247. if (lineBuffers[i] != 0)
  248. delete lineBuffers[i];
  249. for (size_t i = 0; i < slices.size(); i++)
  250. delete slices[i];
  251. if (sampleCountTableComp != 0)
  252. delete sampleCountTableComp;
  253. if (multiPartBackwardSupport)
  254. delete multiPartFile;
  255. }
  256. inline LineBuffer *
  257. DeepScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
  258. {
  259. return lineBuffers[lineBufferNumber % lineBuffers.size()];
  260. }
  261. namespace {
  262. void
  263. reconstructLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  264. LineOrder lineOrder,
  265. vector<Int64> &lineOffsets)
  266. {
  267. Int64 position = is.tellg();
  268. try
  269. {
  270. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  271. {
  272. Int64 lineOffset = is.tellg();
  273. int y;
  274. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y);
  275. Int64 packed_offset;
  276. Int64 packed_sample;
  277. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
  278. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
  279. //next is unpacked sample table size - skip this too
  280. Xdr::skip <StreamIO> (is, packed_offset+packed_sample+8);
  281. if (lineOrder == INCREASING_Y)
  282. lineOffsets[i] = lineOffset;
  283. else
  284. lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
  285. }
  286. }
  287. catch (...)
  288. {
  289. //
  290. // Suppress all exceptions. This functions is
  291. // called only to reconstruct the line offset
  292. // table for incomplete files, and exceptions
  293. // are likely.
  294. //
  295. }
  296. is.clear();
  297. is.seekg (position);
  298. }
  299. void
  300. readLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  301. LineOrder lineOrder,
  302. vector<Int64> &lineOffsets,
  303. bool &complete)
  304. {
  305. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  306. {
  307. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, lineOffsets[i]);
  308. }
  309. complete = true;
  310. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  311. {
  312. if (lineOffsets[i] <= 0)
  313. {
  314. //
  315. // Invalid data in the line offset table mean that
  316. // the file is probably incomplete (the table is
  317. // the last thing written to the file). Either
  318. // some process is still busy writing the file,
  319. // or writing the file was aborted.
  320. //
  321. // We should still be able to read the existing
  322. // parts of the file. In order to do this, we
  323. // have to make a sequential scan over the scan
  324. // line data to reconstruct the line offset table.
  325. //
  326. complete = false;
  327. reconstructLineOffsets (is, lineOrder, lineOffsets);
  328. break;
  329. }
  330. }
  331. }
  332. void
  333. readPixelData (InputStreamMutex *streamData,
  334. DeepScanLineInputFile::Data *ifd,
  335. int minY,
  336. char *&buffer,
  337. Int64 &packedDataSize,
  338. Int64 &unpackedDataSize)
  339. {
  340. //
  341. // Read a single line buffer from the input file.
  342. //
  343. // If the input file is not memory-mapped, we copy the pixel data into
  344. // into the array pointed to by buffer. If the file is memory-mapped,
  345. // then we change where buffer points to instead of writing into the
  346. // array (hence buffer needs to be a reference to a char *).
  347. //
  348. int lineBufferNumber = (minY - ifd->minY) / ifd->linesInBuffer;
  349. Int64 lineOffset = ifd->lineOffsets[lineBufferNumber];
  350. if (lineOffset == 0)
  351. THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
  352. //
  353. // Seek to the start of the scan line in the file,
  354. // if necessary.
  355. //
  356. if (!isMultiPart(ifd->version))
  357. {
  358. if (ifd->nextLineBufferMinY != minY)
  359. streamData->is->seekg (lineOffset);
  360. }
  361. else
  362. {
  363. //
  364. // In a multi-part file, the file pointer may have been moved by
  365. // other parts, so we have to ask tellg() where we are.
  366. //
  367. if (streamData->is->tellg() != ifd->lineOffsets[lineBufferNumber])
  368. streamData->is->seekg (lineOffset);
  369. }
  370. //
  371. // Read the data block's header.
  372. //
  373. int yInFile;
  374. //
  375. // Read the part number when we are dealing with a multi-part file.
  376. //
  377. if (isMultiPart(ifd->version))
  378. {
  379. int partNumber;
  380. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
  381. if (partNumber != ifd->partNumber)
  382. {
  383. THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
  384. << ", should be " << ifd->partNumber << ".");
  385. }
  386. }
  387. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, yInFile);
  388. if (yInFile != minY)
  389. throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
  390. Int64 sampleCountTableSize;
  391. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, sampleCountTableSize);
  392. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, packedDataSize);
  393. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, unpackedDataSize);
  394. //
  395. // We make a check on the data size requirements here.
  396. // Whilst we wish to store 64bit sizes on disk, not all the compressors
  397. // have been made to work with such data sizes and are still limited to
  398. // using signed 32 bit (int) for the data size. As such, this version
  399. // insists that we validate that the data size does not exceed the data
  400. // type max limit.
  401. // @TODO refactor the compressor code to ensure full 64-bit support.
  402. //
  403. int compressorMaxDataSize = std::numeric_limits<int>::max();
  404. if (packedDataSize > Int64(compressorMaxDataSize) ||
  405. unpackedDataSize > Int64(compressorMaxDataSize))
  406. {
  407. THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not support "
  408. << "the allocation of data with size > " << compressorMaxDataSize
  409. << " file unpacked size :" << unpackedDataSize
  410. << " file packed size :" << packedDataSize << ".\n");
  411. }
  412. //
  413. // Skip the pixel sample count table because we have read this data.
  414. //
  415. Xdr::skip <StreamIO> (*streamData->is, sampleCountTableSize);
  416. //
  417. // Read the pixel data.
  418. //
  419. if (streamData->is->isMemoryMapped ())
  420. buffer = streamData->is->readMemoryMapped (packedDataSize);
  421. else
  422. {
  423. // (TODO) check if the packed data size is too big?
  424. // (TODO) better memory management. Don't delete buffer all the time.
  425. if (buffer != 0) delete[] buffer;
  426. buffer = new char[packedDataSize];
  427. streamData->is->read (buffer, packedDataSize);
  428. }
  429. //
  430. // Keep track of which scan line is the next one in
  431. // the file, so that we can avoid redundant seekg()
  432. // operations (seekg() can be fairly expensive).
  433. //
  434. if (ifd->lineOrder == INCREASING_Y)
  435. ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
  436. else
  437. ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
  438. }
  439. //
  440. // A LineBufferTask encapsulates the task uncompressing a set of
  441. // scanlines (line buffer) and copying them into the frame buffer.
  442. //
  443. class LineBufferTask : public Task
  444. {
  445. public:
  446. LineBufferTask (TaskGroup *group,
  447. DeepScanLineInputFile::Data *ifd,
  448. LineBuffer *lineBuffer,
  449. int scanLineMin,
  450. int scanLineMax);
  451. virtual ~LineBufferTask ();
  452. virtual void execute ();
  453. private:
  454. DeepScanLineInputFile::Data * _ifd;
  455. LineBuffer * _lineBuffer;
  456. int _scanLineMin;
  457. int _scanLineMax;
  458. };
  459. LineBufferTask::LineBufferTask
  460. (TaskGroup *group,
  461. DeepScanLineInputFile::Data *ifd,
  462. LineBuffer *lineBuffer,
  463. int scanLineMin,
  464. int scanLineMax)
  465. :
  466. Task (group),
  467. _ifd (ifd),
  468. _lineBuffer (lineBuffer),
  469. _scanLineMin (scanLineMin),
  470. _scanLineMax (scanLineMax)
  471. {
  472. // empty
  473. }
  474. LineBufferTask::~LineBufferTask ()
  475. {
  476. //
  477. // Signal that the line buffer is now free
  478. //
  479. _lineBuffer->post ();
  480. }
  481. void
  482. LineBufferTask::execute ()
  483. {
  484. try
  485. {
  486. //
  487. // Uncompress the data, if necessary
  488. //
  489. if (_lineBuffer->uncompressedData == 0)
  490. {
  491. Int64 uncompressedSize = 0;
  492. int maxY = min (_lineBuffer->maxY, _ifd->maxY);
  493. for (int i = _lineBuffer->minY - _ifd->minY;
  494. i <= maxY - _ifd->minY;
  495. ++i)
  496. {
  497. uncompressedSize += (int) _ifd->bytesPerLine[i];
  498. }
  499. //
  500. // Create the compressor everytime when we want to use it,
  501. // because we don't know maxBytesPerLine beforehand.
  502. // (TODO) optimize this. don't do this every time.
  503. //
  504. if (_lineBuffer->compressor != 0)
  505. delete _lineBuffer->compressor;
  506. Int64 maxBytesPerLine = 0;
  507. for (int i = _lineBuffer->minY - _ifd->minY;
  508. i <= maxY - _ifd->minY;
  509. ++i)
  510. {
  511. if (_ifd->bytesPerLine[i] > maxBytesPerLine)
  512. maxBytesPerLine = _ifd->bytesPerLine[i];
  513. }
  514. _lineBuffer->compressor = newCompressor(_ifd->header.compression(),
  515. maxBytesPerLine,
  516. _ifd->header);
  517. if (_lineBuffer->compressor &&
  518. _lineBuffer->packedDataSize < uncompressedSize)
  519. {
  520. _lineBuffer->format = _lineBuffer->compressor->format();
  521. _lineBuffer->packedDataSize = _lineBuffer->compressor->uncompress
  522. (_lineBuffer->buffer, _lineBuffer->packedDataSize,
  523. _lineBuffer->minY, _lineBuffer->uncompressedData);
  524. }
  525. else
  526. {
  527. //
  528. // If the line is uncompressed, it's in XDR format,
  529. // regardless of the compressor's output format.
  530. //
  531. _lineBuffer->format = Compressor::XDR;
  532. _lineBuffer->uncompressedData = _lineBuffer->buffer;
  533. }
  534. }
  535. int yStart, yStop, dy;
  536. if (_ifd->lineOrder == INCREASING_Y)
  537. {
  538. yStart = _scanLineMin;
  539. yStop = _scanLineMax + 1;
  540. dy = 1;
  541. }
  542. else
  543. {
  544. yStart = _scanLineMax;
  545. yStop = _scanLineMin - 1;
  546. dy = -1;
  547. }
  548. for (int y = yStart; y != yStop; y += dy)
  549. {
  550. //
  551. // Convert one scan line's worth of pixel data back
  552. // from the machine-independent representation, and
  553. // store the result in the frame buffer.
  554. //
  555. const char *readPtr = _lineBuffer->uncompressedData +
  556. _ifd->offsetInLineBuffer[y - _ifd->minY];
  557. //
  558. // Iterate over all image channels.
  559. //
  560. for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
  561. {
  562. //
  563. // Test if scan line y of this channel contains any data
  564. // (the scan line contains data only if y % ySampling == 0).
  565. //
  566. InSliceInfo &slice = *_ifd->slices[i];
  567. if (modp (y, slice.ySampling) != 0)
  568. continue;
  569. //
  570. // Find the x coordinates of the leftmost and rightmost
  571. // sampled pixels (i.e. pixels within the data window
  572. // for which x % xSampling == 0).
  573. //
  574. //
  575. // Fill the frame buffer with pixel data.
  576. //
  577. if (slice.skip)
  578. {
  579. //
  580. // The file contains data for this channel, but
  581. // the frame buffer contains no slice for this channel.
  582. //
  583. skipChannel (readPtr, slice.typeInFile,
  584. _ifd->lineSampleCount[y - _ifd->minY]);
  585. }
  586. else
  587. {
  588. //
  589. // The frame buffer contains a slice for this channel.
  590. //
  591. int width = (_ifd->maxX - _ifd->minX + 1);
  592. copyIntoDeepFrameBuffer (readPtr, slice.base,
  593. (char*) (&_ifd->sampleCount[0][0]
  594. - _ifd->minX
  595. - _ifd->minY * width),
  596. sizeof(unsigned int) * 1,
  597. sizeof(unsigned int) * width,
  598. y, _ifd->minX, _ifd->maxX,
  599. 0, 0,
  600. 0, 0,
  601. slice.sampleStride,
  602. slice.xPointerStride,
  603. slice.yPointerStride,
  604. slice.fill,
  605. slice.fillValue, _lineBuffer->format,
  606. slice.typeInFrameBuffer,
  607. slice.typeInFile);
  608. }
  609. }
  610. }
  611. }
  612. catch (std::exception &e)
  613. {
  614. if (!_lineBuffer->hasException)
  615. {
  616. _lineBuffer->exception = e.what();
  617. _lineBuffer->hasException = true;
  618. }
  619. }
  620. catch (...)
  621. {
  622. if (!_lineBuffer->hasException)
  623. {
  624. _lineBuffer->exception = "unrecognized exception";
  625. _lineBuffer->hasException = true;
  626. }
  627. }
  628. }
  629. LineBufferTask *
  630. newLineBufferTask
  631. (TaskGroup *group,
  632. DeepScanLineInputFile::Data *ifd,
  633. int number,
  634. int scanLineMin,
  635. int scanLineMax)
  636. {
  637. //
  638. // Wait for a line buffer to become available, fill the line
  639. // buffer with raw data from the file if necessary, and create
  640. // a new LineBufferTask whose execute() method will uncompress
  641. // the contents of the buffer and copy the pixels into the
  642. // frame buffer.
  643. //
  644. LineBuffer *lineBuffer = ifd->getLineBuffer (number);
  645. try
  646. {
  647. lineBuffer->wait ();
  648. if (lineBuffer->number != number)
  649. {
  650. lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
  651. lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
  652. lineBuffer->number = number;
  653. lineBuffer->uncompressedData = 0;
  654. readPixelData (ifd->_streamData, ifd, lineBuffer->minY,
  655. lineBuffer->buffer,
  656. lineBuffer->packedDataSize,
  657. lineBuffer->unpackedDataSize);
  658. }
  659. }
  660. catch (std::exception &e)
  661. {
  662. if (!lineBuffer->hasException)
  663. {
  664. lineBuffer->exception = e.what();
  665. lineBuffer->hasException = true;
  666. }
  667. lineBuffer->number = -1;
  668. lineBuffer->post();
  669. throw;
  670. }
  671. catch (...)
  672. {
  673. //
  674. // Reading from the file caused an exception.
  675. // Signal that the line buffer is free, and
  676. // re-throw the exception.
  677. //
  678. lineBuffer->exception = "unrecognized exception";
  679. lineBuffer->hasException = true;
  680. lineBuffer->number = -1;
  681. lineBuffer->post();
  682. throw;
  683. }
  684. scanLineMin = max (lineBuffer->minY, scanLineMin);
  685. scanLineMax = min (lineBuffer->maxY, scanLineMax);
  686. return new LineBufferTask (group, ifd, lineBuffer,
  687. scanLineMin, scanLineMax);
  688. }
  689. } // namespace
  690. void DeepScanLineInputFile::initialize(const Header& header)
  691. {
  692. try
  693. {
  694. if (header.type() != DEEPSCANLINE)
  695. throw IEX_NAMESPACE::ArgExc("Can't build a DeepScanLineInputFile from "
  696. "a type-mismatched part.");
  697. if(header.version()!=1)
  698. {
  699. THROW(IEX_NAMESPACE::ArgExc, "Version " << header.version() << " not supported for deepscanline images in this version of the library");
  700. }
  701. _data->header = header;
  702. _data->lineOrder = _data->header.lineOrder();
  703. const Box2i &dataWindow = _data->header.dataWindow();
  704. _data->minX = dataWindow.min.x;
  705. _data->maxX = dataWindow.max.x;
  706. _data->minY = dataWindow.min.y;
  707. _data->maxY = dataWindow.max.y;
  708. _data->sampleCount.resizeErase(_data->maxY - _data->minY + 1,
  709. _data->maxX - _data->minX + 1);
  710. _data->lineSampleCount.resizeErase(_data->maxY - _data->minY + 1);
  711. Compressor* compressor = newCompressor(_data->header.compression(),
  712. 0,
  713. _data->header);
  714. _data->linesInBuffer = numLinesInBuffer (compressor);
  715. delete compressor;
  716. _data->nextLineBufferMinY = _data->minY - 1;
  717. int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
  718. _data->linesInBuffer) / _data->linesInBuffer;
  719. _data->lineOffsets.resize (lineOffsetSize);
  720. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  721. _data->lineBuffers[i] = new LineBuffer ();
  722. _data->gotSampleCount.resizeErase(_data->maxY - _data->minY + 1);
  723. for (int i = 0; i < _data->maxY - _data->minY + 1; i++)
  724. _data->gotSampleCount[i] = false;
  725. _data->maxSampleCountTableSize = min(_data->linesInBuffer, _data->maxY - _data->minY + 1) *
  726. (_data->maxX - _data->minX + 1) *
  727. sizeof(unsigned int);
  728. _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize);
  729. _data->sampleCountTableComp = newCompressor(_data->header.compression(),
  730. _data->maxSampleCountTableSize,
  731. _data->header);
  732. _data->bytesPerLine.resize (_data->maxY - _data->minY + 1);
  733. const ChannelList & c=header.channels();
  734. _data->combinedSampleSize=0;
  735. for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
  736. {
  737. switch(i.channel().type)
  738. {
  739. case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
  740. _data->combinedSampleSize+=Xdr::size<half>();
  741. break;
  742. case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
  743. _data->combinedSampleSize+=Xdr::size<float>();
  744. break;
  745. case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
  746. _data->combinedSampleSize+=Xdr::size<unsigned int>();
  747. break;
  748. default :
  749. THROW(IEX_NAMESPACE::ArgExc, "Bad type for channel " << i.name() << " initializing deepscanline reader");
  750. }
  751. }
  752. }
  753. catch (...)
  754. {
  755. delete _data;
  756. _data=NULL;
  757. throw;
  758. }
  759. }
  760. DeepScanLineInputFile::DeepScanLineInputFile(InputPartData* part)
  761. {
  762. _data = new Data(part->numThreads);
  763. _data->_deleteStream=false;
  764. _data->_streamData = part->mutex;
  765. _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
  766. _data->version = part->version;
  767. initialize(part->header);
  768. _data->lineOffsets = part->chunkOffsets;
  769. _data->partNumber = part->partNumber;
  770. }
  771. DeepScanLineInputFile::DeepScanLineInputFile
  772. (const char fileName[], int numThreads)
  773. :
  774. _data (new Data (numThreads))
  775. {
  776. _data->_streamData = new InputStreamMutex();
  777. _data->_deleteStream = true;
  778. OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0;
  779. try
  780. {
  781. is = new StdIFStream (fileName);
  782. readMagicNumberAndVersionField(*is, _data->version);
  783. //
  784. // Backward compatibility to read multpart file.
  785. //
  786. if (isMultiPart(_data->version))
  787. {
  788. compatibilityInitialize(*is);
  789. return;
  790. }
  791. _data->_streamData->is = is;
  792. _data->memoryMapped = is->isMemoryMapped();
  793. _data->header.readFrom (*_data->_streamData->is, _data->version);
  794. _data->header.sanityCheck (isTiled (_data->version));
  795. initialize(_data->header);
  796. readLineOffsets (*_data->_streamData->is,
  797. _data->lineOrder,
  798. _data->lineOffsets,
  799. _data->fileIsComplete);
  800. }
  801. catch (IEX_NAMESPACE::BaseExc &e)
  802. {
  803. if (is) delete is;
  804. if (_data && _data->_streamData) delete _data->_streamData;
  805. if (_data) delete _data;
  806. REPLACE_EXC (e, "Cannot read image file "
  807. "\"" << fileName << "\". " << e);
  808. throw;
  809. }
  810. catch (...)
  811. {
  812. if (is) delete is;
  813. if (_data && _data->_streamData) delete _data->_streamData;
  814. if (_data) delete _data;
  815. throw;
  816. }
  817. }
  818. DeepScanLineInputFile::DeepScanLineInputFile
  819. (const Header &header,
  820. OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
  821. int version,
  822. int numThreads)
  823. :
  824. _data (new Data (numThreads))
  825. {
  826. _data->_streamData=new InputStreamMutex();
  827. _data->_deleteStream=false;
  828. _data->_streamData->is = is;
  829. _data->memoryMapped = is->isMemoryMapped();
  830. _data->version =version;
  831. initialize (header);
  832. readLineOffsets (*_data->_streamData->is,
  833. _data->lineOrder,
  834. _data->lineOffsets,
  835. _data->fileIsComplete);
  836. }
  837. DeepScanLineInputFile::~DeepScanLineInputFile ()
  838. {
  839. if (_data->_deleteStream)
  840. delete _data->_streamData->is;
  841. if (_data)
  842. {
  843. if (!_data->memoryMapped)
  844. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  845. delete [] _data->lineBuffers[i]->buffer;
  846. //
  847. // Unless this file was opened via the multipart API, delete the streamdata
  848. // object too.
  849. // (TODO) it should be "isMultiPart(data->version)", but when there is only
  850. // single part,
  851. // (see the above constructor) the version field is not set.
  852. //
  853. // (TODO) we should have a way to tell if the stream data is owned by this
  854. // file or by a parent multipart file.
  855. //
  856. if (_data->partNumber == -1 && _data->_streamData)
  857. delete _data->_streamData;
  858. delete _data;
  859. }
  860. }
  861. void
  862. DeepScanLineInputFile::compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
  863. {
  864. is.seekg(0);
  865. //
  866. // Construct a MultiPartInputFile, initialize TiledInputFile
  867. // with the part 0 data.
  868. // (TODO) maybe change the third parameter of the constructor of MultiPartInputFile later.
  869. //
  870. _data->multiPartBackwardSupport = true;
  871. _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
  872. InputPartData* part = _data->multiPartFile->getPart(0);
  873. multiPartInitialize(part);
  874. }
  875. void DeepScanLineInputFile::multiPartInitialize(InputPartData* part)
  876. {
  877. _data->_streamData = part->mutex;
  878. _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
  879. _data->version = part->version;
  880. initialize(part->header);
  881. _data->lineOffsets = part->chunkOffsets;
  882. _data->partNumber = part->partNumber;
  883. }
  884. const char *
  885. DeepScanLineInputFile::fileName () const
  886. {
  887. return _data->_streamData->is->fileName();
  888. }
  889. const Header &
  890. DeepScanLineInputFile::header () const
  891. {
  892. return _data->header;
  893. }
  894. int
  895. DeepScanLineInputFile::version () const
  896. {
  897. return _data->version;
  898. }
  899. void
  900. DeepScanLineInputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
  901. {
  902. Lock lock (*_data->_streamData);
  903. //
  904. // Check if the new frame buffer descriptor is
  905. // compatible with the image file header.
  906. //
  907. const ChannelList &channels = _data->header.channels();
  908. for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
  909. j != frameBuffer.end();
  910. ++j)
  911. {
  912. ChannelList::ConstIterator i = channels.find (j.name());
  913. if (i == channels.end())
  914. continue;
  915. if (i.channel().xSampling != j.slice().xSampling ||
  916. i.channel().ySampling != j.slice().ySampling)
  917. THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
  918. "of \"" << i.name() << "\" channel "
  919. "of input file \"" << fileName() << "\" are "
  920. "not compatible with the frame buffer's "
  921. "subsampling factors.");
  922. }
  923. //
  924. // Store the pixel sample count table.
  925. // (TODO) Support for different sampling rates?
  926. //
  927. const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
  928. if (sampleCountSlice.base == 0)
  929. {
  930. throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
  931. }
  932. else
  933. {
  934. _data->sampleCountSliceBase = sampleCountSlice.base;
  935. _data->sampleCountXStride = sampleCountSlice.xStride;
  936. _data->sampleCountYStride = sampleCountSlice.yStride;
  937. }
  938. //
  939. // Initialize the slice table for readPixels().
  940. //
  941. vector<InSliceInfo*> slices;
  942. ChannelList::ConstIterator i = channels.begin();
  943. for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
  944. j != frameBuffer.end();
  945. ++j)
  946. {
  947. while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
  948. {
  949. //
  950. // Channel i is present in the file but not
  951. // in the frame buffer; data for channel i
  952. // will be skipped during readPixels().
  953. //
  954. slices.push_back (new InSliceInfo (i.channel().type,
  955. NULL,
  956. i.channel().type,
  957. 0,
  958. 0,
  959. 0, // sampleStride
  960. i.channel().xSampling,
  961. i.channel().ySampling,
  962. false, // fill
  963. true, // skip
  964. 0.0)); // fillValue
  965. ++i;
  966. }
  967. bool fill = false;
  968. if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
  969. {
  970. //
  971. // Channel i is present in the frame buffer, but not in the file.
  972. // In the frame buffer, slice j will be filled with a default value.
  973. //
  974. fill = true;
  975. }
  976. slices.push_back (new InSliceInfo (j.slice().type,
  977. j.slice().base,
  978. fill? j.slice().type:
  979. i.channel().type,
  980. j.slice().xStride,
  981. j.slice().yStride,
  982. j.slice().sampleStride,
  983. j.slice().xSampling,
  984. j.slice().ySampling,
  985. fill,
  986. false, // skip
  987. j.slice().fillValue));
  988. if (i != channels.end() && !fill)
  989. ++i;
  990. }
  991. //
  992. // Client may want data to be filled in multiple arrays,
  993. // so we reset gotSampleCount and bytesPerLine.
  994. //
  995. for (long i = 0; i < _data->gotSampleCount.size(); i++)
  996. _data->gotSampleCount[i] = false;
  997. for (size_t i = 0; i < _data->bytesPerLine.size(); i++)
  998. _data->bytesPerLine[i] = 0;
  999. //
  1000. // Store the new frame buffer.
  1001. //
  1002. _data->frameBuffer = frameBuffer;
  1003. for (size_t i = 0; i < _data->slices.size(); i++)
  1004. delete _data->slices[i];
  1005. _data->slices = slices;
  1006. _data->frameBufferValid = true;
  1007. }
  1008. const DeepFrameBuffer &
  1009. DeepScanLineInputFile::frameBuffer () const
  1010. {
  1011. Lock lock (*_data->_streamData);
  1012. return _data->frameBuffer;
  1013. }
  1014. bool
  1015. DeepScanLineInputFile::isComplete () const
  1016. {
  1017. return _data->fileIsComplete;
  1018. }
  1019. void
  1020. DeepScanLineInputFile::readPixels (int scanLine1, int scanLine2)
  1021. {
  1022. try
  1023. {
  1024. Lock lock (*_data->_streamData);
  1025. if (_data->slices.size() == 0)
  1026. throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
  1027. "as pixel data destination.");
  1028. int scanLineMin = min (scanLine1, scanLine2);
  1029. int scanLineMax = max (scanLine1, scanLine2);
  1030. if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
  1031. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
  1032. "the image file's data window.");
  1033. for (int i = scanLineMin; i <= scanLineMax; i++)
  1034. {
  1035. if (_data->gotSampleCount[i - _data->minY] == false)
  1036. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line without "
  1037. "knowing the sample counts, please"
  1038. "read the sample counts first.");
  1039. }
  1040. //
  1041. // We impose a numbering scheme on the lineBuffers where the first
  1042. // scanline is contained in lineBuffer 1.
  1043. //
  1044. // Determine the first and last lineBuffer numbers in this scanline
  1045. // range. We always attempt to read the scanlines in the order that
  1046. // they are stored in the file.
  1047. //
  1048. int start, stop, dl;
  1049. if (_data->lineOrder == INCREASING_Y)
  1050. {
  1051. start = (scanLineMin - _data->minY) / _data->linesInBuffer;
  1052. stop = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
  1053. dl = 1;
  1054. }
  1055. else
  1056. {
  1057. start = (scanLineMax - _data->minY) / _data->linesInBuffer;
  1058. stop = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
  1059. dl = -1;
  1060. }
  1061. //
  1062. // Create a task group for all line buffer tasks. When the
  1063. // task group goes out of scope, the destructor waits until
  1064. // all tasks are complete.
  1065. //
  1066. {
  1067. TaskGroup taskGroup;
  1068. //
  1069. // Add the line buffer tasks.
  1070. //
  1071. // The tasks will execute in the order that they are created
  1072. // because we lock the line buffers during construction and the
  1073. // constructors are called by the main thread. Hence, in order
  1074. // for a successive task to execute the previous task which
  1075. // used that line buffer must have completed already.
  1076. //
  1077. for (int l = start; l != stop; l += dl)
  1078. {
  1079. ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
  1080. _data, l,
  1081. scanLineMin,
  1082. scanLineMax));
  1083. }
  1084. //
  1085. // finish all tasks
  1086. //
  1087. }
  1088. //
  1089. // Exeption handling:
  1090. //
  1091. // LineBufferTask::execute() may have encountered exceptions, but
  1092. // those exceptions occurred in another thread, not in the thread
  1093. // that is executing this call to ScanLineInputFile::readPixels().
  1094. // LineBufferTask::execute() has caught all exceptions and stored
  1095. // the exceptions' what() strings in the line buffers.
  1096. // Now we check if any line buffer contains a stored exception; if
  1097. // this is the case then we re-throw the exception in this thread.
  1098. // (It is possible that multiple line buffers contain stored
  1099. // exceptions. We re-throw the first exception we find and
  1100. // ignore all others.)
  1101. //
  1102. const string *exception = 0;
  1103. for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
  1104. {
  1105. LineBuffer *lineBuffer = _data->lineBuffers[i];
  1106. if (lineBuffer->hasException && !exception)
  1107. exception = &lineBuffer->exception;
  1108. lineBuffer->hasException = false;
  1109. }
  1110. if (exception)
  1111. throw IEX_NAMESPACE::IoExc (*exception);
  1112. }
  1113. catch (IEX_NAMESPACE::BaseExc &e)
  1114. {
  1115. REPLACE_EXC (e, "Error reading pixel data from image "
  1116. "file \"" << fileName() << "\". " << e);
  1117. throw;
  1118. }
  1119. }
  1120. void
  1121. DeepScanLineInputFile::readPixels (int scanLine)
  1122. {
  1123. readPixels (scanLine, scanLine);
  1124. }
  1125. void
  1126. DeepScanLineInputFile::rawPixelData (int firstScanLine,
  1127. char *pixelData,
  1128. Int64 &pixelDataSize)
  1129. {
  1130. int minY = lineBufferMinY
  1131. (firstScanLine, _data->minY, _data->linesInBuffer);
  1132. int lineBufferNumber = (minY - _data->minY) / _data->linesInBuffer;
  1133. Int64 lineOffset = _data->lineOffsets[lineBufferNumber];
  1134. if (lineOffset == 0)
  1135. THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
  1136. // enter the lock here - prevent another thread reseeking the file during read
  1137. Lock lock (*_data->_streamData);
  1138. //
  1139. // Seek to the start of the scan line in the file,
  1140. //
  1141. if (_data->_streamData->is->tellg() != _data->lineOffsets[lineBufferNumber])
  1142. _data->_streamData->is->seekg (lineOffset);
  1143. //
  1144. // Read the data block's header.
  1145. //
  1146. int yInFile;
  1147. //
  1148. // Read the part number when we are dealing with a multi-part file.
  1149. //
  1150. if (isMultiPart(_data->version))
  1151. {
  1152. int partNumber;
  1153. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, partNumber);
  1154. if (partNumber != _data->partNumber)
  1155. {
  1156. THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
  1157. << ", should be " << _data->partNumber << ".");
  1158. }
  1159. }
  1160. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, yInFile);
  1161. if (yInFile != minY)
  1162. throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
  1163. Int64 sampleCountTableSize;
  1164. Int64 packedDataSize;
  1165. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, sampleCountTableSize);
  1166. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, packedDataSize);
  1167. // total requirement for reading all the data
  1168. Int64 totalSizeRequired=28+sampleCountTableSize+packedDataSize;
  1169. bool big_enough = totalSizeRequired<=pixelDataSize;
  1170. pixelDataSize = totalSizeRequired;
  1171. // was the block we were given big enough?
  1172. if(!big_enough || pixelData==NULL)
  1173. {
  1174. // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
  1175. // in single part files)
  1176. if(!isMultiPart(_data->version))
  1177. {
  1178. if (_data->nextLineBufferMinY == minY)
  1179. _data->_streamData->is->seekg (lineOffset);
  1180. }
  1181. // leave lock here - bail before reading more data
  1182. return;
  1183. }
  1184. // copy the values we have read into the output block
  1185. *(int *) pixelData = yInFile;
  1186. *(Int64 *) (pixelData+4) =sampleCountTableSize;
  1187. *(Int64 *) (pixelData+12) = packedDataSize;
  1188. // didn't read the unpackedsize - do that now
  1189. Xdr::read<StreamIO> (*_data->_streamData->is, *(Int64 *) (pixelData+20));
  1190. // read the actual data
  1191. _data->_streamData->is->read(pixelData+28, sampleCountTableSize+packedDataSize);
  1192. // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
  1193. // in single part files)
  1194. if(!isMultiPart(_data->version))
  1195. {
  1196. if (_data->nextLineBufferMinY == minY)
  1197. _data->_streamData->is->seekg (lineOffset);
  1198. }
  1199. // leave lock here
  1200. }
  1201. void DeepScanLineInputFile::readPixels (const char* rawPixelData,
  1202. const DeepFrameBuffer& frameBuffer,
  1203. int scanLine1,
  1204. int scanLine2) const
  1205. {
  1206. //
  1207. // read header from block - already converted from Xdr to native format
  1208. //
  1209. int data_scanline = *(int *) rawPixelData;
  1210. Int64 sampleCountTableDataSize=*(Int64 *) (rawPixelData+4);
  1211. Int64 packedDataSize = *(Int64 *) (rawPixelData+12);
  1212. Int64 unpackedDataSize = *(Int64 *) (rawPixelData+20);
  1213. //
  1214. // Uncompress the data, if necessary
  1215. //
  1216. Compressor * decomp = NULL;
  1217. const char * uncompressed_data;
  1218. Compressor::Format format = Compressor::XDR;
  1219. if(packedDataSize <unpackedDataSize)
  1220. {
  1221. decomp = newCompressor(_data->header.compression(),
  1222. unpackedDataSize,
  1223. _data->header);
  1224. decomp->uncompress(rawPixelData+28+sampleCountTableDataSize,
  1225. packedDataSize,
  1226. data_scanline, uncompressed_data);
  1227. format = decomp->format();
  1228. }
  1229. else
  1230. {
  1231. //
  1232. // If the line is uncompressed, it's in XDR format,
  1233. // regardless of the compressor's output format.
  1234. //
  1235. format = Compressor::XDR;
  1236. uncompressed_data = rawPixelData+28+sampleCountTableDataSize;
  1237. }
  1238. int yStart, yStop, dy;
  1239. if (_data->lineOrder == INCREASING_Y)
  1240. {
  1241. yStart = scanLine1;
  1242. yStop = scanLine2 + 1;
  1243. dy = 1;
  1244. }
  1245. else
  1246. {
  1247. yStart = scanLine2;
  1248. yStop = scanLine1 - 1;
  1249. dy = -1;
  1250. }
  1251. const char* samplecount_base = frameBuffer.getSampleCountSlice().base;
  1252. int samplecount_xstride = frameBuffer.getSampleCountSlice().xStride;
  1253. int samplecount_ystride = frameBuffer.getSampleCountSlice().yStride;
  1254. //
  1255. // For each line within the block, get the count of bytes.
  1256. //
  1257. int minYInLineBuffer = data_scanline;
  1258. int maxYInLineBuffer = min(minYInLineBuffer + _data->linesInBuffer - 1, _data->maxY);
  1259. vector<size_t> bytesPerLine(1+_data->maxY-_data->minY);
  1260. bytesPe