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

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 1069 lines · 598 code · 192 blank · 279 comment · 105 complexity · 4afc4f15da69d57a2cb9dfb201c3681e MD5 · raw file

  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2006, 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 B44Compressor
  37. //
  38. // This compressor is lossy for HALF channels; the compression rate
  39. // is fixed at 32/14 (approximately 2.28). FLOAT and UINT channels
  40. // are not compressed; their data are preserved exactly.
  41. //
  42. // Each HALF channel is split into blocks of 4 by 4 pixels. An
  43. // uncompressed block occupies 32 bytes, which are re-interpreted
  44. // as sixteen 16-bit unsigned integers, t[0] ... t[15]. Compression
  45. // shrinks the block to 14 bytes. The compressed 14-byte block
  46. // contains
  47. //
  48. // - t[0]
  49. //
  50. // - a 6-bit shift value
  51. //
  52. // - 15 densely packed 6-bit values, r[0] ... r[14], which are
  53. // computed by subtracting adjacent pixel values and right-
  54. // shifting the differences according to the stored shift value.
  55. //
  56. // Differences between adjacent pixels are computed according
  57. // to the following diagram:
  58. //
  59. // 0 --------> 1 --------> 2 --------> 3
  60. // | 3 7 11
  61. // |
  62. // | 0
  63. // |
  64. // v
  65. // 4 --------> 5 --------> 6 --------> 7
  66. // | 4 8 12
  67. // |
  68. // | 1
  69. // |
  70. // v
  71. // 8 --------> 9 --------> 10 --------> 11
  72. // | 5 9 13
  73. // |
  74. // | 2
  75. // |
  76. // v
  77. // 12 --------> 13 --------> 14 --------> 15
  78. // 6 10 14
  79. //
  80. // Here
  81. //
  82. // 5 ---------> 6
  83. // 8
  84. //
  85. // means that r[8] is the difference between t[5] and t[6].
  86. //
  87. // - optionally, a 4-by-4 pixel block where all pixels have the
  88. // same value can be treated as a special case, where the
  89. // compressed block contains only 3 instead of 14 bytes:
  90. // t[0], followed by an "impossible" 6-bit shift value and
  91. // two padding bits.
  92. //
  93. // This compressor can handle positive and negative pixel values.
  94. // NaNs and infinities are replaced with zeroes before compression.
  95. //
  96. //-----------------------------------------------------------------------------
  97. #include <ImfB44Compressor.h>
  98. #include <ImfHeader.h>
  99. #include <ImfChannelList.h>
  100. #include <ImfMisc.h>
  101. #include <ImfCheckedArithmetic.h>
  102. #include <ImathFun.h>
  103. #include <ImathBox.h>
  104. #include <Iex.h>
  105. #include <ImfIO.h>
  106. #include <ImfXdr.h>
  107. #include <string.h>
  108. #include <assert.h>
  109. #include <algorithm>
  110. namespace Imf {
  111. using Imath::divp;
  112. using Imath::modp;
  113. using Imath::Box2i;
  114. using Imath::V2i;
  115. using std::min;
  116. namespace {
  117. //
  118. // Lookup tables for
  119. // y = exp (x / 8)
  120. // and
  121. // x = 8 * log (y)
  122. //
  123. #include "b44ExpLogTable.h"
  124. inline void
  125. convertFromLinear (unsigned short s[16])
  126. {
  127. for (int i = 0; i < 16; ++i)
  128. s[i] = expTable[s[i]];
  129. }
  130. inline void
  131. convertToLinear (unsigned short s[16])
  132. {
  133. for (int i = 0; i < 16; ++i)
  134. s[i] = logTable[s[i]];
  135. }
  136. inline int
  137. shiftAndRound (int x, int shift)
  138. {
  139. //
  140. // Compute
  141. //
  142. // y = x * pow (2, -shift),
  143. //
  144. // then round y to the nearest integer.
  145. // In case of a tie, where y is exactly
  146. // halfway between two integers, round
  147. // to the even one.
  148. //
  149. x <<= 1;
  150. int a = (1 << shift) - 1;
  151. shift += 1;
  152. int b = (x >> shift) & 1;
  153. return (x + a + b) >> shift;
  154. }
  155. int
  156. pack (const unsigned short s[16],
  157. unsigned char b[14],
  158. bool optFlatFields,
  159. bool exactMax)
  160. {
  161. //
  162. // Pack a block of 4 by 4 16-bit pixels (32 bytes) into
  163. // either 14 or 3 bytes.
  164. //
  165. //
  166. // Integers s[0] ... s[15] represent floating-point numbers
  167. // in what is essentially a sign-magnitude format. Convert
  168. // s[0] .. s[15] into a new set of integers, t[0] ... t[15],
  169. // such that if t[i] is greater than t[j], the floating-point
  170. // number that corresponds to s[i] is always greater than
  171. // the floating-point number that corresponds to s[j].
  172. //
  173. // Also, replace any bit patterns that represent NaNs or
  174. // infinities with bit patterns that represent floating-point
  175. // zeroes.
  176. //
  177. // bit pattern floating-point bit pattern
  178. // in s[i] value in t[i]
  179. //
  180. // 0x7fff NAN 0x8000
  181. // 0x7ffe NAN 0x8000
  182. // ... ...
  183. // 0x7c01 NAN 0x8000
  184. // 0x7c00 +infinity 0x8000
  185. // 0x7bff +HALF_MAX 0xfbff
  186. // 0x7bfe 0xfbfe
  187. // 0x7bfd 0xfbfd
  188. // ... ...
  189. // 0x0002 +2 * HALF_MIN 0x8002
  190. // 0x0001 +HALF_MIN 0x8001
  191. // 0x0000 +0.0 0x8000
  192. // 0x8000 -0.0 0x7fff
  193. // 0x8001 -HALF_MIN 0x7ffe
  194. // 0x8002 -2 * HALF_MIN 0x7ffd
  195. // ... ...
  196. // 0xfbfd 0x0f02
  197. // 0xfbfe 0x0401
  198. // 0xfbff -HALF_MAX 0x0400
  199. // 0xfc00 -infinity 0x8000
  200. // 0xfc01 NAN 0x8000
  201. // ... ...
  202. // 0xfffe NAN 0x8000
  203. // 0xffff NAN 0x8000
  204. //
  205. unsigned short t[16];
  206. for (int i = 0; i < 16; ++i)
  207. {
  208. if ((s[i] & 0x7c00) == 0x7c00)
  209. t[i] = 0x8000;
  210. else if (s[i] & 0x8000)
  211. t[i] = ~s[i];
  212. else
  213. t[i] = s[i] | 0x8000;
  214. }
  215. //
  216. // Find the maximum, tMax, of t[0] ... t[15].
  217. //
  218. unsigned short tMax = 0;
  219. for (int i = 0; i < 16; ++i)
  220. if (tMax < t[i])
  221. tMax = t[i];
  222. //
  223. // Compute a set of running differences, r[0] ... r[14]:
  224. // Find a shift value such that after rounding off the
  225. // rightmost bits and shifting all differenes are between
  226. // -32 and +31. Then bias the differences so that they
  227. // end up between 0 and 63.
  228. //
  229. int shift = -1;
  230. int d[16];
  231. int r[15];
  232. int rMin;
  233. int rMax;
  234. const int bias = 0x20;
  235. do
  236. {
  237. shift += 1;
  238. //
  239. // Compute absolute differences, d[0] ... d[15],
  240. // between tMax and t[0] ... t[15].
  241. //
  242. // Shift and round the absolute differences.
  243. //
  244. for (int i = 0; i < 16; ++i)
  245. d[i] = shiftAndRound (tMax - t[i], shift);
  246. //
  247. // Convert d[0] .. d[15] into running differences
  248. //
  249. r[ 0] = d[ 0] - d[ 4] + bias;
  250. r[ 1] = d[ 4] - d[ 8] + bias;
  251. r[ 2] = d[ 8] - d[12] + bias;
  252. r[ 3] = d[ 0] - d[ 1] + bias;
  253. r[ 4] = d[ 4] - d[ 5] + bias;
  254. r[ 5] = d[ 8] - d[ 9] + bias;
  255. r[ 6] = d[12] - d[13] + bias;
  256. r[ 7] = d[ 1] - d[ 2] + bias;
  257. r[ 8] = d[ 5] - d[ 6] + bias;
  258. r[ 9] = d[ 9] - d[10] + bias;
  259. r[10] = d[13] - d[14] + bias;
  260. r[11] = d[ 2] - d[ 3] + bias;
  261. r[12] = d[ 6] - d[ 7] + bias;
  262. r[13] = d[10] - d[11] + bias;
  263. r[14] = d[14] - d[15] + bias;
  264. rMin = r[0];
  265. rMax = r[0];
  266. for (int i = 1; i < 15; ++i)
  267. {
  268. if (rMin > r[i])
  269. rMin = r[i];
  270. if (rMax < r[i])
  271. rMax = r[i];
  272. }
  273. }
  274. while (rMin < 0 || rMax > 0x3f);
  275. if (rMin == bias && rMax == bias && optFlatFields)
  276. {
  277. //
  278. // Special case - all pixels have the same value.
  279. // We encode this in 3 instead of 14 bytes by
  280. // storing the value 0xfc in the third output byte,
  281. // which cannot occur in the 14-byte encoding.
  282. //
  283. b[0] = (t[0] >> 8);
  284. b[1] = t[0];
  285. b[2] = 0xfc;
  286. return 3;
  287. }
  288. if (exactMax)
  289. {
  290. //
  291. // Adjust t[0] so that the pixel whose value is equal
  292. // to tMax gets represented as accurately as possible.
  293. //
  294. t[0] = tMax - (d[0] << shift);
  295. }
  296. //
  297. // Pack t[0], shift and r[0] ... r[14] into 14 bytes:
  298. //
  299. b[ 0] = (t[0] >> 8);
  300. b[ 1] = t[0];
  301. b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
  302. b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
  303. b[ 4] = (unsigned char) ((r[ 1] << 6) | r[ 2] );
  304. b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));
  305. b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));
  306. b[ 7] = (unsigned char) ((r[ 5] << 6) | r[ 6] );
  307. b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));
  308. b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));
  309. b[10] = (unsigned char) ((r[ 9] << 6) | r[10] );
  310. b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));
  311. b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));
  312. b[13] = (unsigned char) ((r[13] << 6) | r[14] );
  313. return 14;
  314. }
  315. inline
  316. void
  317. unpack14 (const unsigned char b[14], unsigned short s[16])
  318. {
  319. //
  320. // Unpack a 14-byte block into 4 by 4 16-bit pixels.
  321. //
  322. #if defined (DEBUG)
  323. assert (b[2] != 0xfc);
  324. #endif
  325. s[ 0] = (b[0] << 8) | b[1];
  326. unsigned short shift = (b[ 2] >> 2);
  327. unsigned short bias = (0x20 << shift);
  328. s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
  329. s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
  330. s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias;
  331. s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias;
  332. s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
  333. s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
  334. s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias;
  335. s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias;
  336. s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
  337. s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
  338. s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias;
  339. s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias;
  340. s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
  341. s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
  342. s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias;
  343. for (int i = 0; i < 16; ++i)
  344. {
  345. if (s[i] & 0x8000)
  346. s[i] &= 0x7fff;
  347. else
  348. s[i] = ~s[i];
  349. }
  350. }
  351. inline
  352. void
  353. unpack3 (const unsigned char b[3], unsigned short s[16])
  354. {
  355. //
  356. // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
  357. //
  358. #if defined (DEBUG)
  359. assert (b[2] == 0xfc);
  360. #endif
  361. s[0] = (b[0] << 8) | b[1];
  362. if (s[0] & 0x8000)
  363. s[0] &= 0x7fff;
  364. else
  365. s[0] = ~s[0];
  366. for (int i = 1; i < 16; ++i)
  367. s[i] = s[0];
  368. }
  369. void
  370. notEnoughData ()
  371. {
  372. throw Iex::InputExc ("Error decompressing data "
  373. "(input data are shorter than expected).");
  374. }
  375. void
  376. tooMuchData ()
  377. {
  378. throw Iex::InputExc ("Error decompressing data "
  379. "(input data are longer than expected).");
  380. }
  381. } // namespace
  382. struct B44Compressor::ChannelData
  383. {
  384. unsigned short * start;
  385. unsigned short * end;
  386. int nx;
  387. int ny;
  388. int ys;
  389. PixelType type;
  390. bool pLinear;
  391. int size;
  392. };
  393. B44Compressor::B44Compressor
  394. (const Header &hdr,
  395. size_t maxScanLineSize,
  396. size_t numScanLines,
  397. bool optFlatFields)
  398. :
  399. Compressor (hdr),
  400. _maxScanLineSize (maxScanLineSize),
  401. _optFlatFields (optFlatFields),
  402. _format (XDR),
  403. _numScanLines (numScanLines),
  404. _tmpBuffer (0),
  405. _outBuffer (0),
  406. _numChans (0),
  407. _channels (hdr.channels()),
  408. _channelData (0)
  409. {
  410. //
  411. // Allocate buffers for compressed an uncompressed pixel data,
  412. // allocate a set of ChannelData structs to help speed up the
  413. // compress() and uncompress() functions, below, and determine
  414. // if uncompressed pixel data should be in native or Xdr format.
  415. //
  416. _tmpBuffer = new unsigned short
  417. [checkArraySize (uiMult (maxScanLineSize, numScanLines),
  418. sizeof (unsigned short))];
  419. const ChannelList &channels = header().channels();
  420. int numHalfChans = 0;
  421. for (ChannelList::ConstIterator c = channels.begin();
  422. c != channels.end();
  423. ++c)
  424. {
  425. assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
  426. ++_numChans;
  427. if (c.channel().type == HALF)
  428. ++numHalfChans;
  429. }
  430. //
  431. // Compressed data may be larger than the input data
  432. //
  433. size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;
  434. _outBuffer = new char
  435. [uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];
  436. _channelData = new ChannelData[_numChans];
  437. int i = 0;
  438. for (ChannelList::ConstIterator c = channels.begin();
  439. c != channels.end();
  440. ++c, ++i)
  441. {
  442. _channelData[i].ys = c.channel().ySampling;
  443. _channelData[i].type = c.channel().type;
  444. _channelData[i].pLinear = c.channel().pLinear;
  445. _channelData[i].size =
  446. pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
  447. }
  448. const Box2i &dataWindow = hdr.dataWindow();
  449. _minX = dataWindow.min.x;
  450. _maxX = dataWindow.max.x;
  451. _maxY = dataWindow.max.y;
  452. //
  453. // We can support uncompressed data in the machine's native
  454. // format only if all image channels are of type HALF.
  455. //
  456. assert (sizeof (unsigned short) == pixelTypeSize (HALF));
  457. if (_numChans == numHalfChans)
  458. _format = NATIVE;
  459. }
  460. B44Compressor::~B44Compressor ()
  461. {
  462. delete [] _tmpBuffer;
  463. delete [] _outBuffer;
  464. delete [] _channelData;
  465. }
  466. int
  467. B44Compressor::numScanLines () const
  468. {
  469. return _numScanLines;
  470. }
  471. Compressor::Format
  472. B44Compressor::format () const
  473. {
  474. return _format;
  475. }
  476. int
  477. B44Compressor::compress (const char *inPtr,
  478. int inSize,
  479. int minY,
  480. const char *&outPtr)
  481. {
  482. return compress (inPtr,
  483. inSize,
  484. Box2i (V2i (_minX, minY),
  485. V2i (_maxX, minY + numScanLines() - 1)),
  486. outPtr);
  487. }
  488. int
  489. B44Compressor::compressTile (const char *inPtr,
  490. int inSize,
  491. Imath::Box2i range,
  492. const char *&outPtr)
  493. {
  494. return compress (inPtr, inSize, range, outPtr);
  495. }
  496. int
  497. B44Compressor::uncompress (const char *inPtr,
  498. int inSize,
  499. int minY,
  500. const char *&outPtr)
  501. {
  502. return uncompress (inPtr,
  503. inSize,
  504. Box2i (V2i (_minX, minY),
  505. V2i (_maxX, minY + numScanLines() - 1)),
  506. outPtr);
  507. }
  508. int
  509. B44Compressor::uncompressTile (const char *inPtr,
  510. int inSize,
  511. Imath::Box2i range,
  512. const char *&outPtr)
  513. {
  514. return uncompress (inPtr, inSize, range, outPtr);
  515. }
  516. int
  517. B44Compressor::compress (const char *inPtr,
  518. int inSize,
  519. Imath::Box2i range,
  520. const char *&outPtr)
  521. {
  522. //
  523. // Compress a block of pixel data: First copy the input pixels
  524. // from the input buffer into _tmpBuffer, rearranging them such
  525. // that blocks of 4x4 pixels of a single channel can be accessed
  526. // conveniently. Then compress each 4x4 block of HALF pixel data
  527. // and append the result to the output buffer. Copy UINT and
  528. // FLOAT data to the output buffer without compressing them.
  529. //
  530. outPtr = _outBuffer;
  531. if (inSize == 0)
  532. {
  533. //
  534. // Special case - empty input buffer.
  535. //
  536. return 0;
  537. }
  538. //
  539. // For each channel, detemine how many pixels are stored
  540. // in the input buffer, and where those pixels will be
  541. // placed in _tmpBuffer.
  542. //
  543. int minX = range.min.x;
  544. int maxX = min (range.max.x, _maxX);
  545. int minY = range.min.y;
  546. int maxY = min (range.max.y, _maxY);
  547. unsigned short *tmpBufferEnd = _tmpBuffer;
  548. int i = 0;
  549. for (ChannelList::ConstIterator c = _channels.begin();
  550. c != _channels.end();
  551. ++c, ++i)
  552. {
  553. ChannelData &cd = _channelData[i];
  554. cd.start = tmpBufferEnd;
  555. cd.end = cd.start;
  556. cd.nx = numSamples (c.channel().xSampling, minX, maxX);
  557. cd.ny = numSamples (c.channel().ySampling, minY, maxY);
  558. tmpBufferEnd += cd.nx * cd.ny * cd.size;
  559. }
  560. if (_format == XDR)
  561. {
  562. //
  563. // The data in the input buffer are in the machine-independent
  564. // Xdr format. Copy the HALF channels into _tmpBuffer and
  565. // convert them back into native format for compression.
  566. // Copy UINT and FLOAT channels verbatim into _tmpBuffer.
  567. //
  568. for (int y = minY; y <= maxY; ++y)
  569. {
  570. for (int i = 0; i < _numChans; ++i)
  571. {
  572. ChannelData &cd = _channelData[i];
  573. if (modp (y, cd.ys) != 0)
  574. continue;
  575. if (cd.type == HALF)
  576. {
  577. for (int x = cd.nx; x > 0; --x)
  578. {
  579. Xdr::read <CharPtrIO> (inPtr, *cd.end);
  580. ++cd.end;
  581. }
  582. }
  583. else
  584. {
  585. int n = cd.nx * cd.size;
  586. memcpy (cd.end, inPtr, n * sizeof (unsigned short));
  587. inPtr += n * sizeof (unsigned short);
  588. cd.end += n;
  589. }
  590. }
  591. }
  592. }
  593. else
  594. {
  595. //
  596. // The input buffer contains only HALF channels, and they
  597. // are in native, machine-dependent format. Copy the pixels
  598. // into _tmpBuffer.
  599. //
  600. for (int y = minY; y <= maxY; ++y)
  601. {
  602. for (int i = 0; i < _numChans; ++i)
  603. {
  604. ChannelData &cd = _channelData[i];
  605. #if defined (DEBUG)
  606. assert (cd.type == HALF);
  607. #endif
  608. if (modp (y, cd.ys) != 0)
  609. continue;
  610. int n = cd.nx * cd.size;
  611. memcpy (cd.end, inPtr, n * sizeof (unsigned short));
  612. inPtr += n * sizeof (unsigned short);
  613. cd.end += n;
  614. }
  615. }
  616. }
  617. //
  618. // The pixels for each channel have been packed into a contiguous
  619. // block in _tmpBuffer. HALF channels are in native format; UINT
  620. // and FLOAT channels are in Xdr format.
  621. //
  622. #if defined (DEBUG)
  623. for (int i = 1; i < _numChans; ++i)
  624. assert (_channelData[i-1].end == _channelData[i].start);
  625. assert (_channelData[_numChans-1].end == tmpBufferEnd);
  626. #endif
  627. //
  628. // For each HALF channel, split the data in _tmpBuffer into 4x4
  629. // pixel blocks. Compress each block and append the compressed
  630. // data to the output buffer.
  631. //
  632. // UINT and FLOAT channels are copied from _tmpBuffer into the
  633. // output buffer without further processing.
  634. //
  635. char *outEnd = _outBuffer;
  636. for (int i = 0; i < _numChans; ++i)
  637. {
  638. ChannelData &cd = _channelData[i];
  639. if (cd.type != HALF)
  640. {
  641. //
  642. // UINT or FLOAT channel.
  643. //
  644. int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
  645. memcpy (outEnd, cd.start, n);
  646. outEnd += n;
  647. continue;
  648. }
  649. //
  650. // HALF channel
  651. //
  652. for (int y = 0; y < cd.ny; y += 4)
  653. {
  654. //
  655. // Copy the next 4x4 pixel block into array s.
  656. // If the width, cd.nx, or the height, cd.ny, of
  657. // the pixel data in _tmpBuffer is not divisible
  658. // by 4, then pad the data by repeating the
  659. // rightmost column and the bottom row.
  660. //
  661. unsigned short *row0 = cd.start + y * cd.nx;
  662. unsigned short *row1 = row0 + cd.nx;
  663. unsigned short *row2 = row1 + cd.nx;
  664. unsigned short *row3 = row2 + cd.nx;
  665. if (y + 3 >= cd.ny)
  666. {
  667. if (y + 1 >= cd.ny)
  668. row1 = row0;
  669. if (y + 2 >= cd.ny)
  670. row2 = row1;
  671. row3 = row2;
  672. }
  673. for (int x = 0; x < cd.nx; x += 4)
  674. {
  675. unsigned short s[16];
  676. if (x + 3 >= cd.nx)
  677. {
  678. int n = cd.nx - x;
  679. for (int i = 0; i < 4; ++i)
  680. {
  681. int j = min (i, n - 1);
  682. s[i + 0] = row0[j];
  683. s[i + 4] = row1[j];
  684. s[i + 8] = row2[j];
  685. s[i + 12] = row3[j];
  686. }
  687. }
  688. else
  689. {
  690. memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
  691. memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
  692. memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
  693. memcpy (&s[12], row3, 4 * sizeof (unsigned short));
  694. }
  695. row0 += 4;
  696. row1 += 4;
  697. row2 += 4;
  698. row3 += 4;
  699. //
  700. // Compress the contents of array s and append the
  701. // results to the output buffer.
  702. //
  703. if (cd.pLinear)
  704. convertFromLinear (s);
  705. outEnd += pack (s, (unsigned char *) outEnd,
  706. _optFlatFields, !cd.pLinear);
  707. }
  708. }
  709. }
  710. return outEnd - _outBuffer;
  711. }
  712. int
  713. B44Compressor::uncompress (const char *inPtr,
  714. int inSize,
  715. Imath::Box2i range,
  716. const char *&outPtr)
  717. {
  718. //
  719. // This function is the reverse of the compress() function,
  720. // above. First all pixels are moved from the input buffer
  721. // into _tmpBuffer. UINT and FLOAT channels are copied
  722. // verbatim; HALF channels are uncompressed in blocks of
  723. // 4x4 pixels. Then the pixels in _tmpBuffer are copied
  724. // into the output buffer and rearranged such that the data
  725. // for for each scan line form a contiguous block.
  726. //
  727. outPtr = _outBuffer;
  728. if (inSize == 0)
  729. {
  730. return 0;
  731. }
  732. int minX = range.min.x;
  733. int maxX = min (range.max.x, _maxX);
  734. int minY = range.min.y;
  735. int maxY = min (range.max.y, _maxY);
  736. unsigned short *tmpBufferEnd = _tmpBuffer;
  737. int i = 0;
  738. for (ChannelList::ConstIterator c = _channels.begin();
  739. c != _channels.end();
  740. ++c, ++i)
  741. {
  742. ChannelData &cd = _channelData[i];
  743. cd.start = tmpBufferEnd;
  744. cd.end = cd.start;
  745. cd.nx = numSamples (c.channel().xSampling, minX, maxX);
  746. cd.ny = numSamples (c.channel().ySampling, minY, maxY);
  747. tmpBufferEnd += cd.nx * cd.ny * cd.size;
  748. }
  749. for (int i = 0; i < _numChans; ++i)
  750. {
  751. ChannelData &cd = _channelData[i];
  752. if (cd.type != HALF)
  753. {
  754. //
  755. // UINT or FLOAT channel.
  756. //
  757. int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
  758. if (inSize < n)
  759. notEnoughData();
  760. memcpy (cd.start, inPtr, n);
  761. inPtr += n;
  762. inSize -= n;
  763. continue;
  764. }
  765. //
  766. // HALF channel
  767. //
  768. for (int y = 0; y < cd.ny; y += 4)
  769. {
  770. unsigned short *row0 = cd.start + y * cd.nx;
  771. unsigned short *row1 = row0 + cd.nx;
  772. unsigned short *row2 = row1 + cd.nx;
  773. unsigned short *row3 = row2 + cd.nx;
  774. for (int x = 0; x < cd.nx; x += 4)
  775. {
  776. unsigned short s[16];
  777. if (inSize < 3)
  778. notEnoughData();
  779. if (((const unsigned char *)inPtr)[2] == 0xfc)
  780. {
  781. unpack3 ((const unsigned char *)inPtr, s);
  782. inPtr += 3;
  783. inSize -= 3;
  784. }
  785. else
  786. {
  787. if (inSize < 14)
  788. notEnoughData();
  789. unpack14 ((const unsigned char *)inPtr, s);
  790. inPtr += 14;
  791. inSize -= 14;
  792. }
  793. if (cd.pLinear)
  794. convertToLinear (s);
  795. int n = (x + 3 < cd.nx)?
  796. 4 * sizeof (unsigned short) :
  797. (cd.nx - x) * sizeof (unsigned short);
  798. if (y + 3 < cd.ny)
  799. {
  800. memcpy (row0, &s[ 0], n);
  801. memcpy (row1, &s[ 4], n);
  802. memcpy (row2, &s[ 8], n);
  803. memcpy (row3, &s[12], n);
  804. }
  805. else
  806. {
  807. memcpy (row0, &s[ 0], n);
  808. if (y + 1 < cd.ny)
  809. memcpy (row1, &s[ 4], n);
  810. if (y + 2 < cd.ny)
  811. memcpy (row2, &s[ 8], n);
  812. }
  813. row0 += 4;
  814. row1 += 4;
  815. row2 += 4;
  816. row3 += 4;
  817. }
  818. }
  819. }
  820. char *outEnd = _outBuffer;
  821. if (_format == XDR)
  822. {
  823. for (int y = minY; y <= maxY; ++y)
  824. {
  825. for (int i = 0; i < _numChans; ++i)
  826. {
  827. ChannelData &cd = _channelData[i];
  828. if (modp (y, cd.ys) != 0)
  829. continue;
  830. if (cd.type == HALF)
  831. {
  832. for (int x = cd.nx; x > 0; --x)
  833. {
  834. Xdr::write <CharPtrIO> (outEnd, *cd.end);
  835. ++cd.end;
  836. }
  837. }
  838. else
  839. {
  840. int n = cd.nx * cd.size;
  841. memcpy (outEnd, cd.end, n * sizeof (unsigned short));
  842. outEnd += n * sizeof (unsigned short);
  843. cd.end += n;
  844. }
  845. }
  846. }
  847. }
  848. else
  849. {
  850. for (int y = minY; y <= maxY; ++y)
  851. {
  852. for (int i = 0; i < _numChans; ++i)
  853. {
  854. ChannelData &cd = _channelData[i];
  855. #if defined (DEBUG)
  856. assert (cd.type == HALF);
  857. #endif
  858. if (modp (y, cd.ys) != 0)
  859. continue;
  860. int n = cd.nx * cd.size;
  861. memcpy (outEnd, cd.end, n * sizeof (unsigned short));
  862. outEnd += n * sizeof (unsigned short);
  863. cd.end += n;
  864. }
  865. }
  866. }
  867. #if defined (DEBUG)
  868. for (int i = 1; i < _numChans; ++i)
  869. assert (_channelData[i-1].end == _channelData[i].start);
  870. assert (_channelData[_numChans-1].end == tmpBufferEnd);
  871. #endif
  872. if (inSize > 0)
  873. tooMuchData();
  874. outPtr = _outBuffer;
  875. return outEnd - _outBuffer;
  876. }
  877. } // namespace Imf