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