/src/opencv/3rdparty/openexr/IlmImf/ImfPxr24Compressor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | ///////////////////////////////////////////////////////////////////////////// |
2 | | // |
3 | | // Copyright (c) 2004, Pixar Animation Studios |
4 | | // |
5 | | // All rights reserved. |
6 | | // |
7 | | // Redistribution and use in source and binary forms, with or without |
8 | | // modification, are permitted provided that the following conditions are |
9 | | // met: |
10 | | // * Redistributions of source code must retain the above copyright |
11 | | // notice, this list of conditions and the following disclaimer. |
12 | | // * Redistributions in binary form must reproduce the above |
13 | | // copyright notice, this list of conditions and the following disclaimer |
14 | | // in the documentation and/or other materials provided with the |
15 | | // distribution. |
16 | | // * Neither the name of Pixar Animation Studios nor the names of |
17 | | // its contributors may be used to endorse or promote products derived |
18 | | // from this software without specific prior written permission. |
19 | | // |
20 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
24 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | | // |
32 | | ///////////////////////////////////////////////////////////////////////////// |
33 | | |
34 | | //----------------------------------------------------------------------------- |
35 | | // |
36 | | // class Pxr24Compressor |
37 | | // |
38 | | // This compressor is based on source code that was contributed to |
39 | | // OpenEXR by Pixar Animation Studios. The compression method was |
40 | | // developed by Loren Carpenter. |
41 | | // |
42 | | // The compressor preprocesses the pixel data to reduce entropy, |
43 | | // and then calls zlib. |
44 | | // |
45 | | // Compression of HALF and UINT channels is lossless, but compressing |
46 | | // FLOAT channels is lossy: 32-bit floating-point numbers are converted |
47 | | // to 24 bits by rounding the significand to 15 bits. |
48 | | // |
49 | | // When the compressor is invoked, the caller has already arranged |
50 | | // the pixel data so that the values for each channel appear in a |
51 | | // contiguous block of memory. The compressor converts the pixel |
52 | | // values to unsigned integers: For UINT, this is a no-op. HALF |
53 | | // values are simply re-interpreted as 16-bit integers. FLOAT |
54 | | // values are converted to 24 bits, and the resulting bit patterns |
55 | | // are interpreted as integers. The compressor then replaces each |
56 | | // value with the difference between the value and its left neighbor. |
57 | | // This turns flat fields in the image into zeroes, and ramps into |
58 | | // strings of similar values. Next, each difference is split into |
59 | | // 2, 3 or 4 bytes, and the bytes are transposed so that all the |
60 | | // most significant bytes end up in a contiguous block, followed |
61 | | // by the second most significant bytes, and so on. The resulting |
62 | | // string of bytes is compressed with zlib. |
63 | | // |
64 | | //----------------------------------------------------------------------------- |
65 | | |
66 | | #include "ImfPxr24Compressor.h" |
67 | | #include "ImfHeader.h" |
68 | | #include "ImfChannelList.h" |
69 | | #include "ImfMisc.h" |
70 | | #include "ImfCheckedArithmetic.h" |
71 | | #include "ImfNamespace.h" |
72 | | |
73 | | #include <ImathFun.h> |
74 | | #include <Iex.h> |
75 | | |
76 | | #include <half.h> |
77 | | #include <zlib.h> |
78 | | #include <assert.h> |
79 | | #include <algorithm> |
80 | | |
81 | | using namespace std; |
82 | | using namespace IMATH_NAMESPACE; |
83 | | |
84 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER |
85 | | |
86 | | namespace { |
87 | | |
88 | | // |
89 | | // Conversion from 32-bit to 24-bit floating-point numbers. |
90 | | // Conversion back to 32 bits is simply an 8-bit shift to the left. |
91 | | // |
92 | | |
93 | | inline unsigned int |
94 | | floatToFloat24 (float f) |
95 | 0 | { |
96 | 0 | union |
97 | 0 | { |
98 | 0 | float f; |
99 | 0 | unsigned int i; |
100 | 0 | } u; |
101 | |
|
102 | 0 | u.f = f; |
103 | | |
104 | | // |
105 | | // Disassemble the 32-bit floating point number, f, |
106 | | // into sign, s, exponent, e, and significand, m. |
107 | | // |
108 | |
|
109 | 0 | unsigned int s = u.i & 0x80000000; |
110 | 0 | unsigned int e = u.i & 0x7f800000; |
111 | 0 | unsigned int m = u.i & 0x007fffff; |
112 | 0 | unsigned int i; |
113 | |
|
114 | 0 | if (e == 0x7f800000) |
115 | 0 | { |
116 | 0 | if (m) |
117 | 0 | { |
118 | | // |
119 | | // F is a NAN; we preserve the sign bit and |
120 | | // the 15 leftmost bits of the significand, |
121 | | // with one exception: If the 15 leftmost |
122 | | // bits are all zero, the NAN would turn |
123 | | // into an infinity, so we have to set at |
124 | | // least one bit in the significand. |
125 | | // |
126 | |
|
127 | 0 | m >>= 8; |
128 | 0 | i = (e >> 8) | m | (m == 0); |
129 | 0 | } |
130 | 0 | else |
131 | 0 | { |
132 | | // |
133 | | // F is an infinity. |
134 | | // |
135 | |
|
136 | 0 | i = e >> 8; |
137 | 0 | } |
138 | 0 | } |
139 | 0 | else |
140 | 0 | { |
141 | | // |
142 | | // F is finite, round the significand to 15 bits. |
143 | | // |
144 | |
|
145 | 0 | i = ((e | m) + (m & 0x00000080)) >> 8; |
146 | |
|
147 | 0 | if (i >= 0x7f8000) |
148 | 0 | { |
149 | | // |
150 | | // F was close to FLT_MAX, and the significand was |
151 | | // rounded up, resulting in an exponent overflow. |
152 | | // Avoid the overflow by truncating the significand |
153 | | // instead of rounding it. |
154 | | // |
155 | |
|
156 | 0 | i = (e | m) >> 8; |
157 | 0 | } |
158 | 0 | } |
159 | |
|
160 | 0 | return (s >> 8) | i; |
161 | 0 | } |
162 | | |
163 | | |
164 | | void |
165 | | notEnoughData () |
166 | 0 | { |
167 | 0 | throw IEX_NAMESPACE::InputExc ("Error decompressing data " |
168 | 0 | "(input data are shorter than expected)."); |
169 | 0 | } |
170 | | |
171 | | |
172 | | void |
173 | | tooMuchData () |
174 | 0 | { |
175 | 0 | throw IEX_NAMESPACE::InputExc ("Error decompressing data " |
176 | 0 | "(input data are longer than expected)."); |
177 | 0 | } |
178 | | |
179 | | } // namespace |
180 | | |
181 | | |
182 | | Pxr24Compressor::Pxr24Compressor (const Header &hdr, |
183 | | size_t maxScanLineSize, |
184 | | size_t numScanLines) |
185 | | : |
186 | 0 | Compressor (hdr), |
187 | 0 | _maxScanLineSize (maxScanLineSize), |
188 | 0 | _numScanLines (numScanLines), |
189 | 0 | _tmpBuffer (0), |
190 | 0 | _outBuffer (0), |
191 | 0 | _channels (hdr.channels()) |
192 | 0 | { |
193 | 0 | size_t maxInBytes = |
194 | 0 | uiMult (maxScanLineSize, numScanLines); |
195 | |
|
196 | 0 | size_t maxOutBytes = |
197 | 0 | uiAdd (uiAdd (maxInBytes, |
198 | 0 | size_t (ceil (maxInBytes * 0.01))), |
199 | 0 | size_t (100)); |
200 | |
|
201 | 0 | _tmpBuffer = new unsigned char [maxInBytes]; |
202 | 0 | _outBuffer = new char [maxOutBytes]; |
203 | |
|
204 | 0 | const Box2i &dataWindow = hdr.dataWindow(); |
205 | |
|
206 | 0 | _minX = dataWindow.min.x; |
207 | 0 | _maxX = dataWindow.max.x; |
208 | 0 | _maxY = dataWindow.max.y; |
209 | 0 | } |
210 | | |
211 | | |
212 | | Pxr24Compressor::~Pxr24Compressor () |
213 | 0 | { |
214 | 0 | delete [] _tmpBuffer; |
215 | 0 | delete [] _outBuffer; |
216 | 0 | } |
217 | | |
218 | | |
219 | | int |
220 | | Pxr24Compressor::numScanLines () const |
221 | 0 | { |
222 | 0 | return _numScanLines; |
223 | 0 | } |
224 | | |
225 | | |
226 | | Compressor::Format |
227 | | Pxr24Compressor::format () const |
228 | 0 | { |
229 | 0 | return NATIVE; |
230 | 0 | } |
231 | | |
232 | | |
233 | | int |
234 | | Pxr24Compressor::compress (const char *inPtr, |
235 | | int inSize, |
236 | | int minY, |
237 | | const char *&outPtr) |
238 | 0 | { |
239 | 0 | return compress (inPtr, |
240 | 0 | inSize, |
241 | 0 | Box2i (V2i (_minX, minY), |
242 | 0 | V2i (_maxX, minY + _numScanLines - 1)), |
243 | 0 | outPtr); |
244 | 0 | } |
245 | | |
246 | | |
247 | | int |
248 | | Pxr24Compressor::compressTile (const char *inPtr, |
249 | | int inSize, |
250 | | Box2i range, |
251 | | const char *&outPtr) |
252 | 0 | { |
253 | 0 | return compress (inPtr, inSize, range, outPtr); |
254 | 0 | } |
255 | | |
256 | | |
257 | | int |
258 | | Pxr24Compressor::uncompress (const char *inPtr, |
259 | | int inSize, |
260 | | int minY, |
261 | | const char *&outPtr) |
262 | 0 | { |
263 | 0 | return uncompress (inPtr, |
264 | 0 | inSize, |
265 | 0 | Box2i (V2i (_minX, minY), |
266 | 0 | V2i (_maxX, minY + _numScanLines - 1)), |
267 | 0 | outPtr); |
268 | 0 | } |
269 | | |
270 | | |
271 | | int |
272 | | Pxr24Compressor::uncompressTile (const char *inPtr, |
273 | | int inSize, |
274 | | Box2i range, |
275 | | const char *&outPtr) |
276 | 0 | { |
277 | 0 | return uncompress (inPtr, inSize, range, outPtr); |
278 | 0 | } |
279 | | |
280 | | |
281 | | int |
282 | | Pxr24Compressor::compress (const char *inPtr, |
283 | | int inSize, |
284 | | Box2i range, |
285 | | const char *&outPtr) |
286 | 0 | { |
287 | 0 | if (inSize == 0) |
288 | 0 | { |
289 | 0 | outPtr = _outBuffer; |
290 | 0 | return 0; |
291 | 0 | } |
292 | | |
293 | 0 | int minX = range.min.x; |
294 | 0 | int maxX = min (range.max.x, _maxX); |
295 | 0 | int minY = range.min.y; |
296 | 0 | int maxY = min (range.max.y, _maxY); |
297 | |
|
298 | 0 | unsigned char *tmpBufferEnd = _tmpBuffer; |
299 | |
|
300 | 0 | for (int y = minY; y <= maxY; ++y) |
301 | 0 | { |
302 | 0 | for (ChannelList::ConstIterator i = _channels.begin(); |
303 | 0 | i != _channels.end(); |
304 | 0 | ++i) |
305 | 0 | { |
306 | 0 | const Channel &c = i.channel(); |
307 | |
|
308 | 0 | if (modp (y, c.ySampling) != 0) |
309 | 0 | continue; |
310 | | |
311 | 0 | int n = numSamples (c.xSampling, minX, maxX); |
312 | |
|
313 | 0 | unsigned char *ptr[4]; |
314 | 0 | unsigned int previousPixel = 0; |
315 | |
|
316 | 0 | switch (c.type) |
317 | 0 | { |
318 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: |
319 | |
|
320 | 0 | ptr[0] = tmpBufferEnd; |
321 | 0 | ptr[1] = ptr[0] + n; |
322 | 0 | ptr[2] = ptr[1] + n; |
323 | 0 | ptr[3] = ptr[2] + n; |
324 | 0 | tmpBufferEnd = ptr[3] + n; |
325 | |
|
326 | 0 | for (int j = 0; j < n; ++j) |
327 | 0 | { |
328 | 0 | unsigned int pixel; |
329 | 0 | char *pPtr = (char *) &pixel; |
330 | |
|
331 | 0 | for (size_t k = 0; k < sizeof (pixel); ++k) |
332 | 0 | *pPtr++ = *inPtr++; |
333 | |
|
334 | 0 | unsigned int diff = pixel - previousPixel; |
335 | 0 | previousPixel = pixel; |
336 | |
|
337 | 0 | *(ptr[0]++) = diff >> 24; |
338 | 0 | *(ptr[1]++) = diff >> 16; |
339 | 0 | *(ptr[2]++) = diff >> 8; |
340 | 0 | *(ptr[3]++) = diff; |
341 | 0 | } |
342 | |
|
343 | 0 | break; |
344 | | |
345 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: |
346 | |
|
347 | 0 | ptr[0] = tmpBufferEnd; |
348 | 0 | ptr[1] = ptr[0] + n; |
349 | 0 | tmpBufferEnd = ptr[1] + n; |
350 | |
|
351 | 0 | for (int j = 0; j < n; ++j) |
352 | 0 | { |
353 | 0 | half pixel; |
354 | |
|
355 | 0 | pixel = *(const half *) inPtr; |
356 | 0 | inPtr += sizeof (half); |
357 | |
|
358 | 0 | unsigned int diff = pixel.bits() - previousPixel; |
359 | 0 | previousPixel = pixel.bits(); |
360 | |
|
361 | 0 | *(ptr[0]++) = diff >> 8; |
362 | 0 | *(ptr[1]++) = diff; |
363 | 0 | } |
364 | |
|
365 | 0 | break; |
366 | | |
367 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: |
368 | |
|
369 | 0 | ptr[0] = tmpBufferEnd; |
370 | 0 | ptr[1] = ptr[0] + n; |
371 | 0 | ptr[2] = ptr[1] + n; |
372 | 0 | tmpBufferEnd = ptr[2] + n; |
373 | |
|
374 | 0 | for (int j = 0; j < n; ++j) |
375 | 0 | { |
376 | 0 | float pixel; |
377 | 0 | char *pPtr = (char *) &pixel; |
378 | |
|
379 | 0 | for (size_t k = 0; k < sizeof (pixel); ++k) |
380 | 0 | *pPtr++ = *inPtr++; |
381 | |
|
382 | 0 | unsigned int pixel24 = floatToFloat24 (pixel); |
383 | 0 | unsigned int diff = pixel24 - previousPixel; |
384 | 0 | previousPixel = pixel24; |
385 | |
|
386 | 0 | *(ptr[0]++) = diff >> 16; |
387 | 0 | *(ptr[1]++) = diff >> 8; |
388 | 0 | *(ptr[2]++) = diff; |
389 | 0 | } |
390 | |
|
391 | 0 | break; |
392 | | |
393 | 0 | default: |
394 | |
|
395 | 0 | assert (false); |
396 | 0 | } |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | 0 | uLongf outSize = int (ceil ((tmpBufferEnd - _tmpBuffer) * 1.01)) + 100; |
401 | |
|
402 | 0 | if (Z_OK != ::compress ((Bytef *) _outBuffer, |
403 | 0 | &outSize, |
404 | 0 | (const Bytef *) _tmpBuffer, |
405 | 0 | tmpBufferEnd - _tmpBuffer)) |
406 | 0 | { |
407 | 0 | throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed."); |
408 | 0 | } |
409 | | |
410 | 0 | outPtr = _outBuffer; |
411 | 0 | return outSize; |
412 | 0 | } |
413 | | |
414 | | |
415 | | int |
416 | | Pxr24Compressor::uncompress (const char *inPtr, |
417 | | int inSize, |
418 | | Box2i range, |
419 | | const char *&outPtr) |
420 | 0 | { |
421 | 0 | if (inSize == 0) |
422 | 0 | { |
423 | 0 | outPtr = _outBuffer; |
424 | 0 | return 0; |
425 | 0 | } |
426 | | |
427 | 0 | uLongf tmpSize = _maxScanLineSize * _numScanLines; |
428 | |
|
429 | 0 | if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer, |
430 | 0 | &tmpSize, |
431 | 0 | (const Bytef *) inPtr, |
432 | 0 | inSize)) |
433 | 0 | { |
434 | 0 | throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed."); |
435 | 0 | } |
436 | | |
437 | 0 | int minX = range.min.x; |
438 | 0 | int maxX = min (range.max.x, _maxX); |
439 | 0 | int minY = range.min.y; |
440 | 0 | int maxY = min (range.max.y, _maxY); |
441 | |
|
442 | 0 | const unsigned char *tmpBufferEnd = _tmpBuffer; |
443 | 0 | char *writePtr = _outBuffer; |
444 | |
|
445 | 0 | for (int y = minY; y <= maxY; ++y) |
446 | 0 | { |
447 | 0 | for (ChannelList::ConstIterator i = _channels.begin(); |
448 | 0 | i != _channels.end(); |
449 | 0 | ++i) |
450 | 0 | { |
451 | 0 | const Channel &c = i.channel(); |
452 | |
|
453 | 0 | if (modp (y, c.ySampling) != 0) |
454 | 0 | continue; |
455 | | |
456 | 0 | int n = numSamples (c.xSampling, minX, maxX); |
457 | |
|
458 | 0 | const unsigned char *ptr[4]; |
459 | 0 | unsigned int pixel = 0; |
460 | |
|
461 | 0 | switch (c.type) |
462 | 0 | { |
463 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: |
464 | |
|
465 | 0 | ptr[0] = tmpBufferEnd; |
466 | 0 | ptr[1] = ptr[0] + n; |
467 | 0 | ptr[2] = ptr[1] + n; |
468 | 0 | ptr[3] = ptr[2] + n; |
469 | 0 | tmpBufferEnd = ptr[3] + n; |
470 | |
|
471 | 0 | if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize) |
472 | 0 | notEnoughData(); |
473 | |
|
474 | 0 | for (int j = 0; j < n; ++j) |
475 | 0 | { |
476 | 0 | unsigned int diff = (*(ptr[0]++) << 24) | |
477 | 0 | (*(ptr[1]++) << 16) | |
478 | 0 | (*(ptr[2]++) << 8) | |
479 | 0 | *(ptr[3]++); |
480 | |
|
481 | 0 | pixel += diff; |
482 | |
|
483 | 0 | char *pPtr = (char *) &pixel; |
484 | |
|
485 | 0 | for (size_t k = 0; k < sizeof (pixel); ++k) |
486 | 0 | *writePtr++ = *pPtr++; |
487 | 0 | } |
488 | |
|
489 | 0 | break; |
490 | | |
491 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: |
492 | |
|
493 | 0 | ptr[0] = tmpBufferEnd; |
494 | 0 | ptr[1] = ptr[0] + n; |
495 | 0 | tmpBufferEnd = ptr[1] + n; |
496 | |
|
497 | 0 | if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize) |
498 | 0 | notEnoughData(); |
499 | |
|
500 | 0 | for (int j = 0; j < n; ++j) |
501 | 0 | { |
502 | 0 | unsigned int diff = (*(ptr[0]++) << 8) | |
503 | 0 | *(ptr[1]++); |
504 | |
|
505 | 0 | pixel += diff; |
506 | |
|
507 | 0 | half * hPtr = (half *) writePtr; |
508 | 0 | hPtr->setBits ((unsigned short) pixel); |
509 | 0 | writePtr += sizeof (half); |
510 | 0 | } |
511 | |
|
512 | 0 | break; |
513 | | |
514 | 0 | case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: |
515 | |
|
516 | 0 | ptr[0] = tmpBufferEnd; |
517 | 0 | ptr[1] = ptr[0] + n; |
518 | 0 | ptr[2] = ptr[1] + n; |
519 | 0 | tmpBufferEnd = ptr[2] + n; |
520 | |
|
521 | 0 | if ( (uLongf) (tmpBufferEnd - _tmpBuffer) > tmpSize) |
522 | 0 | notEnoughData(); |
523 | |
|
524 | 0 | for (int j = 0; j < n; ++j) |
525 | 0 | { |
526 | 0 | unsigned int diff = (*(ptr[0]++) << 24) | |
527 | 0 | (*(ptr[1]++) << 16) | |
528 | 0 | (*(ptr[2]++) << 8); |
529 | 0 | pixel += diff; |
530 | |
|
531 | 0 | char *pPtr = (char *) &pixel; |
532 | |
|
533 | 0 | for (size_t k = 0; k < sizeof (pixel); ++k) |
534 | 0 | *writePtr++ = *pPtr++; |
535 | 0 | } |
536 | |
|
537 | 0 | break; |
538 | | |
539 | 0 | default: |
540 | |
|
541 | 0 | assert (false); |
542 | 0 | } |
543 | 0 | } |
544 | 0 | } |
545 | | |
546 | 0 | if ((uLongf) (tmpBufferEnd - _tmpBuffer) < tmpSize) |
547 | 0 | tooMuchData(); |
548 | |
|
549 | 0 | outPtr = _outBuffer; |
550 | 0 | return writePtr - _outBuffer; |
551 | 0 | } |
552 | | |
553 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |