We need to split these steps up in preparation for multi-core support. Reading needs to be done in a serial manner, whilst decoding can be done in parallel. This also involved a rather large cleanup of the Tight decoder.tags/v1.6.90
@@ -15,7 +15,8 @@ | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#include <rdr/InStream.h> | |||
#include <rdr/MemInStream.h> | |||
#include <rdr/OutStream.h> | |||
#include <rfb/PixelBuffer.h> | |||
#include <rfb/CopyRectDecoder.h> | |||
@@ -30,10 +31,17 @@ CopyRectDecoder::~CopyRectDecoder() | |||
} | |||
void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
const ConnParams& cp, rdr::OutStream* os) | |||
{ | |||
int srcX = is->readU16(); | |||
int srcY = is->readU16(); | |||
os->copyBytes(is, 4); | |||
} | |||
void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
rdr::MemInStream is(buffer, buflen); | |||
int srcX = is.readU16(); | |||
int srcY = is.readU16(); | |||
pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY)); | |||
} |
@@ -27,7 +27,10 @@ namespace rfb { | |||
CopyRectDecoder(); | |||
virtual ~CopyRectDecoder(); | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb); | |||
const ConnParams& cp, rdr::OutStream* os); | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb); | |||
}; | |||
} | |||
#endif |
@@ -26,6 +26,7 @@ | |||
#include <rfb/LogWriter.h> | |||
#include <rdr/Exception.h> | |||
#include <rdr/MemOutStream.h> | |||
using namespace rfb; | |||
@@ -35,12 +36,14 @@ DecodeManager::DecodeManager(CConnection *conn) : | |||
conn(conn) | |||
{ | |||
memset(decoders, 0, sizeof(decoders)); | |||
bufferStream = new rdr::MemOutStream(); | |||
} | |||
DecodeManager::~DecodeManager() | |||
{ | |||
for (size_t i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++) | |||
delete decoders[i]; | |||
delete bufferStream; | |||
} | |||
void DecodeManager::decodeRect(const Rect& r, int encoding, | |||
@@ -60,5 +63,11 @@ void DecodeManager::decodeRect(const Rect& r, int encoding, | |||
throw rdr::Exception("Unknown encoding"); | |||
} | |||
} | |||
decoders[encoding]->readRect(r, conn->getInStream(), conn->cp, pb); | |||
bufferStream->clear(); | |||
decoders[encoding]->readRect(r, conn->getInStream(), | |||
conn->cp, bufferStream); | |||
decoders[encoding]->decodeRect(r, bufferStream->data(), | |||
bufferStream->length(), | |||
conn->cp, pb); | |||
} |
@@ -21,6 +21,8 @@ | |||
#include <rfb/encodings.h> | |||
namespace rdr { class MemOutStream; } | |||
namespace rfb { | |||
class CConnection; | |||
class Decoder; | |||
@@ -38,6 +40,7 @@ namespace rfb { | |||
private: | |||
CConnection *conn; | |||
Decoder *decoders[encodingMax+1]; | |||
rdr::MemOutStream *bufferStream; | |||
}; | |||
} | |||
@@ -19,7 +19,10 @@ | |||
#ifndef __RFB_DECODER_H__ | |||
#define __RFB_DECODER_H__ | |||
namespace rdr { class InStream; } | |||
namespace rdr { | |||
class InStream; | |||
class OutStream; | |||
} | |||
namespace rfb { | |||
class ConnParams; | |||
@@ -31,12 +34,20 @@ namespace rfb { | |||
Decoder(); | |||
virtual ~Decoder(); | |||
// readRect() is the main interface that decodes the given rectangle | |||
// with data from the given InStream, onto the ModifiablePixelBuffer. | |||
// The PixelFormat of the PixelBuffer might not match the ConnParams | |||
// and it is up to the decoder to do any necessary conversion. | |||
// These functions are the main interface to an individual decoder | |||
// readRect() transfers data for the given rectangle from the | |||
// InStream to the OutStream, possibly changing it along the way to | |||
// make it easier to decode. | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb)=0; | |||
const ConnParams& cp, rdr::OutStream* os)=0; | |||
// decodeRect() decodes the given rectangle with data from the | |||
// given buffer, onto the ModifiablePixelBuffer. The PixelFormat of | |||
// the PixelBuffer might not match the ConnParams and it is up to | |||
// the decoder to do any necessary conversion. | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb)=0; | |||
static bool supported(int encoding); | |||
static Decoder* createDecoder(int encoding); |
@@ -15,7 +15,11 @@ | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#include <rdr/InStream.h> | |||
#include <rdr/MemInStream.h> | |||
#include <rdr/OutStream.h> | |||
#include <rfb/ConnParams.h> | |||
#include <rfb/PixelBuffer.h> | |||
#include <rfb/HextileDecoder.h> | |||
@@ -41,13 +45,60 @@ HextileDecoder::~HextileDecoder() | |||
} | |||
void HextileDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb) | |||
const ConnParams& cp, rdr::OutStream* os) | |||
{ | |||
Rect t; | |||
size_t bytesPerPixel; | |||
bytesPerPixel = cp.pf().bpp/8; | |||
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { | |||
t.br.y = __rfbmin(r.br.y, t.tl.y + 16); | |||
for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) { | |||
rdr::U8 tileType; | |||
t.br.x = __rfbmin(r.br.x, t.tl.x + 16); | |||
tileType = is->readU8(); | |||
os->writeU8(tileType); | |||
if (tileType & hextileRaw) { | |||
os->copyBytes(is, t.area() * bytesPerPixel); | |||
continue; | |||
} | |||
if (tileType & hextileBgSpecified) | |||
os->copyBytes(is, bytesPerPixel); | |||
if (tileType & hextileFgSpecified) | |||
os->copyBytes(is, bytesPerPixel); | |||
if (tileType & hextileAnySubrects) { | |||
rdr::U8 nSubrects; | |||
nSubrects = is->readU8(); | |||
os->writeU8(nSubrects); | |||
if (tileType & hextileSubrectsColoured) | |||
os->copyBytes(is, nSubrects * (bytesPerPixel + 2)); | |||
else | |||
os->copyBytes(is, nSubrects * 2); | |||
} | |||
} | |||
} | |||
} | |||
void HextileDecoder::decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
rdr::MemInStream is(buffer, buflen); | |||
const PixelFormat& pf = cp.pf(); | |||
rdr::U8 buf[16 * 16 * 4 * pf.bpp/8]; | |||
switch (pf.bpp) { | |||
case 8: hextileDecode8 (r, is, (rdr::U8*) buf, pf, pb); break; | |||
case 16: hextileDecode16(r, is, (rdr::U16*)buf, pf, pb); break; | |||
case 32: hextileDecode32(r, is, (rdr::U32*)buf, pf, pb); break; | |||
case 8: hextileDecode8 (r, &is, pf, pb); break; | |||
case 16: hextileDecode16(r, &is, pf, pb); break; | |||
case 32: hextileDecode32(r, &is, pf, pb); break; | |||
} | |||
} |
@@ -27,7 +27,10 @@ namespace rfb { | |||
HextileDecoder(); | |||
virtual ~HextileDecoder(); | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb); | |||
const ConnParams& cp, rdr::OutStream* os); | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb); | |||
}; | |||
} | |||
#endif |
@@ -15,7 +15,11 @@ | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#include <rdr/InStream.h> | |||
#include <rdr/MemInStream.h> | |||
#include <rdr/OutStream.h> | |||
#include <rfb/ConnParams.h> | |||
#include <rfb/PixelBuffer.h> | |||
#include <rfb/RREDecoder.h> | |||
@@ -41,12 +45,25 @@ RREDecoder::~RREDecoder() | |||
} | |||
void RREDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb) | |||
const ConnParams& cp, rdr::OutStream* os) | |||
{ | |||
rdr::U32 numRects; | |||
numRects = is->readU32(); | |||
os->writeU32(numRects); | |||
os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8)); | |||
} | |||
void RREDecoder::decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
rdr::MemInStream is(buffer, buflen); | |||
const PixelFormat& pf = cp.pf(); | |||
switch (pf.bpp) { | |||
case 8: rreDecode8 (r, is, pf, pb); break; | |||
case 16: rreDecode16(r, is, pf, pb); break; | |||
case 32: rreDecode32(r, is, pf, pb); break; | |||
case 8: rreDecode8 (r, &is, pf, pb); break; | |||
case 16: rreDecode16(r, &is, pf, pb); break; | |||
case 32: rreDecode32(r, &is, pf, pb); break; | |||
} | |||
} |
@@ -27,7 +27,10 @@ namespace rfb { | |||
RREDecoder(); | |||
virtual ~RREDecoder(); | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb); | |||
const ConnParams& cp, rdr::OutStream* os); | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb); | |||
}; | |||
} | |||
#endif |
@@ -15,7 +15,10 @@ | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#include <rdr/InStream.h> | |||
#include <assert.h> | |||
#include <rdr/OutStream.h> | |||
#include <rfb/ConnParams.h> | |||
#include <rfb/PixelBuffer.h> | |||
#include <rfb/RawDecoder.h> | |||
@@ -31,36 +34,15 @@ RawDecoder::~RawDecoder() | |||
} | |||
void RawDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb) | |||
const ConnParams& cp, rdr::OutStream* os) | |||
{ | |||
const PixelFormat& pf = cp.pf(); | |||
rdr::U8 imageBuf[16384]; | |||
const int maxPixels = sizeof(imageBuf) / (pf.bpp/8); | |||
int x = r.tl.x; | |||
int y = r.tl.y; | |||
int w = r.width(); | |||
int h = r.height(); | |||
while (h > 0) { | |||
int dx; | |||
dx = 0; | |||
while (dx < w) { | |||
int dw; | |||
dw = maxPixels; | |||
if (dx + dw > w) | |||
dw = w - dx; | |||
is->readBytes(imageBuf, dw * pf.bpp/8); | |||
pb->imageRect(pf, Rect(x+dx, y, x+dx+dw, y+1), imageBuf); | |||
dx += dw; | |||
} | |||
os->copyBytes(is, r.area() * cp.pf().bpp/8); | |||
} | |||
y++; | |||
h--; | |||
} | |||
void RawDecoder::decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
assert(buflen >= (size_t)r.area() * cp.pf().bpp/8); | |||
pb->imageRect(cp.pf(), r, buffer); | |||
} |
@@ -26,7 +26,10 @@ namespace rfb { | |||
RawDecoder(); | |||
virtual ~RawDecoder(); | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb); | |||
const ConnParams& cp, rdr::OutStream* os); | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb); | |||
}; | |||
} | |||
#endif |
@@ -1,5 +1,6 @@ | |||
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. | |||
* Copyright 2004-2005 Cendio AB. | |||
* Copyright 2009-2015 Pierre Ossman for Cendio AB | |||
* Copyright (C) 2011 D. R. Commander. All Rights Reserved. | |||
* | |||
* This is free software; you can redistribute it and/or modify | |||
@@ -17,14 +18,23 @@ | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#include <assert.h> | |||
#include <rdr/InStream.h> | |||
#include <rdr/MemInStream.h> | |||
#include <rdr/OutStream.h> | |||
#include <rfb/ConnParams.h> | |||
#include <rfb/Exception.h> | |||
#include <rfb/PixelBuffer.h> | |||
#include <rfb/TightConstants.h> | |||
#include <rfb/TightDecoder.h> | |||
using namespace rfb; | |||
#define TIGHT_MAX_WIDTH 2048 | |||
static const int TIGHT_MAX_WIDTH = 2048; | |||
static const int TIGHT_MIN_TO_COMPRESS = 12; | |||
#define BPP 8 | |||
#include <rfb/tightDecode.h> | |||
@@ -45,29 +55,355 @@ TightDecoder::~TightDecoder() | |||
} | |||
void TightDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb) | |||
const ConnParams& cp, rdr::OutStream* os) | |||
{ | |||
rdr::U8 comp_ctl; | |||
comp_ctl = is->readU8(); | |||
os->writeU8(comp_ctl); | |||
comp_ctl >>= 4; | |||
// "Fill" compression type. | |||
if (comp_ctl == tightFill) { | |||
if (cp.pf().is888()) | |||
os->copyBytes(is, 3); | |||
else | |||
os->copyBytes(is, cp.pf().bpp/8); | |||
return; | |||
} | |||
// "JPEG" compression type. | |||
if (comp_ctl == tightJpeg) { | |||
rdr::U32 len; | |||
len = readCompact(is); | |||
os->writeOpaque32(len); | |||
os->copyBytes(is, len); | |||
return; | |||
} | |||
// Quit on unsupported compression type. | |||
if (comp_ctl > tightMaxSubencoding) | |||
throw Exception("TightDecoder: bad subencoding value received"); | |||
// "Basic" compression type. | |||
int palSize = 0; | |||
if (r.width() > TIGHT_MAX_WIDTH) | |||
throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width()); | |||
// Possible palette | |||
if ((comp_ctl & tightExplicitFilter) != 0) { | |||
rdr::U8 filterId; | |||
filterId = is->readU8(); | |||
os->writeU8(filterId); | |||
switch (filterId) { | |||
case tightFilterPalette: | |||
palSize = is->readU8() + 1; | |||
os->writeU8(palSize - 1); | |||
if (cp.pf().is888()) | |||
os->copyBytes(is, palSize * 3); | |||
else | |||
os->copyBytes(is, palSize * cp.pf().bpp/8); | |||
break; | |||
case tightFilterGradient: | |||
if (cp.pf().bpp == 8) | |||
throw Exception("TightDecoder: invalid BPP for gradient filter"); | |||
break; | |||
case tightFilterCopy: | |||
break; | |||
default: | |||
throw Exception("TightDecoder: unknown filter code received"); | |||
} | |||
} | |||
size_t rowSize, dataSize; | |||
if (palSize != 0) { | |||
if (palSize <= 2) | |||
rowSize = (r.width() + 7) / 8; | |||
else | |||
rowSize = r.width(); | |||
} else if (cp.pf().is888()) { | |||
rowSize = r.width() * 3; | |||
} else { | |||
rowSize = r.width() * cp.pf().bpp/8; | |||
} | |||
dataSize = r.height() * rowSize; | |||
if (dataSize < TIGHT_MIN_TO_COMPRESS) | |||
os->copyBytes(is, dataSize); | |||
else { | |||
rdr::U32 len; | |||
len = readCompact(is); | |||
os->writeOpaque32(len); | |||
os->copyBytes(is, len); | |||
} | |||
} | |||
void TightDecoder::decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
this->is = is; | |||
this->pb = pb; | |||
clientpf = pb->getPF(); | |||
serverpf = cp.pf(); | |||
const rdr::U8* bufptr; | |||
const PixelFormat& pf = cp.pf(); | |||
rdr::U8 comp_ctl; | |||
bufptr = (const rdr::U8*)buffer; | |||
assert(buflen >= 1); | |||
comp_ctl = *bufptr; | |||
bufptr += 1; | |||
buflen -= 1; | |||
// Flush zlib streams if we are told by the server to do so. | |||
for (int i = 0; i < 4; i++) { | |||
if (comp_ctl & 1) { | |||
zis[i].reset(); | |||
} | |||
comp_ctl >>= 1; | |||
} | |||
// "Fill" compression type. | |||
if (comp_ctl == tightFill) { | |||
if (pf.is888()) { | |||
rdr::U8 pix[4]; | |||
assert(buflen >= 3); | |||
pf.bufferFromRGB(pix, bufptr, 1); | |||
pb->fillRect(pf, r, pix); | |||
} else { | |||
assert(buflen >= (size_t)pf.bpp/8); | |||
pb->fillRect(pf, r, bufptr); | |||
} | |||
return; | |||
} | |||
// "JPEG" compression type. | |||
if (comp_ctl == tightJpeg) { | |||
rdr::U32 len; | |||
int stride; | |||
rdr::U8 *buf; | |||
assert(buflen >= 4); | |||
if (clientpf.equal(serverpf)) { | |||
/* Decode directly into the framebuffer (fast path) */ | |||
memcpy(&len, bufptr, 4); | |||
bufptr += 4; | |||
buflen -= 4; | |||
// We always use direct decoding with JPEG images | |||
buf = pb->getBufferRW(r, &stride); | |||
jd.decompress(bufptr, len, buf, stride, r, pb->getPF()); | |||
pb->commitBufferRW(r); | |||
return; | |||
} | |||
// Quit on unsupported compression type. | |||
assert(comp_ctl <= tightMaxSubencoding); | |||
// "Basic" compression type. | |||
int palSize = 0; | |||
rdr::U8 palette[256 * 4]; | |||
bool useGradient = false; | |||
if ((comp_ctl & tightExplicitFilter) != 0) { | |||
rdr::U8 filterId; | |||
assert(buflen >= 1); | |||
filterId = *bufptr; | |||
bufptr += 1; | |||
buflen -= 1; | |||
switch (filterId) { | |||
case tightFilterPalette: | |||
assert(buflen >= 1); | |||
palSize = *bufptr + 1; | |||
bufptr += 1; | |||
buflen -= 1; | |||
if (pf.is888()) { | |||
rdr::U8 tightPalette[palSize * 3]; | |||
assert(buflen >= sizeof(tightPalette)); | |||
memcpy(tightPalette, bufptr, sizeof(tightPalette)); | |||
bufptr += sizeof(tightPalette); | |||
buflen -= sizeof(tightPalette); | |||
pf.bufferFromRGB(palette, tightPalette, palSize); | |||
} else { | |||
size_t len; | |||
len = palSize * pf.bpp/8; | |||
assert(buflen >= len); | |||
memcpy(palette, bufptr, len); | |||
bufptr += len; | |||
buflen -= len; | |||
} | |||
break; | |||
case tightFilterGradient: | |||
useGradient = true; | |||
break; | |||
case tightFilterCopy: | |||
break; | |||
default: | |||
assert(false); | |||
} | |||
} | |||
// Determine if the data should be decompressed or just copied. | |||
size_t rowSize, dataSize; | |||
rdr::U8* netbuf; | |||
netbuf = NULL; | |||
if (palSize != 0) { | |||
if (palSize <= 2) | |||
rowSize = (r.width() + 7) / 8; | |||
else | |||
rowSize = r.width(); | |||
} else if (pf.is888()) { | |||
rowSize = r.width() * 3; | |||
} else { | |||
rowSize = r.width() * pf.bpp/8; | |||
} | |||
dataSize = r.height() * rowSize; | |||
if (dataSize < TIGHT_MIN_TO_COMPRESS) | |||
assert(buflen >= dataSize); | |||
else { | |||
rdr::U32 len; | |||
int streamId; | |||
rdr::MemInStream* ms; | |||
assert(buflen >= 4); | |||
memcpy(&len, bufptr, 4); | |||
bufptr += 4; | |||
buflen -= 4; | |||
assert(buflen >= len); | |||
streamId = comp_ctl & 0x03; | |||
ms = new rdr::MemInStream(bufptr, len); | |||
zis[streamId].setUnderlying(ms, len); | |||
// Allocate buffer and decompress the data | |||
netbuf = new rdr::U8[dataSize]; | |||
zis[streamId].readBytes(netbuf, dataSize); | |||
zis[streamId].reset(); | |||
delete ms; | |||
bufptr = netbuf; | |||
buflen = dataSize; | |||
} | |||
// Time to decode the actual data | |||
bool directDecode; | |||
rdr::U8* outbuf; | |||
int stride; | |||
if (pb->getPF().equal(pf)) { | |||
// Decode directly into the framebuffer (fast path) | |||
directDecode = true; | |||
} else { | |||
/* Decode into an intermediate buffer and use pixel translation */ | |||
// Decode into an intermediate buffer and use pixel translation | |||
directDecode = false; | |||
} | |||
switch (serverpf.bpp) { | |||
case 8: | |||
tightDecode8 (r); break; | |||
case 16: | |||
tightDecode16(r); break; | |||
case 32: | |||
tightDecode32(r); break; | |||
if (directDecode) | |||
outbuf = pb->getBufferRW(r, &stride); | |||
else { | |||
outbuf = new rdr::U8[r.area() * pf.bpp/8]; | |||
stride = r.width(); | |||
} | |||
if (palSize == 0) { | |||
// Truecolor data | |||
if (useGradient) { | |||
if (pf.is888()) | |||
FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r); | |||
else { | |||
switch (pf.bpp) { | |||
case 8: | |||
assert(false); | |||
break; | |||
case 16: | |||
FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r); | |||
break; | |||
case 32: | |||
FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r); | |||
break; | |||
} | |||
} | |||
} else { | |||
// Copy | |||
rdr::U8* ptr = outbuf; | |||
const rdr::U8* srcPtr = bufptr; | |||
int w = r.width(); | |||
int h = r.height(); | |||
if (pf.is888()) { | |||
while (h > 0) { | |||
pf.bufferFromRGB(ptr, srcPtr, w); | |||
ptr += stride * pf.bpp/8; | |||
srcPtr += w * 3; | |||
h--; | |||
} | |||
} else { | |||
while (h > 0) { | |||
memcpy(ptr, srcPtr, w * pf.bpp/8); | |||
ptr += stride * pf.bpp/8; | |||
srcPtr += w * pf.bpp/8; | |||
h--; | |||
} | |||
} | |||
} | |||
} else { | |||
// Indexed color | |||
switch (pf.bpp) { | |||
case 8: | |||
FilterPalette((const rdr::U8*)palette, palSize, | |||
bufptr, (rdr::U8*)outbuf, stride, r); | |||
break; | |||
case 16: | |||
FilterPalette((const rdr::U16*)palette, palSize, | |||
bufptr, (rdr::U16*)outbuf, stride, r); | |||
break; | |||
case 32: | |||
FilterPalette((const rdr::U32*)palette, palSize, | |||
bufptr, (rdr::U32*)outbuf, stride, r); | |||
break; | |||
} | |||
} | |||
if (directDecode) | |||
pb->commitBufferRW(r); | |||
else { | |||
pb->imageRect(pf, r, outbuf); | |||
delete [] outbuf; | |||
} | |||
delete [] netbuf; | |||
} | |||
rdr::U32 TightDecoder::readCompact(rdr::InStream* is) |
@@ -1,5 +1,6 @@ | |||
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. | |||
* Copyright (C) 2011 D. R. Commander. All Rights Reserved. | |||
* Copyright 2009-2015 Pierre Ossman for Cendio AB | |||
* | |||
* This is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
@@ -31,39 +32,35 @@ namespace rfb { | |||
TightDecoder(); | |||
virtual ~TightDecoder(); | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb); | |||
const ConnParams& cp, rdr::OutStream* os); | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb); | |||
private: | |||
rdr::U32 readCompact(rdr::InStream* is); | |||
void tightDecode8(const Rect& r); | |||
void tightDecode16(const Rect& r); | |||
void tightDecode32(const Rect& r); | |||
void FilterGradient24(const rdr::U8* inbuf, const PixelFormat& pf, | |||
rdr::U32* outbuf, int stride, const Rect& r); | |||
void DecompressJpegRect8(const Rect& r); | |||
void DecompressJpegRect16(const Rect& r); | |||
void DecompressJpegRect32(const Rect& r); | |||
void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf, | |||
rdr::U16* outbuf, int stride, const Rect& r); | |||
void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf, | |||
rdr::U32* outbuf, int stride, const Rect& r); | |||
void FilterGradient8(rdr::U8 *netbuf, rdr::U8* buf, int stride, | |||
const Rect& r); | |||
void FilterGradient16(rdr::U8 *netbuf, rdr::U16* buf, int stride, | |||
const Rect& r); | |||
void FilterGradient24(rdr::U8 *netbuf, rdr::U32* buf, int stride, | |||
const Rect& r); | |||
void FilterGradient32(rdr::U8 *netbuf, rdr::U32* buf, int stride, | |||
const Rect& r); | |||
void FilterPalette(const rdr::U8* palette, int palSize, | |||
const rdr::U8* inbuf, rdr::U8* outbuf, | |||
int stride, const Rect& r); | |||
void FilterPalette(const rdr::U16* palette, int palSize, | |||
const rdr::U8* inbuf, rdr::U16* outbuf, | |||
int stride, const Rect& r); | |||
void FilterPalette(const rdr::U32* palette, int palSize, | |||
const rdr::U8* inbuf, rdr::U32* outbuf, | |||
int stride, const Rect& r); | |||
void directFillRect8(const Rect& r, Pixel pix); | |||
void directFillRect16(const Rect& r, Pixel pix); | |||
void directFillRect32(const Rect& r, Pixel pix); | |||
ModifiablePixelBuffer* pb; | |||
rdr::InStream* is; | |||
private: | |||
rdr::ZlibInStream zis[4]; | |||
JpegDecompressor jd; | |||
PixelFormat clientpf; | |||
PixelFormat serverpf; | |||
bool directDecode; | |||
}; | |||
} | |||
@@ -15,7 +15,11 @@ | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||
* USA. | |||
*/ | |||
#include <rdr/InStream.h> | |||
#include <rdr/MemInStream.h> | |||
#include <rdr/OutStream.h> | |||
#include <rfb/ConnParams.h> | |||
#include <rfb/PixelBuffer.h> | |||
#include <rfb/ZRLEDecoder.h> | |||
@@ -67,13 +71,25 @@ ZRLEDecoder::~ZRLEDecoder() | |||
} | |||
void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb) | |||
const ConnParams& cp, rdr::OutStream* os) | |||
{ | |||
rdr::U32 len; | |||
len = is->readU32(); | |||
os->writeU32(len); | |||
os->copyBytes(is, len); | |||
} | |||
void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
rdr::MemInStream is(buffer, buflen); | |||
const rfb::PixelFormat& pf = cp.pf(); | |||
rdr::U8* buf[64 * 64 * 4 * pf.bpp/8]; | |||
switch (pf.bpp) { | |||
case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, pf, pb); break; | |||
case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, pf, pb); break; | |||
case 8: zrleDecode8 (r, &is, &zis, (rdr::U8*) buf, pf, pb); break; | |||
case 16: zrleDecode16(r, &is, &zis, (rdr::U16*)buf, pf, pb); break; | |||
case 32: | |||
{ | |||
Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); | |||
@@ -83,16 +99,16 @@ void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is, | |||
if ((fitsInLS3Bytes && pf.isLittleEndian()) || | |||
(fitsInMS3Bytes && pf.isBigEndian())) | |||
{ | |||
zrleDecode24A(r, is, &zis, (rdr::U32*)buf, pf, pb); | |||
zrleDecode24A(r, &is, &zis, (rdr::U32*)buf, pf, pb); | |||
} | |||
else if ((fitsInLS3Bytes && pf.isBigEndian()) || | |||
(fitsInMS3Bytes && pf.isLittleEndian())) | |||
{ | |||
zrleDecode24B(r, is, &zis, (rdr::U32*)buf, pf, pb); | |||
zrleDecode24B(r, &is, &zis, (rdr::U32*)buf, pf, pb); | |||
} | |||
else | |||
{ | |||
zrleDecode32(r, is, &zis, (rdr::U32*)buf, pf, pb); | |||
zrleDecode32(r, &is, &zis, (rdr::U32*)buf, pf, pb); | |||
} | |||
break; | |||
} |
@@ -28,7 +28,10 @@ namespace rfb { | |||
ZRLEDecoder(); | |||
virtual ~ZRLEDecoder(); | |||
virtual void readRect(const Rect& r, rdr::InStream* is, | |||
const ConnParams& cp, ModifiablePixelBuffer* pb); | |||
const ConnParams& cp, rdr::OutStream* os); | |||
virtual void decodeRect(const Rect& r, const void* buffer, | |||
size_t buflen, const ConnParams& cp, | |||
ModifiablePixelBuffer* pb); | |||
private: | |||
rdr::ZlibInStream zis; | |||
}; |
@@ -37,12 +37,14 @@ namespace rfb { | |||
#define READ_PIXEL CONCAT2E(readOpaque,BPP) | |||
#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP) | |||
void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, | |||
const PixelFormat& pf, ModifiablePixelBuffer* pb) | |||
static void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, | |||
const PixelFormat& pf, | |||
ModifiablePixelBuffer* pb) | |||
{ | |||
Rect t; | |||
PIXEL_T bg = 0; | |||
PIXEL_T fg = 0; | |||
PIXEL_T buf[16 * 16 * 4]; | |||
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { | |||
@@ -55,20 +57,20 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, | |||
int tileType = is->readU8(); | |||
if (tileType & hextileRaw) { | |||
is->readBytes(buf, t.area() * (BPP/8)); | |||
pb->imageRect(pf, t, buf); | |||
continue; | |||
is->readBytes(buf, t.area() * (BPP/8)); | |||
pb->imageRect(pf, t, buf); | |||
continue; | |||
} | |||
if (tileType & hextileBgSpecified) | |||
bg = is->READ_PIXEL(); | |||
bg = is->READ_PIXEL(); | |||
int len = t.area(); | |||
PIXEL_T* ptr = (PIXEL_T*)buf; | |||
PIXEL_T* ptr = buf; | |||
while (len-- > 0) *ptr++ = bg; | |||
if (tileType & hextileFgSpecified) | |||
fg = is->READ_PIXEL(); | |||
fg = is->READ_PIXEL(); | |||
if (tileType & hextileAnySubrects) { | |||
int nSubrects = is->readU8(); | |||
@@ -85,7 +87,7 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, | |||
int y = (xy & 15); | |||
int w = ((wh >> 4) & 15) + 1; | |||
int h = (wh & 15) + 1; | |||
PIXEL_T* ptr = (PIXEL_T*)buf + y * t.width() + x; | |||
PIXEL_T* ptr = buf + y * t.width() + x; | |||
int rowAdd = t.width() - w; | |||
while (h-- > 0) { | |||
int len = w; |
@@ -1,5 +1,6 @@ | |||
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. | |||
* Copyright 2004-2005 Cendio AB. | |||
* Copyright 2009-2015 Pierre Ossman for Cendio AB | |||
* Copyright (C) 2011 D. R. Commander. All Rights Reserved. | |||
* | |||
* This is free software; you can redistribute it and/or modify | |||
@@ -24,11 +25,6 @@ | |||
// This file is #included after having set the following macro: | |||
// BPP - 8, 16 or 32 | |||
#include <rdr/InStream.h> | |||
#include <rdr/ZlibInStream.h> | |||
#include <rfb/Exception.h> | |||
#include <rfb/TightConstants.h> | |||
namespace rfb { | |||
// CONCAT2E concatenates its arguments, expanding them if they are macros | |||
@@ -39,242 +35,17 @@ namespace rfb { | |||
#endif | |||
#define PIXEL_T rdr::CONCAT2E(U,BPP) | |||
#define READ_PIXEL CONCAT2E(readOpaque,BPP) | |||
#define TIGHT_DECODE TightDecoder::CONCAT2E(tightDecode,BPP) | |||
#define DECOMPRESS_JPEG_RECT TightDecoder::CONCAT2E(DecompressJpegRect,BPP) | |||
#define FILTER_GRADIENT TightDecoder::CONCAT2E(FilterGradient,BPP) | |||
#define TIGHT_MIN_TO_COMPRESS 12 | |||
// Main function implementing Tight decoder | |||
void TIGHT_DECODE (const Rect& r) | |||
{ | |||
bool cutZeros = false; | |||
#if BPP == 32 | |||
if (serverpf.is888()) { | |||
cutZeros = true; | |||
} | |||
#endif | |||
rdr::U8 comp_ctl = is->readU8(); | |||
// Flush zlib streams if we are told by the server to do so. | |||
for (int i = 0; i < 4; i++) { | |||
if (comp_ctl & 1) { | |||
zis[i].reset(); | |||
} | |||
comp_ctl >>= 1; | |||
} | |||
// "Fill" compression type. | |||
if (comp_ctl == tightFill) { | |||
PIXEL_T pix; | |||
if (cutZeros) { | |||
rdr::U8 bytebuf[3]; | |||
is->readBytes(bytebuf, 3); | |||
serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1); | |||
} else { | |||
pix = is->READ_PIXEL(); | |||
} | |||
pb->fillRect(serverpf, r, &pix); | |||
return; | |||
} | |||
// "JPEG" compression type. | |||
if (comp_ctl == tightJpeg) { | |||
DECOMPRESS_JPEG_RECT(r); | |||
return; | |||
} | |||
// Quit on unsupported compression type. | |||
if (comp_ctl > tightMaxSubencoding) { | |||
throw Exception("TightDecoder: bad subencoding value received"); | |||
return; | |||
} | |||
// "Basic" compression type. | |||
int palSize = 0; | |||
static PIXEL_T palette[256]; | |||
bool useGradient = false; | |||
if ((comp_ctl & tightExplicitFilter) != 0) { | |||
rdr::U8 filterId = is->readU8(); | |||
switch (filterId) { | |||
case tightFilterPalette: | |||
palSize = is->readU8() + 1; | |||
if (cutZeros) { | |||
rdr::U8 tightPalette[256 * 3]; | |||
is->readBytes(tightPalette, palSize * 3); | |||
serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize); | |||
} else { | |||
is->readBytes(palette, palSize * sizeof(PIXEL_T)); | |||
} | |||
break; | |||
case tightFilterGradient: | |||
useGradient = true; | |||
break; | |||
case tightFilterCopy: | |||
break; | |||
default: | |||
throw Exception("TightDecoder: unknown filter code received"); | |||
return; | |||
} | |||
} | |||
int bppp = BPP; | |||
if (palSize != 0) { | |||
bppp = (palSize <= 2) ? 1 : 8; | |||
} else if (cutZeros) { | |||
bppp = 24; | |||
} | |||
// Determine if the data should be decompressed or just copied. | |||
int rowSize = (r.width() * bppp + 7) / 8; | |||
int dataSize = r.height() * rowSize; | |||
int streamId = -1; | |||
rdr::InStream *input; | |||
if (dataSize < TIGHT_MIN_TO_COMPRESS) { | |||
input = is; | |||
} else { | |||
int length = readCompact(is); | |||
streamId = comp_ctl & 0x03; | |||
zis[streamId].setUnderlying(is, length); | |||
input = &zis[streamId]; | |||
} | |||
// Allocate netbuf and read in data | |||
rdr::U8 *netbuf = new rdr::U8[dataSize]; | |||
if (!netbuf) { | |||
throw Exception("rfb::TightDecoder::tightDecode unable to allocate buffer"); | |||
} | |||
input->readBytes(netbuf, dataSize); | |||
PIXEL_T *buf; | |||
int stride = r.width(); | |||
if (directDecode) | |||
buf = (PIXEL_T *)pb->getBufferRW(r, &stride); | |||
else | |||
buf = new PIXEL_T[r.area()]; | |||
if (palSize == 0) { | |||
// Truecolor data | |||
if (useGradient) { | |||
#if BPP == 32 | |||
if (cutZeros) { | |||
FilterGradient24(netbuf, buf, stride, r); | |||
} else | |||
#endif | |||
{ | |||
FILTER_GRADIENT(netbuf, buf, stride, r); | |||
} | |||
} else { | |||
// Copy | |||
int h = r.height(); | |||
PIXEL_T *ptr = buf; | |||
rdr::U8 *srcPtr = netbuf; | |||
int w = r.width(); | |||
if (cutZeros) { | |||
while (h > 0) { | |||
serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w); | |||
ptr += stride; | |||
srcPtr += w * 3; | |||
h--; | |||
} | |||
} else { | |||
while (h > 0) { | |||
memcpy(ptr, srcPtr, w * sizeof(PIXEL_T)); | |||
ptr += stride; | |||
srcPtr += w * sizeof(PIXEL_T); | |||
h--; | |||
} | |||
} | |||
} | |||
} else { | |||
// Indexed color | |||
int x, h = r.height(), w = r.width(), b, pad = stride - w; | |||
PIXEL_T *ptr = buf; | |||
rdr::U8 bits, *srcPtr = netbuf; | |||
if (palSize <= 2) { | |||
// 2-color palette | |||
while (h > 0) { | |||
for (x = 0; x < w / 8; x++) { | |||
bits = *srcPtr++; | |||
for (b = 7; b >= 0; b--) { | |||
*ptr++ = palette[bits >> b & 1]; | |||
} | |||
} | |||
if (w % 8 != 0) { | |||
bits = *srcPtr++; | |||
for (b = 7; b >= 8 - w % 8; b--) { | |||
*ptr++ = palette[bits >> b & 1]; | |||
} | |||
} | |||
ptr += pad; | |||
h--; | |||
} | |||
} else { | |||
// 256-color palette | |||
while (h > 0) { | |||
PIXEL_T *endOfRow = ptr + w; | |||
while (ptr < endOfRow) { | |||
*ptr++ = palette[*srcPtr++]; | |||
} | |||
ptr += pad; | |||
h--; | |||
} | |||
} | |||
} | |||
if (directDecode) | |||
pb->commitBufferRW(r); | |||
else { | |||
pb->imageRect(serverpf, r, buf); | |||
delete [] buf; | |||
} | |||
delete [] netbuf; | |||
if (streamId != -1) { | |||
zis[streamId].reset(); | |||
} | |||
} | |||
void | |||
DECOMPRESS_JPEG_RECT(const Rect& r) | |||
{ | |||
// Read length | |||
int compressedLen = readCompact(is); | |||
if (compressedLen <= 0) { | |||
throw Exception("Incorrect data received from the server.\n"); | |||
} | |||
// Allocate netbuf and read in data | |||
rdr::U8* netbuf = new rdr::U8[compressedLen]; | |||
if (!netbuf) { | |||
throw Exception("rfb::TightDecoder::DecompressJpegRect unable to allocate buffer"); | |||
} | |||
is->readBytes(netbuf, compressedLen); | |||
// We always use direct decoding with JPEG images | |||
int stride; | |||
rdr::U8 *buf = pb->getBufferRW(r, &stride); | |||
jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf); | |||
pb->commitBufferRW(r); | |||
delete [] netbuf; | |||
} | |||
#if BPP == 32 | |||
void | |||
TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, | |||
const Rect& r) | |||
TightDecoder::FilterGradient24(const rdr::U8 *inbuf, | |||
const PixelFormat& pf, PIXEL_T* outbuf, | |||
int stride, const Rect& r) | |||
{ | |||
int x, y, c; | |||
static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; | |||
static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; | |||
rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; | |||
rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; | |||
rdr::U8 pix[3]; | |||
int est[3]; | |||
@@ -287,10 +58,10 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, | |||
for (y = 0; y < rectHeight; y++) { | |||
/* First pixel in a row */ | |||
for (c = 0; c < 3; c++) { | |||
pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c]; | |||
pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c]; | |||
thisRow[c] = pix[c]; | |||
} | |||
serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1); | |||
pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); | |||
/* Remaining pixels of a row */ | |||
for (x = 1; x < rectWidth; x++) { | |||
@@ -301,10 +72,10 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, | |||
} else if (est[c] < 0) { | |||
est[c] = 0; | |||
} | |||
pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c]; | |||
pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c]; | |||
thisRow[x*3+c] = pix[c]; | |||
} | |||
serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1); | |||
pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); | |||
} | |||
memcpy(prevRow, thisRow, sizeof(prevRow)); | |||
@@ -313,12 +84,15 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, | |||
#endif | |||
void | |||
FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) | |||
#if BPP != 8 | |||
void TightDecoder::FilterGradient(const rdr::U8* inbuf, | |||
const PixelFormat& pf, PIXEL_T* outbuf, | |||
int stride, const Rect& r) | |||
{ | |||
int x, y, c; | |||
static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)]; | |||
static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)]; | |||
static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; | |||
static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; | |||
rdr::U8 pix[3]; | |||
int est[3]; | |||
@@ -330,13 +104,13 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) | |||
for (y = 0; y < rectHeight; y++) { | |||
/* First pixel in a row */ | |||
serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1); | |||
pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1); | |||
for (c = 0; c < 3; c++) | |||
pix[c] += prevRow[c]; | |||
memcpy(thisRow, pix, sizeof(pix)); | |||
serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1); | |||
pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); | |||
/* Remaining pixels of a row */ | |||
for (x = 1; x < rectWidth; x++) { | |||
@@ -349,23 +123,60 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) | |||
} | |||
} | |||
serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1); | |||
pf.rgbFromBuffer(pix, &inbuf[y*rectWidth+x], 1); | |||
for (c = 0; c < 3; c++) | |||
pix[c] += est[c]; | |||
memcpy(&thisRow[x*3], pix, sizeof(pix)); | |||
serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1); | |||
pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); | |||
} | |||
memcpy(prevRow, thisRow, sizeof(prevRow)); | |||
} | |||
} | |||
#undef TIGHT_MIN_TO_COMPRESS | |||
#undef FILTER_GRADIENT | |||
#undef DECOMPRESS_JPEG_RECT | |||
#undef TIGHT_DECODE | |||
#undef READ_PIXEL | |||
#endif | |||
void TightDecoder::FilterPalette(const PIXEL_T* palette, int palSize, | |||
const rdr::U8* inbuf, PIXEL_T* outbuf, | |||
int stride, const Rect& r) | |||
{ | |||
// Indexed color | |||
int x, h = r.height(), w = r.width(), b, pad = stride - w; | |||
PIXEL_T* ptr = outbuf; | |||
rdr::U8 bits; | |||
const rdr::U8* srcPtr = inbuf; | |||
if (palSize <= 2) { | |||
// 2-color palette | |||
while (h > 0) { | |||
for (x = 0; x < w / 8; x++) { | |||
bits = *srcPtr++; | |||
for (b = 7; b >= 0; b--) { | |||
*ptr++ = palette[bits >> b & 1]; | |||
} | |||
} | |||
if (w % 8 != 0) { | |||
bits = *srcPtr++; | |||
for (b = 7; b >= 8 - w % 8; b--) { | |||
*ptr++ = palette[bits >> b & 1]; | |||
} | |||
} | |||
ptr += pad; | |||
h--; | |||
} | |||
} else { | |||
// 256-color palette | |||
while (h > 0) { | |||
PIXEL_T *endOfRow = ptr + w; | |||
while (ptr < endOfRow) { | |||
*ptr++ = palette[*srcPtr++]; | |||
} | |||
ptr += pad; | |||
h--; | |||
} | |||
} | |||
} | |||
#undef PIXEL_T | |||
} |