Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/OpenEXR/IlmImf/ImfB44Compressor.cpp view on Meta::CPAN
//-----------------------------------------------------------------------------
//
// class B44Compressor
//
// This compressor is lossy for HALF channels; the compression rate
// is fixed at 32/14 (approximately 2.28). FLOAT and UINT channels
// are not compressed; their data are preserved exactly.
//
// Each HALF channel is split into blocks of 4 by 4 pixels. An
// uncompressed block occupies 32 bytes, which are re-interpreted
// as sixteen 16-bit unsigned integers, t[0] ... t[15]. Compression
// shrinks the block to 14 bytes. The compressed 14-byte block
// contains
//
// - t[0]
//
// - a 6-bit shift value
//
// - 15 densely packed 6-bit values, r[0] ... r[14], which are
// computed by subtracting adjacent pixel values and right-
// shifting the differences according to the stored shift value.
//
// Differences between adjacent pixels are computed according
// to the following diagram:
//
// 0 --------> 1 --------> 2 --------> 3
// | 3 7 11
// |
// | 0
// |
// v
// 4 --------> 5 --------> 6 --------> 7
// | 4 8 12
// |
// | 1
// |
// v
// 8 --------> 9 --------> 10 --------> 11
// | 5 9 13
// |
// | 2
// |
// v
// 12 --------> 13 --------> 14 --------> 15
// 6 10 14
//
// Here
//
// 5 ---------> 6
// 8
//
// means that r[8] is the difference between t[5] and t[6].
//
// - optionally, a 4-by-4 pixel block where all pixels have the
// same value can be treated as a special case, where the
// compressed block contains only 3 instead of 14 bytes:
// t[0], followed by an "impossible" 6-bit shift value and
// two padding bits.
//
// This compressor can handle positive and negative pixel values.
// NaNs and infinities are replaced with zeroes before compression.
//
//-----------------------------------------------------------------------------
#include "ImfB44Compressor.h"
#include "ImfHeader.h"
#include "ImfChannelList.h"
#include "ImfMisc.h"
#include "ImfCheckedArithmetic.h"
#include <ImathFun.h>
#include <ImathBox.h>
#include <Iex.h>
#include <ImfIO.h>
#include <ImfXdr.h>
#include <string.h>
#include <assert.h>
#include <algorithm>
#include "ImfNamespace.h"
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
using IMATH_NAMESPACE::divp;
using IMATH_NAMESPACE::modp;
using IMATH_NAMESPACE::Box2i;
using IMATH_NAMESPACE::V2i;
using std::min;
namespace {
//
// Lookup tables for
// y = exp (x / 8)
// and
// x = 8 * log (y)
//
#include "b44ExpLogTable.h"
inline void
convertFromLinear (unsigned short s[16])
{
for (int i = 0; i < 16; ++i)
s[i] = expTable[s[i]];
}
inline void
convertToLinear (unsigned short s[16])
{
for (int i = 0; i < 16; ++i)
s[i] = logTable[s[i]];
}
inline int
shiftAndRound (int x, int shift)
{
//
// Compute
//
// y = x * pow (2, -shift),
//
// then round y to the nearest integer.
// In case of a tie, where y is exactly
// halfway between two integers, round
// to the even one.
//
x <<= 1;
int a = (1 << shift) - 1;
shift += 1;
int b = (x >> shift) & 1;
return (x + a + b) >> shift;
}
int
pack (const unsigned short s[16],
unsigned char b[14],
bool optFlatFields,
bool exactMax)
{
//
// Pack a block of 4 by 4 16-bit pixels (32 bytes) into
// either 14 or 3 bytes.
//
//
// Integers s[0] ... s[15] represent floating-point numbers
// in what is essentially a sign-magnitude format. Convert
// s[0] .. s[15] into a new set of integers, t[0] ... t[15],
// such that if t[i] is greater than t[j], the floating-point
// number that corresponds to s[i] is always greater than
// the floating-point number that corresponds to s[j].
//
// Also, replace any bit patterns that represent NaNs or
// infinities with bit patterns that represent floating-point
// zeroes.
//
// bit pattern floating-point bit pattern
// in s[i] value in t[i]
//
// 0x7fff NAN 0x8000
// 0x7ffe NAN 0x8000
// ... ...
// 0x7c01 NAN 0x8000
// 0x7c00 +infinity 0x8000
// 0x7bff +HALF_MAX 0xfbff
// 0x7bfe 0xfbfe
// 0x7bfd 0xfbfd
// ... ...
// 0x0002 +2 * HALF_MIN 0x8002
// 0x0001 +HALF_MIN 0x8001
// 0x0000 +0.0 0x8000
// 0x8000 -0.0 0x7fff
// 0x8001 -HALF_MIN 0x7ffe
// 0x8002 -2 * HALF_MIN 0x7ffd
// ... ...
// 0xfbfd 0x0f02
// 0xfbfe 0x0401
// 0xfbff -HALF_MAX 0x0400
// 0xfc00 -infinity 0x8000
// 0xfc01 NAN 0x8000
// ... ...
// 0xfffe NAN 0x8000
// 0xffff NAN 0x8000
//
unsigned short t[16];
for (int i = 0; i < 16; ++i)
{
if ((s[i] & 0x7c00) == 0x7c00)
t[i] = 0x8000;
else if (s[i] & 0x8000)
t[i] = ~s[i];
else
t[i] = s[i] | 0x8000;
}
//
// Find the maximum, tMax, of t[0] ... t[15].
//
unsigned short tMax = 0;
for (int i = 0; i < 16; ++i)
if (tMax < t[i])
tMax = t[i];
//
// Compute a set of running differences, r[0] ... r[14]:
// Find a shift value such that after rounding off the
// rightmost bits and shifting all differenes are between
// -32 and +31. Then bias the differences so that they
// end up between 0 and 63.
( run in 0.368 second using v1.01-cache-2.11-cpan-f6376fbd888 )