ImfPizCompressor.cpp 15 KB

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