/src/FreeImage/Source/OpenEXR/IlmImf/ImfPizCompressor.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 666 lines · 412 code · 141 blank · 113 comment · 71 complexity · 9966825948d503c00bcc5274269684b4 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 PizCompressor
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include <ImfPizCompressor.h>
  40. #include <ImfHeader.h>
  41. #include <ImfChannelList.h>
  42. #include <ImfHuf.h>
  43. #include <ImfWav.h>
  44. #include <ImfMisc.h>
  45. #include <ImfCheckedArithmetic.h>
  46. #include <ImathFun.h>
  47. #include <ImathBox.h>
  48. #include <Iex.h>
  49. #include <ImfIO.h>
  50. #include <ImfXdr.h>
  51. #include <ImfAutoArray.h>
  52. #include <string.h>
  53. #include <assert.h>
  54. namespace Imf {
  55. using Imath::divp;
  56. using Imath::modp;
  57. using Imath::Box2i;
  58. using Imath::V2i;
  59. using Iex::InputExc;
  60. namespace {
  61. //
  62. // Functions to compress the range of values in the pixel data
  63. //
  64. const int USHORT_RANGE = (1 << 16);
  65. const int BITMAP_SIZE = (USHORT_RANGE >> 3);
  66. void
  67. bitmapFromData (const unsigned short data[/*nData*/],
  68. int nData,
  69. unsigned char bitmap[BITMAP_SIZE],
  70. unsigned short &minNonZero,
  71. unsigned short &maxNonZero)
  72. {
  73. for (int i = 0; i < BITMAP_SIZE; ++i)
  74. bitmap[i] = 0;
  75. for (int i = 0; i < nData; ++i)
  76. bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
  77. bitmap[0] &= ~1; // zero is not explicitly stored in
  78. // the bitmap; we assume that the
  79. // data always contain zeroes
  80. minNonZero = BITMAP_SIZE - 1;
  81. maxNonZero = 0;
  82. for (int i = 0; i < BITMAP_SIZE; ++i)
  83. {
  84. if (bitmap[i])
  85. {
  86. if (minNonZero > i)
  87. minNonZero = i;
  88. if (maxNonZero < i)
  89. maxNonZero = i;
  90. }
  91. }
  92. }
  93. unsigned short
  94. forwardLutFromBitmap (const unsigned char bitmap[BITMAP_SIZE],
  95. unsigned short lut[USHORT_RANGE])
  96. {
  97. int k = 0;
  98. for (int i = 0; i < USHORT_RANGE; ++i)
  99. {
  100. if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
  101. lut[i] = k++;
  102. else
  103. lut[i] = 0;
  104. }
  105. return k - 1; // maximum value stored in lut[],
  106. } // i.e. number of ones in bitmap minus 1
  107. unsigned short
  108. reverseLutFromBitmap (const unsigned char bitmap[BITMAP_SIZE],
  109. unsigned short lut[USHORT_RANGE])
  110. {
  111. int k = 0;
  112. for (int i = 0; i < USHORT_RANGE; ++i)
  113. {
  114. if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
  115. lut[k++] = i;
  116. }
  117. int n = k - 1;
  118. while (k < USHORT_RANGE)
  119. lut[k++] = 0;
  120. return n; // maximum k where lut[k] is non-zero,
  121. } // i.e. number of ones in bitmap minus 1
  122. void
  123. applyLut (const unsigned short lut[USHORT_RANGE],
  124. unsigned short data[/*nData*/],
  125. int nData)
  126. {
  127. for (int i = 0; i < nData; ++i)
  128. data[i] = lut[data[i]];
  129. }
  130. } // namespace
  131. struct PizCompressor::ChannelData
  132. {
  133. unsigned short * start;
  134. unsigned short * end;
  135. int nx;
  136. int ny;
  137. int ys;
  138. int size;
  139. };
  140. PizCompressor::PizCompressor
  141. (const Header &hdr,
  142. size_t maxScanLineSize,
  143. size_t numScanLines)
  144. :
  145. Compressor (hdr),
  146. _maxScanLineSize (maxScanLineSize),
  147. _format (XDR),
  148. _numScanLines (numScanLines),
  149. _tmpBuffer (0),
  150. _outBuffer (0),
  151. _numChans (0),
  152. _channels (hdr.channels()),
  153. _channelData (0)
  154. {
  155. size_t tmpBufferSize =
  156. uiMult (maxScanLineSize, numScanLines) / 2;
  157. size_t outBufferSize =
  158. uiAdd (uiMult (maxScanLineSize, numScanLines),
  159. size_t (65536 + 8192));
  160. _tmpBuffer = new unsigned short
  161. [checkArraySize (tmpBufferSize, sizeof (unsigned short))];
  162. _outBuffer = new char [outBufferSize];
  163. const ChannelList &channels = header().channels();
  164. bool onlyHalfChannels = true;
  165. for (ChannelList::ConstIterator c = channels.begin();
  166. c != channels.end();
  167. ++c)
  168. {
  169. _numChans++;
  170. assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
  171. if (c.channel().type != HALF)
  172. onlyHalfChannels = false;
  173. }
  174. _channelData = new ChannelData[_numChans];
  175. const Box2i &dataWindow = hdr.dataWindow();
  176. _minX = dataWindow.min.x;
  177. _maxX = dataWindow.max.x;
  178. _maxY = dataWindow.max.y;
  179. //
  180. // We can support uncompressed data in the machine's native format
  181. // if all image channels are of type HALF, and if the Xdr and the
  182. // native represenations of a half have the same size.
  183. //
  184. if (onlyHalfChannels && (sizeof (half) == pixelTypeSize (HALF)))
  185. _format = NATIVE;
  186. }
  187. PizCompressor::~PizCompressor ()
  188. {
  189. delete [] _tmpBuffer;
  190. delete [] _outBuffer;
  191. delete [] _channelData;
  192. }
  193. int
  194. PizCompressor::numScanLines () const
  195. {
  196. return _numScanLines;
  197. }
  198. Compressor::Format
  199. PizCompressor::format () const
  200. {
  201. return _format;
  202. }
  203. int
  204. PizCompressor::compress (const char *inPtr,
  205. int inSize,
  206. int minY,
  207. const char *&outPtr)
  208. {
  209. return compress (inPtr,
  210. inSize,
  211. Box2i (V2i (_minX, minY),
  212. V2i (_maxX, minY + numScanLines() - 1)),
  213. outPtr);
  214. }
  215. int
  216. PizCompressor::compressTile (const char *inPtr,
  217. int inSize,
  218. Imath::Box2i range,
  219. const char *&outPtr)
  220. {
  221. return compress (inPtr, inSize, range, outPtr);
  222. }
  223. int
  224. PizCompressor::uncompress (const char *inPtr,
  225. int inSize,
  226. int minY,
  227. const char *&outPtr)
  228. {
  229. return uncompress (inPtr,
  230. inSize,
  231. Box2i (V2i (_minX, minY),
  232. V2i (_maxX, minY + numScanLines() - 1)),
  233. outPtr);
  234. }
  235. int
  236. PizCompressor::uncompressTile (const char *inPtr,
  237. int inSize,
  238. Imath::Box2i range,
  239. const char *&outPtr)
  240. {
  241. return uncompress (inPtr, inSize, range, outPtr);
  242. }
  243. int
  244. PizCompressor::compress (const char *inPtr,
  245. int inSize,
  246. Imath::Box2i range,
  247. const char *&outPtr)
  248. {
  249. //
  250. // This is the compress function which is used by both the tiled and
  251. // scanline compression routines.
  252. //
  253. //
  254. // Special case ­- empty input buffer
  255. //
  256. if (inSize == 0)
  257. {
  258. outPtr = _outBuffer;
  259. return 0;
  260. }
  261. //
  262. // Rearrange the pixel data so that the wavelet
  263. // and Huffman encoders can process them easily.
  264. //
  265. // The wavelet and Huffman encoders both handle only
  266. // 16-bit data, so 32-bit data must be split into smaller
  267. // pieces. We treat each 32-bit channel (UINT, FLOAT) as
  268. // two interleaved 16-bit channels.
  269. //
  270. int minX = range.min.x;
  271. int maxX = range.max.x;
  272. int minY = range.min.y;
  273. int maxY = range.max.y;
  274. if (maxY > _maxY)
  275. maxY = _maxY;
  276. if (maxX > _maxX)
  277. maxX = _maxX;
  278. unsigned short *tmpBufferEnd = _tmpBuffer;
  279. int i = 0;
  280. for (ChannelList::ConstIterator c = _channels.begin();
  281. c != _channels.end();
  282. ++c, ++i)
  283. {
  284. ChannelData &cd = _channelData[i];
  285. cd.start = tmpBufferEnd;
  286. cd.end = cd.start;
  287. cd.nx = numSamples (c.channel().xSampling, minX, maxX);
  288. cd.ny = numSamples (c.channel().ySampling, minY, maxY);
  289. cd.ys = c.channel().ySampling;
  290. cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
  291. tmpBufferEnd += cd.nx * cd.ny * cd.size;
  292. }
  293. if (_format == XDR)
  294. {
  295. //
  296. // Machine-independent (Xdr) data format
  297. //
  298. for (int y = minY; y <= maxY; ++y)
  299. {
  300. for (int i = 0; i < _numChans; ++i)
  301. {
  302. ChannelData &cd = _channelData[i];
  303. if (modp (y, cd.ys) != 0)
  304. continue;
  305. for (int x = cd.nx * cd.size; x > 0; --x)
  306. {
  307. Xdr::read <CharPtrIO> (inPtr, *cd.end);
  308. ++cd.end;
  309. }
  310. }
  311. }
  312. }
  313. else
  314. {
  315. //
  316. // Native, machine-dependent data format
  317. //
  318. for (int y = minY; y <= maxY; ++y)
  319. {
  320. for (int i = 0; i < _numChans; ++i)
  321. {
  322. ChannelData &cd = _channelData[i];
  323. if (modp (y, cd.ys) != 0)
  324. continue;
  325. int n = cd.nx * cd.size;
  326. memcpy (cd.end, inPtr, n * sizeof (unsigned short));
  327. inPtr += n * sizeof (unsigned short);
  328. cd.end += n;
  329. }
  330. }
  331. }
  332. #if defined (DEBUG)
  333. for (int i = 1; i < _numChans; ++i)
  334. assert (_channelData[i-1].end == _channelData[i].start);
  335. assert (_channelData[_numChans-1].end == tmpBufferEnd);
  336. #endif
  337. //
  338. // Compress the range of the pixel data
  339. //
  340. AutoArray <unsigned char, BITMAP_SIZE> bitmap;
  341. unsigned short minNonZero;
  342. unsigned short maxNonZero;
  343. bitmapFromData (_tmpBuffer,
  344. tmpBufferEnd - _tmpBuffer,
  345. bitmap,
  346. minNonZero, maxNonZero);
  347. AutoArray <unsigned short, USHORT_RANGE> lut;
  348. unsigned short maxValue = forwardLutFromBitmap (bitmap, lut);
  349. applyLut (lut, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
  350. //
  351. // Store range compression info in _outBuffer
  352. //
  353. char *buf = _outBuffer;
  354. Xdr::write <CharPtrIO> (buf, minNonZero);
  355. Xdr::write <CharPtrIO> (buf, maxNonZero);
  356. if (minNonZero <= maxNonZero)
  357. {
  358. Xdr::write <CharPtrIO> (buf, (char *) &bitmap[0] + minNonZero,
  359. maxNonZero - minNonZero + 1);
  360. }
  361. //
  362. // Apply wavelet encoding
  363. //
  364. for (int i = 0; i < _numChans; ++i)
  365. {
  366. ChannelData &cd = _channelData[i];
  367. for (int j = 0; j < cd.size; ++j)
  368. {
  369. wav2Encode (cd.start + j,
  370. cd.nx, cd.size,
  371. cd.ny, cd.nx * cd.size,
  372. maxValue);
  373. }
  374. }
  375. //
  376. // Apply Huffman encoding; append the result to _outBuffer
  377. //
  378. char *lengthPtr = buf;
  379. Xdr::write <CharPtrIO> (buf, int(0));
  380. int length = hufCompress (_tmpBuffer, tmpBufferEnd - _tmpBuffer, buf);
  381. Xdr::write <CharPtrIO> (lengthPtr, length);
  382. outPtr = _outBuffer;
  383. return buf - _outBuffer + length;
  384. }
  385. int
  386. PizCompressor::uncompress (const char *inPtr,
  387. int inSize,
  388. Imath::Box2i range,
  389. const char *&outPtr)
  390. {
  391. //
  392. // This is the cunompress function which is used by both the tiled and
  393. // scanline decompression routines.
  394. //
  395. //
  396. // Special case - empty input buffer
  397. //
  398. if (inSize == 0)
  399. {
  400. outPtr = _outBuffer;
  401. return 0;
  402. }
  403. //
  404. // Determine the layout of the compressed pixel data
  405. //
  406. int minX = range.min.x;
  407. int maxX = range.max.x;
  408. int minY = range.min.y;
  409. int maxY = range.max.y;
  410. if (maxY > _maxY)
  411. maxY = _maxY;
  412. if (maxX > _maxX)
  413. maxX = _maxX;
  414. unsigned short *tmpBufferEnd = _tmpBuffer;
  415. int i = 0;
  416. for (ChannelList::ConstIterator c = _channels.begin();
  417. c != _channels.end();
  418. ++c, ++i)
  419. {
  420. ChannelData &cd = _channelData[i];
  421. cd.start = tmpBufferEnd;
  422. cd.end = cd.start;
  423. cd.nx = numSamples (c.channel().xSampling, minX, maxX);
  424. cd.ny = numSamples (c.channel().ySampling, minY, maxY);
  425. cd.ys = c.channel().ySampling;
  426. cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
  427. tmpBufferEnd += cd.nx * cd.ny * cd.size;
  428. }
  429. //
  430. // Read range compression data
  431. //
  432. unsigned short minNonZero;
  433. unsigned short maxNonZero;
  434. AutoArray <unsigned char, BITMAP_SIZE> bitmap;
  435. memset (bitmap, 0, sizeof (unsigned char) * BITMAP_SIZE);
  436. Xdr::read <CharPtrIO> (inPtr, minNonZero);
  437. Xdr::read <CharPtrIO> (inPtr, maxNonZero);
  438. if (maxNonZero >= BITMAP_SIZE)
  439. {
  440. throw InputExc ("Error in header for PIZ-compressed data "
  441. "(invalid bitmap size).");
  442. }
  443. if (minNonZero <= maxNonZero)
  444. {
  445. Xdr::read <CharPtrIO> (inPtr, (char *) &bitmap[0] + minNonZero,
  446. maxNonZero - minNonZero + 1);
  447. }
  448. AutoArray <unsigned short, USHORT_RANGE> lut;
  449. unsigned short maxValue = reverseLutFromBitmap (bitmap, lut);
  450. //
  451. // Huffman decoding
  452. //
  453. int length;
  454. Xdr::read <CharPtrIO> (inPtr, length);
  455. hufUncompress (inPtr, length, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
  456. //
  457. // Wavelet decoding
  458. //
  459. for (int i = 0; i < _numChans; ++i)
  460. {
  461. ChannelData &cd = _channelData[i];
  462. for (int j = 0; j < cd.size; ++j)
  463. {
  464. wav2Decode (cd.start + j,
  465. cd.nx, cd.size,
  466. cd.ny, cd.nx * cd.size,
  467. maxValue);
  468. }
  469. }
  470. //
  471. // Expand the pixel data to their original range
  472. //
  473. applyLut (lut, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
  474. //
  475. // Rearrange the pixel data into the format expected by the caller.
  476. //
  477. char *outEnd = _outBuffer;
  478. if (_format == XDR)
  479. {
  480. //
  481. // Machine-independent (Xdr) data format
  482. //
  483. for (int y = minY; y <= maxY; ++y)
  484. {
  485. for (int i = 0; i < _numChans; ++i)
  486. {
  487. ChannelData &cd = _channelData[i];
  488. if (modp (y, cd.ys) != 0)
  489. continue;
  490. for (int x = cd.nx * cd.size; x > 0; --x)
  491. {
  492. Xdr::write <CharPtrIO> (outEnd, *cd.end);
  493. ++cd.end;
  494. }
  495. }
  496. }
  497. }
  498. else
  499. {
  500. //
  501. // Native, machine-dependent data format
  502. //
  503. for (int y = minY; y <= maxY; ++y)
  504. {
  505. for (int i = 0; i < _numChans; ++i)
  506. {
  507. ChannelData &cd = _channelData[i];
  508. if (modp (y, cd.ys) != 0)
  509. continue;
  510. int n = cd.nx * cd.size;
  511. memcpy (outEnd, cd.end, n * sizeof (unsigned short));
  512. outEnd += n * sizeof (unsigned short);
  513. cd.end += n;
  514. }
  515. }
  516. }
  517. #if defined (DEBUG)
  518. for (int i = 1; i < _numChans; ++i)
  519. assert (_channelData[i-1].end == _channelData[i].start);
  520. assert (_channelData[_numChans-1].end == tmpBufferEnd);
  521. #endif
  522. outPtr = _outBuffer;
  523. return outEnd - _outBuffer;
  524. }
  525. } // namespace Imf