1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- ///////////////////////////////////////////////////////////////////////////
- //
- // Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
- // Digital Ltd. LLC
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Industrial Light & Magic nor the names of
- // its contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- //
- ///////////////////////////////////////////////////////////////////////////
- //-----------------------------------------------------------------------------
- //
- // 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.
- //
- int shift = -1;
- int d[16];
- int r[15];
- int rMin;
- int rMax;
- const int bias = 0x20;
- do
- {
- shift += 1;
- //
- // Compute absolute differences, d[0] ... d[15],
- // between tMax and t[0] ... t[15].
- //
- // Shift and round the absolute differences.
- //
- for (int i = 0; i < 16; ++i)
- d[i] = shiftAndRound (tMax - t[i], shift);
- //
- // Convert d[0] .. d[15] into running differences
- //
- r[ 0] = d[ 0] - d[ 4] + bias;
- r[ 1] = d[ 4] - d[ 8] + bias;
- r[ 2] = d[ 8] - d[12] + bias;
- r[ 3] = d[ 0] - d[ 1] + bias;
- r[ 4] = d[ 4] - d[ 5] + bias;
- r[ 5] = d[ 8] - d[ 9] + bias;
- r[ 6] = d[12] - d[13] + bias;
- r[ 7] = d[ 1] - d[ 2] + bias;
- r[ 8] = d[ 5] - d[ 6] + bias;
- r[ 9] = d[ 9] - d[10] + bias;
- r[10] = d[13] - d[14] + bias;
- r[11] = d[ 2] - d[ 3] + bias;
- r[12] = d[ 6] - d[ 7] + bias;
- r[13] = d[10] - d[11] + bias;
- r[14] = d[14] - d[15] + bias;
- rMin = r[0];
- rMax = r[0];
- for (int i = 1; i < 15; ++i)
- {
- if (rMin > r[i])
- rMin = r[i];
- if (rMax < r[i])
- rMax = r[i];
- }
- }
- while (rMin < 0 || rMax > 0x3f);
- if (rMin == bias && rMax == bias && optFlatFields)
- {
- //
- // Special case - all pixels have the same value.
- // We encode this in 3 instead of 14 bytes by
- // storing the value 0xfc in the third output byte,
- // which cannot occur in the 14-byte encoding.
- //
- b[0] = (t[0] >> 8);
- b[1] = (unsigned char) t[0];
- b[2] = 0xfc;
- return 3;
- }
- if (exactMax)
- {
- //
- // Adjust t[0] so that the pixel whose value is equal
- // to tMax gets represented as accurately as possible.
- //
- t[0] = tMax - (d[0] << shift);
- }
- //
- // Pack t[0], shift and r[0] ... r[14] into 14 bytes:
- //
- b[ 0] = (t[0] >> 8);
- b[ 1] = (unsigned char) t[0];
- b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
- b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
- b[ 4] = (unsigned char) ((r[ 1] << 6) | r[ 2] );
- b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));
- b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));
- b[ 7] = (unsigned char) ((r[ 5] << 6) | r[ 6] );
- b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));
- b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));
- b[10] = (unsigned char) ((r[ 9] << 6) | r[10] );
- b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));
- b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));
- b[13] = (unsigned char) ((r[13] << 6) | r[14] );
- return 14;
- }
- inline
- void
- unpack14 (const unsigned char b[14], unsigned short s[16])
- {
- //
- // Unpack a 14-byte block into 4 by 4 16-bit pixels.
- //
- #if defined (DEBUG)
- assert (b[2] != 0xfc);
- #endif
- s[ 0] = (b[0] << 8) | b[1];
- unsigned short shift = (b[ 2] >> 2);
- unsigned short bias = (0x20 << shift);
- s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
- s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
- s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias;
-
- s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias;
- s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
- s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
- s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias;
-
- s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias;
- s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
- s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
- s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias;
-
- s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias;
- s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
- s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
- s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias;
- for (int i = 0; i < 16; ++i)
- {
- if (s[i] & 0x8000)
- s[i] &= 0x7fff;
- else
- s[i] = ~s[i];
- }
- }
- inline
- void
- unpack3 (const unsigned char b[3], unsigned short s[16])
- {
- //
- // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
- //
- #if defined (DEBUG)
- assert (b[2] == 0xfc);
- #endif
- s[0] = (b[0] << 8) | b[1];
- if (s[0] & 0x8000)
- s[0] &= 0x7fff;
- else
- s[0] = ~s[0];
- for (int i = 1; i < 16; ++i)
- s[i] = s[0];
- }
- void
- notEnoughData ()
- {
- throw IEX_NAMESPACE::InputExc ("Error decompressing data "
- "(input data are shorter than expected).");
- }
- void
- tooMuchData ()
- {
- throw IEX_NAMESPACE::InputExc ("Error decompressing data "
- "(input data are longer than expected).");
- }
- } // namespace
- struct B44Compressor::ChannelData
- {
- unsigned short * start;
- unsigned short * end;
- int nx;
- int ny;
- int ys;
- PixelType type;
- bool pLinear;
- int size;
- };
- B44Compressor::B44Compressor
- (const Header &hdr,
- size_t maxScanLineSize,
- size_t numScanLines,
- bool optFlatFields)
- :
- Compressor (hdr),
- _maxScanLineSize (maxScanLineSize),
- _optFlatFields (optFlatFields),
- _format (XDR),
- _numScanLines (numScanLines),
- _tmpBuffer (0),
- _outBuffer (0),
- _numChans (0),
- _channels (hdr.channels()),
- _channelData (0)
- {
- //
- // Allocate buffers for compressed an uncompressed pixel data,
- // allocate a set of ChannelData structs to help speed up the
- // compress() and uncompress() functions, below, and determine
- // if uncompressed pixel data should be in native or Xdr format.
- //
- _tmpBuffer = new unsigned short
- [checkArraySize (uiMult (maxScanLineSize, numScanLines),
- sizeof (unsigned short))];
- const ChannelList &channels = header().channels();
- int numHalfChans = 0;
- for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c)
- {
- assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
- ++_numChans;
- if (c.channel().type == HALF)
- ++numHalfChans;
- }
- //
- // Compressed data may be larger than the input data
- //
- size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;
- _outBuffer = new char
- [uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];
- _channelData = new ChannelData[_numChans];
- int i = 0;
- for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c, ++i)
- {
- _channelData[i].ys = c.channel().ySampling;
- _channelData[i].type = c.channel().type;
- _channelData[i].pLinear = c.channel().pLinear;
- _channelData[i].size =
- pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
- }
- const Box2i &dataWindow = hdr.dataWindow();
- _minX = dataWindow.min.x;
- _maxX = dataWindow.max.x;
- _maxY = dataWindow.max.y;
- //
- // We can support uncompressed data in the machine's native
- // format only if all image channels are of type HALF.
- //
- assert (sizeof (unsigned short) == pixelTypeSize (HALF));
- if (_numChans == numHalfChans)
- _format = NATIVE;
- }
- B44Compressor::~B44Compressor ()
- {
- delete [] _tmpBuffer;
- delete [] _outBuffer;
- delete [] _channelData;
- }
- int
- B44Compressor::numScanLines () const
- {
- return _numScanLines;
- }
- Compressor::Format
- B44Compressor::format () const
- {
- return _format;
- }
- int
- B44Compressor::compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
- {
- return compress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + numScanLines() - 1)),
- outPtr);
- }
- int
- B44Compressor::compressTile (const char *inPtr,
- int inSize,
- IMATH_NAMESPACE::Box2i range,
- const char *&outPtr)
- {
- return compress (inPtr, inSize, range, outPtr);
- }
- int
- B44Compressor::uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
- {
- return uncompress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + numScanLines() - 1)),
- outPtr);
- }
- int
- B44Compressor::uncompressTile (const char *inPtr,
- int inSize,
- IMATH_NAMESPACE::Box2i range,
- const char *&outPtr)
- {
- return uncompress (inPtr, inSize, range, outPtr);
- }
- int
- B44Compressor::compress (const char *inPtr,
- int inSize,
- IMATH_NAMESPACE::Box2i range,
- const char *&outPtr)
- {
- //
- // Compress a block of pixel data: First copy the input pixels
- // from the input buffer into _tmpBuffer, rearranging them such
- // that blocks of 4x4 pixels of a single channel can be accessed
- // conveniently. Then compress each 4x4 block of HALF pixel data
- // and append the result to the output buffer. Copy UINT and
- // FLOAT data to the output buffer without compressing them.
- //
- outPtr = _outBuffer;
- if (inSize == 0)
- {
- //
- // Special case - empty input buffer.
- //
- return 0;
- }
- //
- // For each channel, detemine how many pixels are stored
- // in the input buffer, and where those pixels will be
- // placed in _tmpBuffer.
- //
- int minX = range.min.x;
- int maxX = min (range.max.x, _maxX);
- int minY = range.min.y;
- int maxY = min (range.max.y, _maxY);
-
- unsigned short *tmpBufferEnd = _tmpBuffer;
- int i = 0;
- for (ChannelList::ConstIterator c = _channels.begin();
- c != _channels.end();
- ++c, ++i)
- {
- ChannelData &cd = _channelData[i];
- cd.start = tmpBufferEnd;
- cd.end = cd.start;
- cd.nx = numSamples (c.channel().xSampling, minX, maxX);
- cd.ny = numSamples (c.channel().ySampling, minY, maxY);
- tmpBufferEnd += cd.nx * cd.ny * cd.size;
- }
- if (_format == XDR)
- {
- //
- // The data in the input buffer are in the machine-independent
- // Xdr format. Copy the HALF channels into _tmpBuffer and
- // convert them back into native format for compression.
- // Copy UINT and FLOAT channels verbatim into _tmpBuffer.
- //
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
- if (modp (y, cd.ys) != 0)
- continue;
- if (cd.type == HALF)
- {
- for (int x = cd.nx; x > 0; --x)
- {
- Xdr::read <CharPtrIO> (inPtr, *cd.end);
- ++cd.end;
- }
- }
- else
- {
- int n = cd.nx * cd.size;
- memcpy (cd.end, inPtr, n * sizeof (unsigned short));
- inPtr += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
- }
- }
- else
- {
- //
- // The input buffer contains only HALF channels, and they
- // are in native, machine-dependent format. Copy the pixels
- // into _tmpBuffer.
- //
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
- #if defined (DEBUG)
- assert (cd.type == HALF);
- #endif
- if (modp (y, cd.ys) != 0)
- continue;
- int n = cd.nx * cd.size;
- memcpy (cd.end, inPtr, n * sizeof (unsigned short));
- inPtr += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
- }
- //
- // The pixels for each channel have been packed into a contiguous
- // block in _tmpBuffer. HALF channels are in native format; UINT
- // and FLOAT channels are in Xdr format.
- //
- #if defined (DEBUG)
- for (int i = 1; i < _numChans; ++i)
- assert (_channelData[i-1].end == _channelData[i].start);
- assert (_channelData[_numChans-1].end == tmpBufferEnd);
- #endif
- //
- // For each HALF channel, split the data in _tmpBuffer into 4x4
- // pixel blocks. Compress each block and append the compressed
- // data to the output buffer.
- //
- // UINT and FLOAT channels are copied from _tmpBuffer into the
- // output buffer without further processing.
- //
- char *outEnd = _outBuffer;
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (cd.type != HALF)
- {
- //
- // UINT or FLOAT channel.
- //
- int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
- memcpy (outEnd, cd.start, n);
- outEnd += n;
- continue;
- }
-
- //
- // HALF channel
- //
- for (int y = 0; y < cd.ny; y += 4)
- {
- //
- // Copy the next 4x4 pixel block into array s.
- // If the width, cd.nx, or the height, cd.ny, of
- // the pixel data in _tmpBuffer is not divisible
- // by 4, then pad the data by repeating the
- // rightmost column and the bottom row.
- //
- unsigned short *row0 = cd.start + y * cd.nx;
- unsigned short *row1 = row0 + cd.nx;
- unsigned short *row2 = row1 + cd.nx;
- unsigned short *row3 = row2 + cd.nx;
- if (y + 3 >= cd.ny)
- {
- if (y + 1 >= cd.ny)
- row1 = row0;
- if (y + 2 >= cd.ny)
- row2 = row1;
- row3 = row2;
- }
- for (int x = 0; x < cd.nx; x += 4)
- {
- unsigned short s[16];
- if (x + 3 >= cd.nx)
- {
- int n = cd.nx - x;
- for (int i = 0; i < 4; ++i)
- {
- int j = min (i, n - 1);
- s[i + 0] = row0[j];
- s[i + 4] = row1[j];
- s[i + 8] = row2[j];
- s[i + 12] = row3[j];
- }
- }
- else
- {
- memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
- memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
- memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
- memcpy (&s[12], row3, 4 * sizeof (unsigned short));
- }
- row0 += 4;
- row1 += 4;
- row2 += 4;
- row3 += 4;
- //
- // Compress the contents of array s and append the
- // results to the output buffer.
- //
- if (cd.pLinear)
- convertFromLinear (s);
- outEnd += pack (s, (unsigned char *) outEnd,
- _optFlatFields, !cd.pLinear);
- }
- }
- }
- return outEnd - _outBuffer;
- }
- int
- B44Compressor::uncompress (const char *inPtr,
- int inSize,
- IMATH_NAMESPACE::Box2i range,
- const char *&outPtr)
- {
- //
- // This function is the reverse of the compress() function,
- // above. First all pixels are moved from the input buffer
- // into _tmpBuffer. UINT and FLOAT channels are copied
- // verbatim; HALF channels are uncompressed in blocks of
- // 4x4 pixels. Then the pixels in _tmpBuffer are copied
- // into the output buffer and rearranged such that the data
- // for for each scan line form a contiguous block.
- //
- outPtr = _outBuffer;
- if (inSize == 0)
- {
- return 0;
- }
- int minX = range.min.x;
- int maxX = min (range.max.x, _maxX);
- int minY = range.min.y;
- int maxY = min (range.max.y, _maxY);
-
- unsigned short *tmpBufferEnd = _tmpBuffer;
- int i = 0;
- for (ChannelList::ConstIterator c = _channels.begin();
- c != _channels.end();
- ++c, ++i)
- {
- ChannelData &cd = _channelData[i];
- cd.start = tmpBufferEnd;
- cd.end = cd.start;
- cd.nx = numSamples (c.channel().xSampling, minX, maxX);
- cd.ny = numSamples (c.channel().ySampling, minY, maxY);
- tmpBufferEnd += cd.nx * cd.ny * cd.size;
- }
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
- if (cd.type != HALF)
- {
- //
- // UINT or FLOAT channel.
- //
- int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
- if (inSize < n)
- notEnoughData();
- memcpy (cd.start, inPtr, n);
- inPtr += n;
- inSize -= n;
- continue;
- }
- //
- // HALF channel
- //
- for (int y = 0; y < cd.ny; y += 4)
- {
- unsigned short *row0 = cd.start + y * cd.nx;
- unsigned short *row1 = row0 + cd.nx;
- unsigned short *row2 = row1 + cd.nx;
- unsigned short *row3 = row2 + cd.nx;
- for (int x = 0; x < cd.nx; x += 4)
- {
- unsigned short s[16];
- if (inSize < 3)
- notEnoughData();
- if (((const unsigned char *)inPtr)[2] == 0xfc)
- {
- unpack3 ((const unsigned char *)inPtr, s);
- inPtr += 3;
- inSize -= 3;
- }
- else
- {
- if (inSize < 14)
- notEnoughData();
- unpack14 ((const unsigned char *)inPtr, s);
- inPtr += 14;
- inSize -= 14;
- }
- if (cd.pLinear)
- convertToLinear (s);
- int n = (x + 3 < cd.nx)?
- 4 * sizeof (unsigned short) :
- (cd.nx - x) * sizeof (unsigned short);
- if (y + 3 < cd.ny)
- {
- memcpy (row0, &s[ 0], n);
- memcpy (row1, &s[ 4], n);
- memcpy (row2, &s[ 8], n);
- memcpy (row3, &s[12], n);
- }
- else
- {
- memcpy (row0, &s[ 0], n);
- if (y + 1 < cd.ny)
- memcpy (row1, &s[ 4], n);
- if (y + 2 < cd.ny)
- memcpy (row2, &s[ 8], n);
- }
- row0 += 4;
- row1 += 4;
- row2 += 4;
- row3 += 4;
- }
- }
- }
- char *outEnd = _outBuffer;
- if (_format == XDR)
- {
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
- if (modp (y, cd.ys) != 0)
- continue;
- if (cd.type == HALF)
- {
- for (int x = cd.nx; x > 0; --x)
- {
- Xdr::write <CharPtrIO> (outEnd, *cd.end);
- ++cd.end;
- }
- }
- else
- {
- int n = cd.nx * cd.size;
- memcpy (outEnd, cd.end, n * sizeof (unsigned short));
- outEnd += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
- }
- }
- else
- {
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
- #if defined (DEBUG)
- assert (cd.type == HALF);
- #endif
- if (modp (y, cd.ys) != 0)
- continue;
- int n = cd.nx * cd.size;
- memcpy (outEnd, cd.end, n * sizeof (unsigned short));
- outEnd += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
- }
- #if defined (DEBUG)
- for (int i = 1; i < _numChans; ++i)
- assert (_channelData[i-1].end == _channelData[i].start);
- assert (_channelData[_numChans-1].end == tmpBufferEnd);
- #endif
- if (inSize > 0)
- tooMuchData();
- outPtr = _outBuffer;
- return outEnd - _outBuffer;
- }
- OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
|