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

/3rdparty/openexr/IlmImf/ImfInputFile.cpp

https://gitlab.com/generic-library/opencv
C++ | 648 lines | 420 code | 126 blank | 102 comment | 44 complexity | 230410b935a5fa1445906123e9be8caf 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 InputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfInputFile.h>
  40. #include <ImfScanLineInputFile.h>
  41. #include <ImfTiledInputFile.h>
  42. #include <ImfChannelList.h>
  43. #include <ImfMisc.h>
  44. #include <ImfStdIO.h>
  45. #include <ImfVersion.h>
  46. #include "ImathFun.h"
  47. #include "IlmThreadMutex.h"
  48. #include "Iex.h"
  49. #include "half.h"
  50. #include <fstream>
  51. #include <algorithm>
  52. namespace Imf {
  53. using Imath::Box2i;
  54. using Imath::divp;
  55. using Imath::modp;
  56. using IlmThread::Mutex;
  57. using IlmThread::Lock;
  58. //
  59. // Struct InputFile::Data stores things that will be
  60. // needed between calls to readPixels
  61. //
  62. struct InputFile::Data: public Mutex
  63. {
  64. Header header;
  65. int version;
  66. IStream * is;
  67. bool deleteStream;
  68. TiledInputFile * tFile;
  69. ScanLineInputFile * sFile;
  70. LineOrder lineOrder; // the file's lineorder
  71. int minY; // data window's min y coord
  72. int maxY; // data window's max x coord
  73. FrameBuffer tFileBuffer;
  74. FrameBuffer * cachedBuffer;
  75. int cachedTileY;
  76. int offset;
  77. int numThreads;
  78. Data (bool del, int numThreads);
  79. ~Data ();
  80. void deleteCachedBuffer();
  81. };
  82. InputFile::Data::Data (bool del, int numThreads):
  83. is (0),
  84. deleteStream (del),
  85. tFile (0),
  86. sFile (0),
  87. cachedBuffer (0),
  88. cachedTileY (-1),
  89. numThreads (numThreads)
  90. {
  91. // empty
  92. }
  93. InputFile::Data::~Data ()
  94. {
  95. delete tFile;
  96. delete sFile;
  97. if (deleteStream)
  98. delete is;
  99. deleteCachedBuffer();
  100. }
  101. void
  102. InputFile::Data::deleteCachedBuffer()
  103. {
  104. //
  105. // Delete the cached frame buffer, and all memory
  106. // allocated for the slices in the cached frameBuffer.
  107. //
  108. if (cachedBuffer)
  109. {
  110. for (FrameBuffer::Iterator k = cachedBuffer->begin();
  111. k != cachedBuffer->end();
  112. ++k)
  113. {
  114. Slice &s = k.slice();
  115. switch (s.type)
  116. {
  117. case UINT:
  118. delete [] (((unsigned int *)s.base) + offset);
  119. break;
  120. case HALF:
  121. delete [] ((half *)s.base + offset);
  122. break;
  123. case FLOAT:
  124. delete [] (((float *)s.base) + offset);
  125. break;
  126. }
  127. }
  128. //
  129. // delete the cached frame buffer
  130. //
  131. delete cachedBuffer;
  132. cachedBuffer = 0;
  133. }
  134. }
  135. namespace {
  136. void
  137. bufferedReadPixels (InputFile::Data* ifd, int scanLine1, int scanLine2)
  138. {
  139. //
  140. // bufferedReadPixels reads each row of tiles that intersect the
  141. // scan-line range (scanLine1 to scanLine2). The previous row of
  142. // tiles is cached in order to prevent redundent tile reads when
  143. // accessing scanlines sequentially.
  144. //
  145. int minY = std::min (scanLine1, scanLine2);
  146. int maxY = std::max (scanLine1, scanLine2);
  147. if (minY < ifd->minY || maxY > ifd->maxY)
  148. {
  149. throw Iex::ArgExc ("Tried to read scan line outside "
  150. "the image file's data window.");
  151. }
  152. //
  153. // The minimum and maximum y tile coordinates that intersect this
  154. // scanline range
  155. //
  156. int minDy = (minY - ifd->minY) / ifd->tFile->tileYSize();
  157. int maxDy = (maxY - ifd->minY) / ifd->tFile->tileYSize();
  158. //
  159. // Figure out which one is first in the file so we can read without seeking
  160. //
  161. int yStart, yEnd, yStep;
  162. if (ifd->lineOrder == DECREASING_Y)
  163. {
  164. yStart = maxDy;
  165. yEnd = minDy - 1;
  166. yStep = -1;
  167. }
  168. else
  169. {
  170. yStart = minDy;
  171. yEnd = maxDy + 1;
  172. yStep = 1;
  173. }
  174. //
  175. // the number of pixels in a row of tiles
  176. //
  177. Box2i levelRange = ifd->tFile->dataWindowForLevel(0);
  178. //
  179. // Read the tiles into our temporary framebuffer and copy them into
  180. // the user's buffer
  181. //
  182. for (int j = yStart; j != yEnd; j += yStep)
  183. {
  184. Box2i tileRange = ifd->tFile->dataWindowForTile (0, j, 0);
  185. int minYThisRow = std::max (minY, tileRange.min.y);
  186. int maxYThisRow = std::min (maxY, tileRange.max.y);
  187. if (j != ifd->cachedTileY)
  188. {
  189. //
  190. // We don't have any valid buffered info, so we need to read in
  191. // from the file.
  192. //
  193. ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j);
  194. ifd->cachedTileY = j;
  195. }
  196. //
  197. // Copy the data from our cached framebuffer into the user's
  198. // framebuffer.
  199. //
  200. for (FrameBuffer::ConstIterator k = ifd->cachedBuffer->begin();
  201. k != ifd->cachedBuffer->end();
  202. ++k)
  203. {
  204. Slice fromSlice = k.slice(); // slice to write from
  205. Slice toSlice = ifd->tFileBuffer[k.name()]; // slice to write to
  206. char *fromPtr, *toPtr;
  207. int size = pixelTypeSize (toSlice.type);
  208. int xStart = levelRange.min.x;
  209. int yStart = minYThisRow;
  210. while (modp (xStart, toSlice.xSampling) != 0)
  211. ++xStart;
  212. while (modp (yStart, toSlice.ySampling) != 0)
  213. ++yStart;
  214. for (int y = yStart;
  215. y <= maxYThisRow;
  216. y += toSlice.ySampling)
  217. {
  218. //
  219. // Set the pointers to the start of the y scanline in
  220. // this row of tiles
  221. //
  222. fromPtr = fromSlice.base +
  223. (y - tileRange.min.y) * fromSlice.yStride +
  224. xStart * fromSlice.xStride;
  225. toPtr = toSlice.base +
  226. divp (y, toSlice.ySampling) * toSlice.yStride +
  227. divp (xStart, toSlice.xSampling) * toSlice.xStride;
  228. //
  229. // Copy all pixels for the scanline in this row of tiles
  230. //
  231. for (int x = xStart;
  232. x <= levelRange.max.x;
  233. x += toSlice.xSampling)
  234. {
  235. for (size_t i = 0; i < size; ++i)
  236. toPtr[i] = fromPtr[i];
  237. fromPtr += fromSlice.xStride * toSlice.xSampling;
  238. toPtr += toSlice.xStride;
  239. }
  240. }
  241. }
  242. }
  243. }
  244. } // namespace
  245. InputFile::InputFile (const char fileName[], int numThreads):
  246. _data (new Data (true, numThreads))
  247. {
  248. try
  249. {
  250. _data->is = new StdIFStream (fileName);
  251. initialize();
  252. }
  253. catch (Iex::BaseExc &e)
  254. {
  255. delete _data;
  256. REPLACE_EXC (e, "Cannot read image file "
  257. "\"" << fileName << "\". " << e);
  258. throw;
  259. }
  260. catch (...)
  261. {
  262. delete _data;
  263. throw;
  264. }
  265. }
  266. InputFile::InputFile (IStream &is, int numThreads):
  267. _data (new Data (false, numThreads))
  268. {
  269. try
  270. {
  271. _data->is = &is;
  272. initialize();
  273. }
  274. catch (Iex::BaseExc &e)
  275. {
  276. delete _data;
  277. REPLACE_EXC (e, "Cannot read image file "
  278. "\"" << is.fileName() << "\". " << e);
  279. throw;
  280. }
  281. catch (...)
  282. {
  283. delete _data;
  284. throw;
  285. }
  286. }
  287. void
  288. InputFile::initialize ()
  289. {
  290. _data->header.readFrom (*_data->is, _data->version);
  291. _data->header.sanityCheck (isTiled (_data->version));
  292. if (isTiled (_data->version))
  293. {
  294. _data->lineOrder = _data->header.lineOrder();
  295. //
  296. // Save the dataWindow information
  297. //
  298. const Box2i &dataWindow = _data->header.dataWindow();
  299. _data->minY = dataWindow.min.y;
  300. _data->maxY = dataWindow.max.y;
  301. _data->tFile = new TiledInputFile (_data->header,
  302. _data->is,
  303. _data->version,
  304. _data->numThreads);
  305. }
  306. else
  307. {
  308. _data->sFile = new ScanLineInputFile (_data->header,
  309. _data->is,
  310. _data->numThreads);
  311. }
  312. }
  313. InputFile::~InputFile ()
  314. {
  315. delete _data;
  316. }
  317. const char *
  318. InputFile::fileName () const
  319. {
  320. return _data->is->fileName();
  321. }
  322. const Header &
  323. InputFile::header () const
  324. {
  325. return _data->header;
  326. }
  327. int
  328. InputFile::version () const
  329. {
  330. return _data->version;
  331. }
  332. void
  333. InputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
  334. {
  335. if (isTiled (_data->version))
  336. {
  337. Lock lock (*_data);
  338. //
  339. // We must invalidate the cached buffer if the new frame
  340. // buffer has a different set of channels than the old
  341. // frame buffer, or if the type of a channel has changed.
  342. //
  343. const FrameBuffer &oldFrameBuffer = _data->tFileBuffer;
  344. FrameBuffer::ConstIterator i = oldFrameBuffer.begin();
  345. FrameBuffer::ConstIterator j = frameBuffer.begin();
  346. while (i != oldFrameBuffer.end() && j != frameBuffer.end())
  347. {
  348. if (strcmp (i.name(), j.name()) || i.slice().type != j.slice().type)
  349. break;
  350. ++i;
  351. ++j;
  352. }
  353. if (i != oldFrameBuffer.end() || j != frameBuffer.end())
  354. {
  355. //
  356. // Invalidate the cached buffer.
  357. //
  358. _data->deleteCachedBuffer ();
  359. _data->cachedTileY = -1;
  360. //
  361. // Create new a cached frame buffer. It can hold a single
  362. // row of tiles. The cached buffer can be reused for each
  363. // row of tiles because we set the yTileCoords parameter of
  364. // each Slice to true.
  365. //
  366. const Box2i &dataWindow = _data->header.dataWindow();
  367. _data->cachedBuffer = new FrameBuffer();
  368. _data->offset = dataWindow.min.x;
  369. int tileRowSize = (dataWindow.max.x - dataWindow.min.x + 1) *
  370. _data->tFile->tileYSize();
  371. for (FrameBuffer::ConstIterator k = frameBuffer.begin();
  372. k != frameBuffer.end();
  373. ++k)
  374. {
  375. Slice s = k.slice();
  376. switch (s.type)
  377. {
  378. case UINT:
  379. _data->cachedBuffer->insert
  380. (k.name(),
  381. Slice (UINT,
  382. (char *)(new unsigned int[tileRowSize] -
  383. _data->offset),
  384. sizeof (unsigned int),
  385. sizeof (unsigned int) *
  386. _data->tFile->levelWidth(0),
  387. 1, 1,
  388. s.fillValue,
  389. false, true));
  390. break;
  391. case HALF:
  392. _data->cachedBuffer->insert
  393. (k.name(),
  394. Slice (HALF,
  395. (char *)(new half[tileRowSize] -
  396. _data->offset),
  397. sizeof (half),
  398. sizeof (half) *
  399. _data->tFile->levelWidth(0),
  400. 1, 1,
  401. s.fillValue,
  402. false, true));
  403. break;
  404. case FLOAT:
  405. _data->cachedBuffer->insert
  406. (k.name(),
  407. Slice (FLOAT,
  408. (char *)(new float[tileRowSize] -
  409. _data->offset),
  410. sizeof(float),
  411. sizeof(float) *
  412. _data->tFile->levelWidth(0),
  413. 1, 1,
  414. s.fillValue,
  415. false, true));
  416. break;
  417. default:
  418. throw Iex::ArgExc ("Unknown pixel data type.");
  419. }
  420. }
  421. _data->tFile->setFrameBuffer (*_data->cachedBuffer);
  422. }
  423. _data->tFileBuffer = frameBuffer;
  424. }
  425. else
  426. {
  427. _data->sFile->setFrameBuffer (frameBuffer);
  428. }
  429. }
  430. const FrameBuffer &
  431. InputFile::frameBuffer () const
  432. {
  433. if (isTiled (_data->version))
  434. {
  435. Lock lock (*_data);
  436. return _data->tFileBuffer;
  437. }
  438. else
  439. {
  440. return _data->sFile->frameBuffer();
  441. }
  442. }
  443. bool
  444. InputFile::isComplete () const
  445. {
  446. if (isTiled (_data->version))
  447. return _data->tFile->isComplete();
  448. else
  449. return _data->sFile->isComplete();
  450. }
  451. void
  452. InputFile::readPixels (int scanLine1, int scanLine2)
  453. {
  454. if (isTiled (_data->version))
  455. {
  456. Lock lock (*_data);
  457. bufferedReadPixels (_data, scanLine1, scanLine2);
  458. }
  459. else
  460. {
  461. _data->sFile->readPixels (scanLine1, scanLine2);
  462. }
  463. }
  464. void
  465. InputFile::readPixels (int scanLine)
  466. {
  467. readPixels (scanLine, scanLine);
  468. }
  469. void
  470. InputFile::rawPixelData (int firstScanLine,
  471. const char *&pixelData,
  472. int &pixelDataSize)
  473. {
  474. try
  475. {
  476. if (isTiled (_data->version))
  477. {
  478. throw Iex::ArgExc ("Tried to read a raw scanline "
  479. "from a tiled image.");
  480. }
  481. _data->sFile->rawPixelData (firstScanLine, pixelData, pixelDataSize);
  482. }
  483. catch (Iex::BaseExc &e)
  484. {
  485. REPLACE_EXC (e, "Error reading pixel data from image "
  486. "file \"" << fileName() << "\". " << e);
  487. throw;
  488. }
  489. }
  490. void
  491. InputFile::rawTileData (int &dx, int &dy,
  492. int &lx, int &ly,
  493. const char *&pixelData,
  494. int &pixelDataSize)
  495. {
  496. try
  497. {
  498. if (!isTiled (_data->version))
  499. {
  500. throw Iex::ArgExc ("Tried to read a raw tile "
  501. "from a scanline-based image.");
  502. }
  503. _data->tFile->rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize);
  504. }
  505. catch (Iex::BaseExc &e)
  506. {
  507. REPLACE_EXC (e, "Error reading tile data from image "
  508. "file \"" << fileName() << "\". " << e);
  509. throw;
  510. }
  511. }
  512. TiledInputFile*
  513. InputFile::tFile()
  514. {
  515. if (!isTiled (_data->version))
  516. {
  517. throw Iex::ArgExc ("Cannot get a TiledInputFile pointer "
  518. "from an InputFile that is not tiled.");
  519. }
  520. return _data->tFile;
  521. }
  522. } // namespace Imf