Path: blob/master/3rdparty/openexr/IlmImf/ImfB44Compressor.cpp
16337 views
///////////////////////////////////////////////////////////////////////////1//2// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas3// Digital Ltd. LLC4//5// All rights reserved.6//7// Redistribution and use in source and binary forms, with or without8// modification, are permitted provided that the following conditions are9// met:10// * Redistributions of source code must retain the above copyright11// notice, this list of conditions and the following disclaimer.12// * Redistributions in binary form must reproduce the above13// copyright notice, this list of conditions and the following disclaimer14// in the documentation and/or other materials provided with the15// distribution.16// * Neither the name of Industrial Light & Magic nor the names of17// its contributors may be used to endorse or promote products derived18// from this software without specific prior written permission.19//20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31//32///////////////////////////////////////////////////////////////////////////333435//-----------------------------------------------------------------------------36//37// class B44Compressor38//39// This compressor is lossy for HALF channels; the compression rate40// is fixed at 32/14 (approximately 2.28). FLOAT and UINT channels41// are not compressed; their data are preserved exactly.42//43// Each HALF channel is split into blocks of 4 by 4 pixels. An44// uncompressed block occupies 32 bytes, which are re-interpreted45// as sixteen 16-bit unsigned integers, t[0] ... t[15]. Compression46// shrinks the block to 14 bytes. The compressed 14-byte block47// contains48//49// - t[0]50//51// - a 6-bit shift value52//53// - 15 densely packed 6-bit values, r[0] ... r[14], which are54// computed by subtracting adjacent pixel values and right-55// shifting the differences according to the stored shift value.56//57// Differences between adjacent pixels are computed according58// to the following diagram:59//60// 0 --------> 1 --------> 2 --------> 361// | 3 7 1162// |63// | 064// |65// v66// 4 --------> 5 --------> 6 --------> 767// | 4 8 1268// |69// | 170// |71// v72// 8 --------> 9 --------> 10 --------> 1173// | 5 9 1374// |75// | 276// |77// v78// 12 --------> 13 --------> 14 --------> 1579// 6 10 1480//81// Here82//83// 5 ---------> 684// 885//86// means that r[8] is the difference between t[5] and t[6].87//88// - optionally, a 4-by-4 pixel block where all pixels have the89// same value can be treated as a special case, where the90// compressed block contains only 3 instead of 14 bytes:91// t[0], followed by an "impossible" 6-bit shift value and92// two padding bits.93//94// This compressor can handle positive and negative pixel values.95// NaNs and infinities are replaced with zeroes before compression.96//97//-----------------------------------------------------------------------------9899#include <ImfB44Compressor.h>100#include <ImfHeader.h>101#include <ImfChannelList.h>102#include <ImfMisc.h>103#include <ImfCheckedArithmetic.h>104#include <ImathFun.h>105#include <ImathBox.h>106#include <Iex.h>107#include <ImfIO.h>108#include <ImfXdr.h>109#include <string.h>110#include <assert.h>111#include <algorithm>112113namespace Imf {114115using Imath::divp;116using Imath::modp;117using Imath::Box2i;118using Imath::V2i;119using std::min;120121namespace {122123//124// Lookup tables for125// y = exp (x / 8)126// and127// x = 8 * log (y)128//129130#include "b44ExpLogTable.h"131132133inline void134convertFromLinear (unsigned short s[16])135{136for (int i = 0; i < 16; ++i)137s[i] = expTable[s[i]];138}139140141inline void142convertToLinear (unsigned short s[16])143{144for (int i = 0; i < 16; ++i)145s[i] = logTable[s[i]];146}147148149inline int150shiftAndRound (int x, int shift)151{152//153// Compute154//155// y = x * pow (2, -shift),156//157// then round y to the nearest integer.158// In case of a tie, where y is exactly159// halfway between two integers, round160// to the even one.161//162163x <<= 1;164int a = (1 << shift) - 1;165shift += 1;166int b = (x >> shift) & 1;167return (x + a + b) >> shift;168}169170171int172pack (const unsigned short s[16],173unsigned char b[14],174bool optFlatFields,175bool exactMax)176{177//178// Pack a block of 4 by 4 16-bit pixels (32 bytes) into179// either 14 or 3 bytes.180//181182//183// Integers s[0] ... s[15] represent floating-point numbers184// in what is essentially a sign-magnitude format. Convert185// s[0] .. s[15] into a new set of integers, t[0] ... t[15],186// such that if t[i] is greater than t[j], the floating-point187// number that corresponds to s[i] is always greater than188// the floating-point number that corresponds to s[j].189//190// Also, replace any bit patterns that represent NaNs or191// infinities with bit patterns that represent floating-point192// zeroes.193//194// bit pattern floating-point bit pattern195// in s[i] value in t[i]196//197// 0x7fff NAN 0x8000198// 0x7ffe NAN 0x8000199// ... ...200// 0x7c01 NAN 0x8000201// 0x7c00 +infinity 0x8000202// 0x7bff +HALF_MAX 0xfbff203// 0x7bfe 0xfbfe204// 0x7bfd 0xfbfd205// ... ...206// 0x0002 +2 * HALF_MIN 0x8002207// 0x0001 +HALF_MIN 0x8001208// 0x0000 +0.0 0x8000209// 0x8000 -0.0 0x7fff210// 0x8001 -HALF_MIN 0x7ffe211// 0x8002 -2 * HALF_MIN 0x7ffd212// ... ...213// 0xfbfd 0x0f02214// 0xfbfe 0x0401215// 0xfbff -HALF_MAX 0x0400216// 0xfc00 -infinity 0x8000217// 0xfc01 NAN 0x8000218// ... ...219// 0xfffe NAN 0x8000220// 0xffff NAN 0x8000221//222223unsigned short t[16];224225for (int i = 0; i < 16; ++i)226{227if ((s[i] & 0x7c00) == 0x7c00)228t[i] = 0x8000;229else if (s[i] & 0x8000)230t[i] = ~s[i];231else232t[i] = s[i] | 0x8000;233}234235//236// Find the maximum, tMax, of t[0] ... t[15].237//238239unsigned short tMax = 0;240241for (int i = 0; i < 16; ++i)242if (tMax < t[i])243tMax = t[i];244245//246// Compute a set of running differences, r[0] ... r[14]:247// Find a shift value such that after rounding off the248// rightmost bits and shifting all differenes are between249// -32 and +31. Then bias the differences so that they250// end up between 0 and 63.251//252253int shift = -1;254int d[16];255int r[15];256int rMin;257int rMax;258259const int bias = 0x20;260261do262{263shift += 1;264265//266// Compute absolute differences, d[0] ... d[15],267// between tMax and t[0] ... t[15].268//269// Shift and round the absolute differences.270//271272for (int i = 0; i < 16; ++i)273d[i] = shiftAndRound (tMax - t[i], shift);274275//276// Convert d[0] .. d[15] into running differences277//278279r[ 0] = d[ 0] - d[ 4] + bias;280r[ 1] = d[ 4] - d[ 8] + bias;281r[ 2] = d[ 8] - d[12] + bias;282283r[ 3] = d[ 0] - d[ 1] + bias;284r[ 4] = d[ 4] - d[ 5] + bias;285r[ 5] = d[ 8] - d[ 9] + bias;286r[ 6] = d[12] - d[13] + bias;287288r[ 7] = d[ 1] - d[ 2] + bias;289r[ 8] = d[ 5] - d[ 6] + bias;290r[ 9] = d[ 9] - d[10] + bias;291r[10] = d[13] - d[14] + bias;292293r[11] = d[ 2] - d[ 3] + bias;294r[12] = d[ 6] - d[ 7] + bias;295r[13] = d[10] - d[11] + bias;296r[14] = d[14] - d[15] + bias;297298rMin = r[0];299rMax = r[0];300301for (int i = 1; i < 15; ++i)302{303if (rMin > r[i])304rMin = r[i];305306if (rMax < r[i])307rMax = r[i];308}309}310while (rMin < 0 || rMax > 0x3f);311312if (rMin == bias && rMax == bias && optFlatFields)313{314//315// Special case - all pixels have the same value.316// We encode this in 3 instead of 14 bytes by317// storing the value 0xfc in the third output byte,318// which cannot occur in the 14-byte encoding.319//320321b[0] = (t[0] >> 8);322b[1] = t[0];323b[2] = 0xfc;324325return 3;326}327328if (exactMax)329{330//331// Adjust t[0] so that the pixel whose value is equal332// to tMax gets represented as accurately as possible.333//334335t[0] = tMax - (d[0] << shift);336}337338//339// Pack t[0], shift and r[0] ... r[14] into 14 bytes:340//341342b[ 0] = (t[0] >> 8);343b[ 1] = t[0];344345b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));346b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));347b[ 4] = (unsigned char) ((r[ 1] << 6) | r[ 2] );348349b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));350b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));351b[ 7] = (unsigned char) ((r[ 5] << 6) | r[ 6] );352353b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));354b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));355b[10] = (unsigned char) ((r[ 9] << 6) | r[10] );356357b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));358b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));359b[13] = (unsigned char) ((r[13] << 6) | r[14] );360361return 14;362}363364365inline366void367unpack14 (const unsigned char b[14], unsigned short s[16])368{369//370// Unpack a 14-byte block into 4 by 4 16-bit pixels.371//372373#if defined (DEBUG)374assert (b[2] != 0xfc);375#endif376377s[ 0] = (b[0] << 8) | b[1];378379unsigned short shift = (b[ 2] >> 2);380unsigned short bias = (0x20 << shift);381382s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;383s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;384s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias;385386s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias;387s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;388s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;389s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias;390391s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias;392s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;393s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;394s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias;395396s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias;397s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;398s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;399s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias;400401for (int i = 0; i < 16; ++i)402{403if (s[i] & 0x8000)404s[i] &= 0x7fff;405else406s[i] = ~s[i];407}408}409410411inline412void413unpack3 (const unsigned char b[3], unsigned short s[16])414{415//416// Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.417//418419#if defined (DEBUG)420assert (b[2] == 0xfc);421#endif422423s[0] = (b[0] << 8) | b[1];424425if (s[0] & 0x8000)426s[0] &= 0x7fff;427else428s[0] = ~s[0];429430for (int i = 1; i < 16; ++i)431s[i] = s[0];432}433434435void436notEnoughData ()437{438throw Iex::InputExc ("Error decompressing data "439"(input data are shorter than expected).");440}441442443void444tooMuchData ()445{446throw Iex::InputExc ("Error decompressing data "447"(input data are longer than expected).");448}449450} // namespace451452453struct B44Compressor::ChannelData454{455unsigned short * start;456unsigned short * end;457int nx;458int ny;459int ys;460PixelType type;461bool pLinear;462int size;463};464465466B44Compressor::B44Compressor467(const Header &hdr,468size_t maxScanLineSize,469size_t numScanLines,470bool optFlatFields)471:472Compressor (hdr),473_maxScanLineSize (maxScanLineSize),474_optFlatFields (optFlatFields),475_format (XDR),476_numScanLines (numScanLines),477_tmpBuffer (0),478_outBuffer (0),479_numChans (0),480_channels (hdr.channels()),481_channelData (0)482{483//484// Allocate buffers for compressed an uncompressed pixel data,485// allocate a set of ChannelData structs to help speed up the486// compress() and uncompress() functions, below, and determine487// if uncompressed pixel data should be in native or Xdr format.488//489490_tmpBuffer = new unsigned short491[checkArraySize (uiMult (maxScanLineSize, numScanLines),492sizeof (unsigned short))];493494const ChannelList &channels = header().channels();495int numHalfChans = 0;496497for (ChannelList::ConstIterator c = channels.begin();498c != channels.end();499++c)500{501assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);502++_numChans;503504if (c.channel().type == HALF)505++numHalfChans;506}507508//509// Compressed data may be larger than the input data510//511512size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;513514_outBuffer = new char515[uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];516517_channelData = new ChannelData[_numChans];518519int i = 0;520521for (ChannelList::ConstIterator c = channels.begin();522c != channels.end();523++c, ++i)524{525_channelData[i].ys = c.channel().ySampling;526_channelData[i].type = c.channel().type;527_channelData[i].pLinear = c.channel().pLinear;528_channelData[i].size =529pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);530}531532const Box2i &dataWindow = hdr.dataWindow();533534_minX = dataWindow.min.x;535_maxX = dataWindow.max.x;536_maxY = dataWindow.max.y;537538//539// We can support uncompressed data in the machine's native540// format only if all image channels are of type HALF.541//542543assert (sizeof (unsigned short) == pixelTypeSize (HALF));544545if (_numChans == numHalfChans)546_format = NATIVE;547}548549550B44Compressor::~B44Compressor ()551{552delete [] _tmpBuffer;553delete [] _outBuffer;554delete [] _channelData;555}556557558int559B44Compressor::numScanLines () const560{561return _numScanLines;562}563564565Compressor::Format566B44Compressor::format () const567{568return _format;569}570571572int573B44Compressor::compress (const char *inPtr,574int inSize,575int minY,576const char *&outPtr)577{578return compress (inPtr,579inSize,580Box2i (V2i (_minX, minY),581V2i (_maxX, minY + numScanLines() - 1)),582outPtr);583}584585586int587B44Compressor::compressTile (const char *inPtr,588int inSize,589Imath::Box2i range,590const char *&outPtr)591{592return compress (inPtr, inSize, range, outPtr);593}594595596int597B44Compressor::uncompress (const char *inPtr,598int inSize,599int minY,600const char *&outPtr)601{602return uncompress (inPtr,603inSize,604Box2i (V2i (_minX, minY),605V2i (_maxX, minY + numScanLines() - 1)),606outPtr);607}608609610int611B44Compressor::uncompressTile (const char *inPtr,612int inSize,613Imath::Box2i range,614const char *&outPtr)615{616return uncompress (inPtr, inSize, range, outPtr);617}618619620int621B44Compressor::compress (const char *inPtr,622int inSize,623Imath::Box2i range,624const char *&outPtr)625{626//627// Compress a block of pixel data: First copy the input pixels628// from the input buffer into _tmpBuffer, rearranging them such629// that blocks of 4x4 pixels of a single channel can be accessed630// conveniently. Then compress each 4x4 block of HALF pixel data631// and append the result to the output buffer. Copy UINT and632// FLOAT data to the output buffer without compressing them.633//634635outPtr = _outBuffer;636637if (inSize == 0)638{639//640// Special case - empty input buffer.641//642643return 0;644}645646//647// For each channel, detemine how many pixels are stored648// in the input buffer, and where those pixels will be649// placed in _tmpBuffer.650//651652int minX = range.min.x;653int maxX = min (range.max.x, _maxX);654int minY = range.min.y;655int maxY = min (range.max.y, _maxY);656657unsigned short *tmpBufferEnd = _tmpBuffer;658int i = 0;659660for (ChannelList::ConstIterator c = _channels.begin();661c != _channels.end();662++c, ++i)663{664ChannelData &cd = _channelData[i];665666cd.start = tmpBufferEnd;667cd.end = cd.start;668669cd.nx = numSamples (c.channel().xSampling, minX, maxX);670cd.ny = numSamples (c.channel().ySampling, minY, maxY);671672tmpBufferEnd += cd.nx * cd.ny * cd.size;673}674675if (_format == XDR)676{677//678// The data in the input buffer are in the machine-independent679// Xdr format. Copy the HALF channels into _tmpBuffer and680// convert them back into native format for compression.681// Copy UINT and FLOAT channels verbatim into _tmpBuffer.682//683684for (int y = minY; y <= maxY; ++y)685{686for (int i = 0; i < _numChans; ++i)687{688ChannelData &cd = _channelData[i];689690if (modp (y, cd.ys) != 0)691continue;692693if (cd.type == HALF)694{695for (int x = cd.nx; x > 0; --x)696{697Xdr::read <CharPtrIO> (inPtr, *cd.end);698++cd.end;699}700}701else702{703int n = cd.nx * cd.size;704memcpy (cd.end, inPtr, n * sizeof (unsigned short));705inPtr += n * sizeof (unsigned short);706cd.end += n;707}708}709}710}711else712{713//714// The input buffer contains only HALF channels, and they715// are in native, machine-dependent format. Copy the pixels716// into _tmpBuffer.717//718719for (int y = minY; y <= maxY; ++y)720{721for (int i = 0; i < _numChans; ++i)722{723ChannelData &cd = _channelData[i];724725#if defined (DEBUG)726assert (cd.type == HALF);727#endif728729if (modp (y, cd.ys) != 0)730continue;731732int n = cd.nx * cd.size;733memcpy (cd.end, inPtr, n * sizeof (unsigned short));734inPtr += n * sizeof (unsigned short);735cd.end += n;736}737}738}739740//741// The pixels for each channel have been packed into a contiguous742// block in _tmpBuffer. HALF channels are in native format; UINT743// and FLOAT channels are in Xdr format.744//745746#if defined (DEBUG)747748for (int i = 1; i < _numChans; ++i)749assert (_channelData[i-1].end == _channelData[i].start);750751assert (_channelData[_numChans-1].end == tmpBufferEnd);752753#endif754755//756// For each HALF channel, split the data in _tmpBuffer into 4x4757// pixel blocks. Compress each block and append the compressed758// data to the output buffer.759//760// UINT and FLOAT channels are copied from _tmpBuffer into the761// output buffer without further processing.762//763764char *outEnd = _outBuffer;765766for (int i = 0; i < _numChans; ++i)767{768ChannelData &cd = _channelData[i];769770if (cd.type != HALF)771{772//773// UINT or FLOAT channel.774//775776int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);777memcpy (outEnd, cd.start, n);778outEnd += n;779780continue;781}782783//784// HALF channel785//786787for (int y = 0; y < cd.ny; y += 4)788{789//790// Copy the next 4x4 pixel block into array s.791// If the width, cd.nx, or the height, cd.ny, of792// the pixel data in _tmpBuffer is not divisible793// by 4, then pad the data by repeating the794// rightmost column and the bottom row.795//796797unsigned short *row0 = cd.start + y * cd.nx;798unsigned short *row1 = row0 + cd.nx;799unsigned short *row2 = row1 + cd.nx;800unsigned short *row3 = row2 + cd.nx;801802if (y + 3 >= cd.ny)803{804if (y + 1 >= cd.ny)805row1 = row0;806807if (y + 2 >= cd.ny)808row2 = row1;809810row3 = row2;811}812813for (int x = 0; x < cd.nx; x += 4)814{815unsigned short s[16];816817if (x + 3 >= cd.nx)818{819int n = cd.nx - x;820821for (int i = 0; i < 4; ++i)822{823int j = min (i, n - 1);824825s[i + 0] = row0[j];826s[i + 4] = row1[j];827s[i + 8] = row2[j];828s[i + 12] = row3[j];829}830}831else832{833memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));834memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));835memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));836memcpy (&s[12], row3, 4 * sizeof (unsigned short));837}838839row0 += 4;840row1 += 4;841row2 += 4;842row3 += 4;843844//845// Compress the contents of array s and append the846// results to the output buffer.847//848849if (cd.pLinear)850convertFromLinear (s);851852outEnd += pack (s, (unsigned char *) outEnd,853_optFlatFields, !cd.pLinear);854}855}856}857858return outEnd - _outBuffer;859}860861862int863B44Compressor::uncompress (const char *inPtr,864int inSize,865Imath::Box2i range,866const char *&outPtr)867{868//869// This function is the reverse of the compress() function,870// above. First all pixels are moved from the input buffer871// into _tmpBuffer. UINT and FLOAT channels are copied872// verbatim; HALF channels are uncompressed in blocks of873// 4x4 pixels. Then the pixels in _tmpBuffer are copied874// into the output buffer and rearranged such that the data875// for for each scan line form a contiguous block.876//877878outPtr = _outBuffer;879880if (inSize == 0)881{882return 0;883}884885int minX = range.min.x;886int maxX = min (range.max.x, _maxX);887int minY = range.min.y;888int maxY = min (range.max.y, _maxY);889890unsigned short *tmpBufferEnd = _tmpBuffer;891int i = 0;892893for (ChannelList::ConstIterator c = _channels.begin();894c != _channels.end();895++c, ++i)896{897ChannelData &cd = _channelData[i];898899cd.start = tmpBufferEnd;900cd.end = cd.start;901902cd.nx = numSamples (c.channel().xSampling, minX, maxX);903cd.ny = numSamples (c.channel().ySampling, minY, maxY);904905tmpBufferEnd += cd.nx * cd.ny * cd.size;906}907908for (int i = 0; i < _numChans; ++i)909{910ChannelData &cd = _channelData[i];911912if (cd.type != HALF)913{914//915// UINT or FLOAT channel.916//917918int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);919920if (inSize < n)921notEnoughData();922923memcpy (cd.start, inPtr, n);924inPtr += n;925inSize -= n;926927continue;928}929930//931// HALF channel932//933934for (int y = 0; y < cd.ny; y += 4)935{936unsigned short *row0 = cd.start + y * cd.nx;937unsigned short *row1 = row0 + cd.nx;938unsigned short *row2 = row1 + cd.nx;939unsigned short *row3 = row2 + cd.nx;940941for (int x = 0; x < cd.nx; x += 4)942{943unsigned short s[16];944945if (inSize < 3)946notEnoughData();947948if (((const unsigned char *)inPtr)[2] == 0xfc)949{950unpack3 ((const unsigned char *)inPtr, s);951inPtr += 3;952inSize -= 3;953}954else955{956if (inSize < 14)957notEnoughData();958959unpack14 ((const unsigned char *)inPtr, s);960inPtr += 14;961inSize -= 14;962}963964if (cd.pLinear)965convertToLinear (s);966967int n = (x + 3 < cd.nx)?9684 * sizeof (unsigned short) :969(cd.nx - x) * sizeof (unsigned short);970971if (y + 3 < cd.ny)972{973memcpy (row0, &s[ 0], n);974memcpy (row1, &s[ 4], n);975memcpy (row2, &s[ 8], n);976memcpy (row3, &s[12], n);977}978else979{980memcpy (row0, &s[ 0], n);981982if (y + 1 < cd.ny)983memcpy (row1, &s[ 4], n);984985if (y + 2 < cd.ny)986memcpy (row2, &s[ 8], n);987}988989row0 += 4;990row1 += 4;991row2 += 4;992row3 += 4;993}994}995}996997char *outEnd = _outBuffer;998999if (_format == XDR)1000{1001for (int y = minY; y <= maxY; ++y)1002{1003for (int i = 0; i < _numChans; ++i)1004{1005ChannelData &cd = _channelData[i];10061007if (modp (y, cd.ys) != 0)1008continue;10091010if (cd.type == HALF)1011{1012for (int x = cd.nx; x > 0; --x)1013{1014Xdr::write <CharPtrIO> (outEnd, *cd.end);1015++cd.end;1016}1017}1018else1019{1020int n = cd.nx * cd.size;1021memcpy (outEnd, cd.end, n * sizeof (unsigned short));1022outEnd += n * sizeof (unsigned short);1023cd.end += n;1024}1025}1026}1027}1028else1029{1030for (int y = minY; y <= maxY; ++y)1031{1032for (int i = 0; i < _numChans; ++i)1033{1034ChannelData &cd = _channelData[i];10351036#if defined (DEBUG)1037assert (cd.type == HALF);1038#endif10391040if (modp (y, cd.ys) != 0)1041continue;10421043int n = cd.nx * cd.size;1044memcpy (outEnd, cd.end, n * sizeof (unsigned short));1045outEnd += n * sizeof (unsigned short);1046cd.end += n;1047}1048}1049}10501051#if defined (DEBUG)10521053for (int i = 1; i < _numChans; ++i)1054assert (_channelData[i-1].end == _channelData[i].start);10551056assert (_channelData[_numChans-1].end == tmpBufferEnd);10571058#endif10591060if (inSize > 0)1061tooMuchData();10621063outPtr = _outBuffer;1064return outEnd - _outBuffer;1065}106610671068} // namespace Imf106910701071