#include <rfb/Rect.h>
#include <rfb/encodings.h>
+#include <rfb/TransImageGetter.h>
namespace rfb {
class SMsgWriter;
// writeRect() tries to write the given rectangle. If it is unable to
// write the whole rectangle it returns false and sets actual to the actual
// rectangle which was updated.
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual)=0;
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig,
+ Rect* actual)=0;
static bool supported(int encoding);
static Encoder* createEncoder(int encoding, SMsgWriter* writer);
{
}
-bool HextileEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig,
+ Rect* actual)
{
writer->startRect(r, encodingHextile);
rdr::OutStream* os = writer->getOutStream();
class HextileEncoder : public Encoder {
public:
static Encoder* create(SMsgWriter* writer);
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual ~HextileEncoder();
private:
HextileEncoder(SMsgWriter* writer);
jpeg_destroy_compress(&cinfo);
}
-void JpegCompressor::compress(rdr::U8 *buf, const Rect& r,
+void JpegCompressor::compress(rdr::U8 *buf, int pitch, const Rect& r,
const PixelFormat& pf, int quality, JPEG_SUBSAMP subsamp)
{
int w = r.width();
}
#endif
+ if (pitch == 0) pitch = w * pixelsize;
+
if (cinfo.in_color_space == JCS_RGB) {
srcBuf = new rdr::U8[w * h * pixelsize];
srcBufIsTemp = true;
- pf.rgbFromBuffer(srcBuf, (const rdr::U8 *)buf, w * h);
+ pf.rgbFromBuffer(srcBuf, (const rdr::U8 *)buf, w, pitch, h);
+ pitch = w * pixelsize;
}
cinfo.input_components = pixelsize;
rowPointer = new JSAMPROW[h];
for (int dy = 0; dy < h; dy++)
- rowPointer[dy] = (JSAMPROW)(&srcBuf[dy * w * pixelsize]);
+ rowPointer[dy] = (JSAMPROW)(&srcBuf[dy * pitch]);
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height)
JpegCompressor(int bufferLen = 128*1024);
virtual ~JpegCompressor();
- void compress(rdr::U8 *, const Rect&, const PixelFormat&, int,
+ void compress(rdr::U8 *, int, const Rect&, const PixelFormat&, int,
JPEG_SUBSAMP);
void writeBytes(const void*, int);
// The pointer is to the top-left pixel of the specified Rect.
// The buffer stride (in pixels) is returned.
virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) = 0;
+ virtual rdr::U8* getPixelsRW(const Rect& r, int* stride) = 0;
// Get pixel data for a given part of the buffer
// Data is copied into the supplied buffer, with the specified
virtual int getStride() const;
// Get a pointer to specified pixel data
- virtual rdr::U8* getPixelsRW(const Rect& r, int* stride);
+ rdr::U8* getPixelsRW(const Rect& r, int* stride);
virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) {
return getPixelsRW(r, stride);
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009 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
* it under the terms of the GNU General Public License as published by
}
+void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src,
+ int w, int pitch, int h, ColourMap* cm) const
+{
+ rdr::U8 *rowptr, *colptr;
+
+ if (is888()) {
+ // Optimised common case
+ int rindex, gindex, bindex;
+
+ if (bigEndian) {
+ rindex = (24 - redShift)/8;
+ gindex = (24 - greenShift)/8;
+ bindex = (24 - blueShift)/8;
+ } else {
+ rindex = redShift/8;
+ gindex = greenShift/8;
+ bindex = blueShift/8;
+ }
+
+ for(rowptr = (rdr::U8 *)src; rowptr < &src[pitch * h]; rowptr += pitch) {
+ for(colptr = rowptr; colptr < &rowptr[w * 4]; colptr += 4) {
+ *(dst++) = colptr[rindex];
+ *(dst++) = colptr[gindex];
+ *(dst++) = colptr[bindex];
+ }
+ }
+ } else {
+ // Generic code
+ Pixel p;
+ rdr::U8 r, g, b;
+
+ for(rowptr = (rdr::U8 *)src; rowptr < &src[pitch * h]; rowptr += pitch) {
+ for(colptr = rowptr; colptr < &rowptr[w * bpp/8]; colptr += bpp/8) {
+ p = pixelFromBuffer(colptr);
+
+ rgbFromPixel(p, cm, &r, &g, &b);
+ *(dst++) = r;
+ *(dst++) = g;
+ *(dst++) = b;
+ }
+ }
+ }
+}
+
+
void PixelFormat::print(char* str, int len) const
{
// Unfortunately snprintf is not widely available so we build the string up
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
void rgbFromBuffer(rdr::U16* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const;
void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const;
+ void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int w, int pitch,
+ int h, ColourMap* cm=0) const;
void print(char* str, int len) const;
bool parse(const char* str);
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
outPF, out, outStride,
inRect.width(), inRect.height());
}
+
+bool PixelTransformer::willTransform(void)
+{
+ return transFn != NULL && transFn != noTransFn;
+}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#ifndef __RFB_PIXELTRANSFORMER_H__
#define __RFB_PIXELTRANSFORMER_H__
+#include <stdlib.h>
#include <rfb/Rect.h>
#include <rfb/PixelFormat.h>
void translateRect(void* inPtr, int inStride, Rect inRect,
void* outPtr, int outStride, Point outCoord) const;
+ bool willTransform(void);
+
private:
bool economic;
{
}
-bool RREEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool RREEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
{
int w = r.width();
int h = r.height();
class RREEncoder : public Encoder {
public:
static Encoder* create(SMsgWriter* writer);
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual ~RREEncoder();
private:
RREEncoder(SMsgWriter* writer);
{
}
-bool RawEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool RawEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
{
int x = r.tl.x;
int y = r.tl.y;
class RawEncoder : public Encoder {
public:
static Encoder* create(SMsgWriter* writer);
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual ~RawEncoder();
private:
RawEncoder(SMsgWriter* writer);
vlog.error("writeNoDataUpdate() called");
}
-void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
+void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig,
Region* updatedRegion)
{
std::vector<Rect> rects;
}
}
-bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
{
return writeRect(r, cp->currentEncoding(), ig, actual);
}
bool SMsgWriter::writeRect(const Rect& r, int encoding,
- ImageGetter* ig, Rect* actual)
+ TransImageGetter* ig, Rect* actual)
{
if (!encoders[encoding]) {
encoders[encoding] = Encoder::createEncoder(encoding, this);
// before the first writeRects() call and writeFrameBufferUpdateEnd() after
// the last one. It returns the actual region sent to the client, which
// may be smaller than the update passed in.
- virtual void writeRects(const UpdateInfo& update, ImageGetter* ig,
+ virtual void writeRects(const UpdateInfo& update, TransImageGetter* ig,
Region* updatedRegion);
// To construct a framebuffer update you can call
// writeRect() tries to write the given rectangle. If it is unable to
// write the whole rectangle it returns false and sets actual to the actual
// rectangle which was updated.
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual bool writeRect(const Rect& r, int encoding,
- ImageGetter* ig, Rect* actual);
+ TransImageGetter* ig, Rect* actual);
virtual void writeCopyRect(const Rect& r, int srcX, int srcY);
* USA.
*/
#include <rdr/OutStream.h>
-#include <rfb/ImageGetter.h>
#include <rfb/encodings.h>
#include <rfb/ConnParams.h>
#include <rfb/SMsgWriter.h>
};
const int TightEncoder::defaultCompressLevel = 1;
-// FIXME: Not good to mirror TightEncoder's members here.
-static const TIGHT_CONF* s_pconf;
-static const TIGHT_CONF* s_pjconf;
-
//
// Including BPP-dependent implementation of the encoder.
//
-#define EXTRA_ARGS ImageGetter* ig
-#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
#define BPP 8
#include <rfb/tightEncode.h>
#undef BPP
}
}
-bool TightEncoder::checkSolidTile(Rect& r, ImageGetter *ig, rdr::U32* colorPtr,
+bool TightEncoder::checkSolidTile(Rect& r, rdr::U32* colorPtr,
bool needSameColor)
{
- switch (writer->bpp()) {
+ switch (serverpf.bpp) {
case 32:
- return checkSolidTile32(r, ig, writer, colorPtr, needSameColor);
+ return checkSolidTile32(r, colorPtr, needSameColor);
case 16:
- return checkSolidTile16(r, ig, writer, colorPtr, needSameColor);
+ return checkSolidTile16(r, colorPtr, needSameColor);
default:
- return checkSolidTile8(r, ig, writer, colorPtr, needSameColor);
+ return checkSolidTile8(r, colorPtr, needSameColor);
}
}
-void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig,
- rdr::U32 colorValue, Rect& bestr)
+void TightEncoder::findBestSolidArea(Rect& r, rdr::U32 colorValue, Rect& bestr)
{
int dx, dy, dw, dh;
int w_prev;
TIGHT_MAX_SPLIT_TILE_SIZE : w_prev;
sr.setXYWH(r.tl.x, dy, dw, dh);
- if (!checkSolidTile(sr, ig, &colorValue, true))
+ if (!checkSolidTile(sr, &colorValue, true))
break;
for (dx = r.tl.x + dw; dx < r.tl.x + w_prev;) {
dw = (dx + TIGHT_MAX_SPLIT_TILE_SIZE <= r.tl.x + w_prev) ?
TIGHT_MAX_SPLIT_TILE_SIZE : (r.tl.x + w_prev - dx);
sr.setXYWH(dx, dy, dw, dh);
- if (!checkSolidTile(sr, ig, &colorValue, true))
+ if (!checkSolidTile(sr, &colorValue, true))
break;
- dx += dw;
+ dx += dw;
}
w_prev = dx - r.tl.x;
bestr.br.y = bestr.tl.y + h_best;
}
-void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig,
- rdr::U32 colorValue, Rect& er)
+void TightEncoder::extendSolidArea(const Rect& r, rdr::U32 colorValue,
+ Rect& er)
{
int cx, cy;
Rect sr;
// Try to extend the area upwards.
for (cy = er.tl.y - 1; ; cy--) {
sr.setXYWH(er.tl.x, cy, er.width(), 1);
- if (cy < r.tl.y || !checkSolidTile(sr, ig, &colorValue, true))
+ if (cy < r.tl.y || !checkSolidTile(sr, &colorValue, true))
break;
}
er.tl.y = cy + 1;
// ... downwards.
for (cy = er.br.y; ; cy++) {
sr.setXYWH(er.tl.x, cy, er.width(), 1);
- if (cy >= r.br.y || !checkSolidTile(sr, ig, &colorValue, true))
+ if (cy >= r.br.y || !checkSolidTile(sr, &colorValue, true))
break;
}
er.br.y = cy;
// ... to the left.
for (cx = er.tl.x - 1; ; cx--) {
sr.setXYWH(cx, er.tl.y, 1, er.height());
- if (cx < r.tl.x || !checkSolidTile(sr, ig, &colorValue, true))
+ if (cx < r.tl.x || !checkSolidTile(sr, &colorValue, true))
break;
}
er.tl.x = cx + 1;
// ... to the right.
for (cx = er.br.x; ; cx++) {
sr.setXYWH(cx, er.tl.y, 1, er.height());
- if (cx >= r.br.x || !checkSolidTile(sr, ig, &colorValue, true))
+ if (cx >= r.br.x || !checkSolidTile(sr, &colorValue, true))
break;
}
er.br.x = cx;
((h - 1) / subrectMaxHeight + 1));
}
-void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig)
+void TightEncoder::sendRectSimple(const Rect& r)
{
// Shortcuts to rectangle coordinates and dimensions.
const int x = r.tl.x;
// Encode small rects as is.
bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize;
if (!rectTooBig) {
- writeSubrect(r, ig);
+ writeSubrect(r);
return;
}
sw = (dx + pconf->maxRectWidth < w) ? pconf->maxRectWidth : w - dx;
sh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
sr.setXYWH(x + dx, y + dy, sw, sh);
- writeSubrect(sr, ig);
+ writeSubrect(sr);
}
}
}
-bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
+bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig,
+ Rect* actual)
{
+ ig = _ig;
+ serverpf = ig->getPixelBuffer()->getPF();
ConnParams* cp = writer->getConnParams();
+ clientpf = cp->pf();
// Shortcuts to rectangle coordinates and dimensions.
Rect r = _r;
unsigned int w = r.width();
unsigned int h = r.height();
- // Copy members of current TightEncoder instance to static variables.
- s_pconf = pconf;
- s_pjconf = pjconf;
-
// Encode small rects as is.
if (!cp->supportsLastRect || w * h < TIGHT_MIN_SPLIT_RECT_SIZE) {
- sendRectSimple(r, ig);
+ sendRectSimple(r);
return true;
}
Rect sr, bestr;
unsigned int dx, dy, dw, dh;
rdr::U32 colorValue;
- int maxRectSize = s_pconf->maxRectSize;
- int maxRectWidth = s_pconf->maxRectWidth;
+ int maxRectSize = pconf->maxRectSize;
+ int maxRectWidth = pconf->maxRectWidth;
int nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
- int nMaxRows = s_pconf->maxRectSize / nMaxWidth;
+ int nMaxRows = pconf->maxRectSize / nMaxWidth;
// Try to find large solid-color areas and send them separately.
for (dy = y; dy < y + h; dy += TIGHT_MAX_SPLIT_TILE_SIZE) {
// If a rectangle becomes too large, send its upper part now.
if (dy - y >= nMaxRows) {
sr.setXYWH(x, y, w, nMaxRows);
- sendRectSimple(sr, ig);
+ sendRectSimple(sr);
r.tl.y += nMaxRows;
y = r.tl.y;
h = r.height();
TIGHT_MAX_SPLIT_TILE_SIZE : (x + w - dx);
sr.setXYWH(dx, dy, dw, dh);
- if (checkSolidTile(sr, ig, &colorValue, false)) {
+ if (checkSolidTile(sr, &colorValue, false)) {
// Get dimensions of solid-color area.
sr.setXYWH(dx, dy, r.br.x - dx, r.br.y - dy);
- findBestSolidArea(sr, ig, colorValue, bestr);
+ findBestSolidArea(sr, colorValue, bestr);
// Make sure a solid rectangle is large enough
// (or the whole rectangle is of the same color).
continue;
// Try to extend solid rectangle to maximum size.
- extendSolidArea(r, ig, colorValue, bestr);
+ extendSolidArea(r, colorValue, bestr);
// Send rectangles at top and left to solid-color area.
if (bestr.tl.y != y) {
sr.setXYWH(x, y, w, bestr.tl.y - y);
- sendRectSimple(sr, ig);
+ sendRectSimple(sr);
}
if (bestr.tl.x != x) {
sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height());
- writeRect(sr, ig, NULL);
+ writeRect(sr, _ig, NULL);
}
// Send solid-color rectangle.
- writeSubrect(bestr, ig, true);
+ writeSubrect(bestr, true);
// Send remaining rectangles (at right and bottom).
if (bestr.br.x != r.br.x) {
sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x,
bestr.height());
- writeRect(sr, ig, NULL);
+ writeRect(sr, _ig, NULL);
}
if (bestr.br.y != r.br.y) {
sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y);
- writeRect(sr, ig, NULL);
+ writeRect(sr, _ig, NULL);
}
return true;
}
// No suitable solid-color rectangles found.
- sendRectSimple(r, ig);
+ sendRectSimple(r);
return true;
}
-void TightEncoder::writeSubrect(const Rect& r, ImageGetter* ig,
- bool forceSolid)
+void TightEncoder::writeSubrect(const Rect& r, bool forceSolid)
{
- rdr::U8* imageBuf = writer->getImageBuf(r.area());
- ConnParams* cp = writer->getConnParams();
mos.clear();
- switch (writer->bpp()) {
+ switch (clientpf.bpp) {
case 8:
- tightEncode8(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break;
+ tightEncode8(r, &mos, forceSolid); break;
case 16:
- tightEncode16(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break;
+ tightEncode16(r, &mos, forceSolid); break;
case 32:
- tightEncode32(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break;
+ tightEncode32(r, &mos, forceSolid); break;
}
writer->startRect(r, encodingTight);
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>
#include <rfb/JpegCompressor.h>
+#include <rfb/TransImageGetter.h>
#include <rfb/Encoder.h>
// FIXME: Check if specifying extern "C" is really necessary.
JPEG_SUBSAMP jpegSubSample;
};
+ //
+ // C-style structures to store palette entries and compression paramentes.
+ // Such code probably should be converted into C++ classes.
+ //
+
+ struct TIGHT_COLOR_LIST {
+ TIGHT_COLOR_LIST *next;
+ int idx;
+ rdr::U32 rgb;
+ };
+
+ struct TIGHT_PALETTE_ENTRY {
+ TIGHT_COLOR_LIST *listNode;
+ int numPixels;
+ };
+
+ struct TIGHT_PALETTE {
+ TIGHT_PALETTE_ENTRY entry[256];
+ TIGHT_COLOR_LIST *hash[256];
+ TIGHT_COLOR_LIST list[256];
+ };
+
//
// Compression level stuff. The following array contains various
// encoder parameters for each of 10 compression levels (0..9).
virtual void setCompressLevel(int level);
virtual void setQualityLevel(int level);
virtual int getNumRects(const Rect &r);
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual ~TightEncoder();
private:
TightEncoder(SMsgWriter* writer);
- bool checkSolidTile(Rect& r, ImageGetter *ig, rdr::U32* colorPtr,
- bool needSameColor);
- void extendSolidArea(const Rect& r, ImageGetter *ig,
- rdr::U32 colorValue, Rect& er);
- void findBestSolidArea(Rect& r, ImageGetter* ig, rdr::U32 colorValue,
- Rect& bestr);
- void sendRectSimple(const Rect& r, ImageGetter* ig);
- void writeSubrect(const Rect& r, ImageGetter* ig, bool forceSolid = false);
+ bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor);
+ void extendSolidArea(const Rect& r, rdr::U32 colorValue, Rect& er);
+ void findBestSolidArea(Rect& r, rdr::U32 colorValue, Rect& bestr);
+ void sendRectSimple(const Rect& r);
+ void writeSubrect(const Rect& r, bool forceSolid = false);
+
+ void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
+ const void *buf, unsigned int length, int zlibLevel);
+
+ int paletteInsert(rdr::U32 rgb, int numPixels, int bpp);
+ void paletteReset(void);
+
+ void fastFillPalette8(const Rect &r, rdr::U8 *data, int stride);
+ void fastFillPalette16(const Rect &r, rdr::U16 *data, int stride);
+ void fastFillPalette32(const Rect &r, rdr::U32 *data, int stride);
+
+ void fillPalette8(rdr::U8 *data, int count);
+ void fillPalette16(rdr::U16 *data, int count);
+ void fillPalette32(rdr::U32 *data, int count);
+
+ unsigned int packPixels8(rdr::U8 *buf, unsigned int count);
+ unsigned int packPixels16(rdr::U16 *buf, unsigned int count);
+ unsigned int packPixels32(rdr::U32 *buf, unsigned int count);
+
+ void tightEncode8(const Rect& r, rdr::OutStream *os, bool forceSolid);
+ void tightEncode16(const Rect& r, rdr::OutStream *os, bool forceSolid);
+ void tightEncode32(const Rect& r, rdr::OutStream *os, bool forceSolid);
+
+ bool checkSolidTile8(Rect& r, rdr::U32 *colorPtr, bool needSameColor);
+ bool checkSolidTile16(Rect& r, rdr::U32 *colorPtr, bool needSameColor);
+ bool checkSolidTile32(Rect& r, rdr::U32 *colorPtr, bool needSameColor);
+
+ void encodeSolidRect8(rdr::OutStream *os, rdr::U8 *buf);
+ void encodeSolidRect16(rdr::OutStream *os, rdr::U16 *buf);
+ void encodeSolidRect32(rdr::OutStream *os, rdr::U32 *buf);
+
+ void encodeFullColorRect8(rdr::OutStream *os, rdr::U8 *buf, const Rect& r);
+ void encodeFullColorRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r);
+ void encodeFullColorRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r);
+
+ void encodeMonoRect8(rdr::OutStream *os, rdr::U8 *buf, const Rect& r);
+ void encodeMonoRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r);
+ void encodeMonoRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r);
+
+ void encodeIndexedRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r);
+ void encodeIndexedRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r);
+
+ void encodeJpegRect16(rdr::OutStream *os, rdr::U16 *buf, int, const Rect& r);
+ void encodeJpegRect32(rdr::OutStream *os, rdr::U32 *buf, int, const Rect& r);
SMsgWriter* writer;
rdr::MemOutStream mos;
rdr::ZlibOutStream zos[4];
JpegCompressor jc;
+ TransImageGetter *ig;
+ PixelFormat serverpf, clientpf;
+
+ bool pack24;
+ int palMaxColors, palNumColors;
+ rdr::U32 monoBackground, monoForeground;
+ TIGHT_PALETTE palette;
static const int defaultCompressLevel;
static const TIGHT_CONF conf[];
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
PixelTransformer::setColourMapEntries(firstCol, nCols);
}
+rdr::U8 *TransImageGetter::getPixelsRW(const Rect &r, int *stride)
+{
+ if (!offset.equals(Point(0, 0)))
+ return pb->getPixelsRW(r.translate(offset.negate()), stride);
+ else
+ return pb->getPixelsRW(r, stride);
+}
+
void TransImageGetter::getImage(void* outPtr, const Rect& r, int outStride)
{
int inStride;
if (self->writer)
self->writer->writeSetColourMapEntries(firstColour, nColours, cm);
}
-
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
// padding will be outStride-r.width() pixels).
void getImage(void* outPtr, const Rect& r, int outStride=0);
+ rdr::U8 *getPixelsRW(const Rect &r, int *stride);
+
// setPixelBuffer() changes the pixel buffer to be used. The new pixel
// buffer MUST have the same pixel format as the old one - if not you
// should call init() instead.
void setPixelBuffer(PixelBuffer* pb_) { pb = pb_; }
+ PixelBuffer *getPixelBuffer(void) { return pb; }
+
// setOffset() sets an offset which is subtracted from the coordinates of
// the rectangle given to getImage().
void setOffset(const Point& offset_) { offset = offset_; }
delete mos;
}
-bool ZRLEEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
{
rdr::U8* imageBuf = writer->getImageBuf(64 * 64 * 4 + 4);
mos->clear();
class ZRLEEncoder : public Encoder {
public:
static Encoder* create(SMsgWriter* writer);
- virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual ~ZRLEEncoder();
// setMaxLen() sets the maximum size in bytes of any ZRLE rectangle. This
// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
//
-#include <rdr/OutStream.h>
-#include <rdr/ZlibOutStream.h>
#include <assert.h>
namespace rfb {
#endif
#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
-#define TIGHT_ENCODE CONCAT2E(tightEncode,BPP)
-#define SWAP_PIXEL CONCAT2E(SWAP,BPP)
+#define TIGHT_ENCODE TightEncoder::CONCAT2E(tightEncode,BPP)
#define HASH_FUNCTION CONCAT2E(HASH_FUNC,BPP)
-#define PACK_PIXELS CONCAT2E(packPixels,BPP)
-#define ENCODE_SOLID_RECT CONCAT2E(encodeSolidRect,BPP)
-#define ENCODE_FULLCOLOR_RECT CONCAT2E(encodeFullColorRect,BPP)
-#define ENCODE_MONO_RECT CONCAT2E(encodeMonoRect,BPP)
-#define ENCODE_INDEXED_RECT CONCAT2E(encodeIndexedRect,BPP)
-#define ENCODE_JPEG_RECT CONCAT2E(encodeJpegRect,BPP)
-#define FILL_PALETTE CONCAT2E(fillPalette,BPP)
-#define CHECK_SOLID_TILE CONCAT2E(checkSolidTile,BPP)
+#define PACK_PIXELS TightEncoder::CONCAT2E(packPixels,BPP)
+#define ENCODE_SOLID_RECT TightEncoder::CONCAT2E(encodeSolidRect,BPP)
+#define ENCODE_FULLCOLOR_RECT TightEncoder::CONCAT2E(encodeFullColorRect,BPP)
+#define ENCODE_MONO_RECT TightEncoder::CONCAT2E(encodeMonoRect,BPP)
+#define ENCODE_INDEXED_RECT TightEncoder::CONCAT2E(encodeIndexedRect,BPP)
+#define ENCODE_JPEG_RECT TightEncoder::CONCAT2E(encodeJpegRect,BPP)
+#define FAST_FILL_PALETTE TightEncoder::CONCAT2E(fastFillPalette,BPP)
+#define FILL_PALETTE TightEncoder::CONCAT2E(fillPalette,BPP)
+#define CHECK_SOLID_TILE TightEncoder::CONCAT2E(checkSolidTile,BPP)
#ifndef TIGHT_ONCE
#define TIGHT_ONCE
-//
-// C-style structures to store palette entries and compression paramentes.
-// Such code probably should be converted into C++ classes.
-//
-
-struct TIGHT_COLOR_LIST {
- TIGHT_COLOR_LIST *next;
- int idx;
- rdr::U32 rgb;
-};
-
-struct TIGHT_PALETTE_ENTRY {
- TIGHT_COLOR_LIST *listNode;
- int numPixels;
-};
-
-struct TIGHT_PALETTE {
- TIGHT_PALETTE_ENTRY entry[256];
- TIGHT_COLOR_LIST *hash[256];
- TIGHT_COLOR_LIST list[256];
-};
-
-// FIXME: Is it really a good idea to use static variables for this?
-static bool s_pack24; // use 24-bit packing for 32-bit pixels
-
-// FIXME: Make a separate class for palette operations.
-static int s_palMaxColors, s_palNumColors;
-static rdr::U32 s_monoBackground, s_monoForeground;
-static TIGHT_PALETTE s_palette;
-
-//
-// Swapping bytes in pixels.
-// FIXME: Use a sort of ImageGetter that does not convert pixel format?
-//
-
-#ifndef SWAP16
-#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
-#endif
-#ifndef SWAP32
-#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
- (((n) & 0x0000ff00) << 8) | ((n) << 24))
-#endif
-
//
// Functions to operate on palette structures.
//
#define HASH_FUNC16(rgb) ((int)(((rgb >> 8) + rgb) & 0xFF))
#define HASH_FUNC32(rgb) ((int)(((rgb >> 16) + (rgb >> 8)) & 0xFF))
-static void paletteReset(void)
+void TightEncoder::paletteReset(void)
{
- s_palNumColors = 0;
- memset(s_palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *));
+ palNumColors = 0;
+ memset(palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *));
}
-static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
+int TightEncoder::paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
{
TIGHT_COLOR_LIST *pnode;
TIGHT_COLOR_LIST *prev_pnode = NULL;
hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
- pnode = s_palette.hash[hash_key];
+ pnode = palette.hash[hash_key];
while (pnode != NULL) {
if (pnode->rgb == rgb) {
// Such palette entry already exists.
new_idx = idx = pnode->idx;
- count = s_palette.entry[idx].numPixels + numPixels;
- if (new_idx && s_palette.entry[new_idx-1].numPixels < count) {
+ count = palette.entry[idx].numPixels + numPixels;
+ if (new_idx && palette.entry[new_idx-1].numPixels < count) {
do {
- s_palette.entry[new_idx] = s_palette.entry[new_idx-1];
- s_palette.entry[new_idx].listNode->idx = new_idx;
+ palette.entry[new_idx] = palette.entry[new_idx-1];
+ palette.entry[new_idx].listNode->idx = new_idx;
new_idx--;
}
while (new_idx &&
- s_palette.entry[new_idx-1].numPixels < count);
- s_palette.entry[new_idx].listNode = pnode;
+ palette.entry[new_idx-1].numPixels < count);
+ palette.entry[new_idx].listNode = pnode;
pnode->idx = new_idx;
}
- s_palette.entry[new_idx].numPixels = count;
- return s_palNumColors;
+ palette.entry[new_idx].numPixels = count;
+ return palNumColors;
}
prev_pnode = pnode;
pnode = pnode->next;
}
// Check if palette is full.
- if ( s_palNumColors == 256 || s_palNumColors == s_palMaxColors ) {
- s_palNumColors = 0;
+ if ( palNumColors == 256 || palNumColors == palMaxColors ) {
+ palNumColors = 0;
return 0;
}
// Move palette entries with lesser pixel counts.
- for ( idx = s_palNumColors;
- idx > 0 && s_palette.entry[idx-1].numPixels < numPixels;
+ for ( idx = palNumColors;
+ idx > 0 && palette.entry[idx-1].numPixels < numPixels;
idx-- ) {
- s_palette.entry[idx] = s_palette.entry[idx-1];
- s_palette.entry[idx].listNode->idx = idx;
+ palette.entry[idx] = palette.entry[idx-1];
+ palette.entry[idx].listNode->idx = idx;
}
// Add new palette entry into the freed slot.
- pnode = &s_palette.list[s_palNumColors];
+ pnode = &palette.list[palNumColors];
if (prev_pnode != NULL) {
prev_pnode->next = pnode;
} else {
- s_palette.hash[hash_key] = pnode;
+ palette.hash[hash_key] = pnode;
}
pnode->next = NULL;
pnode->idx = idx;
pnode->rgb = rgb;
- s_palette.entry[idx].listNode = pnode;
- s_palette.entry[idx].numPixels = numPixels;
+ palette.entry[idx].listNode = pnode;
+ palette.entry[idx].numPixels = numPixels;
- return (++s_palNumColors);
+ return (++palNumColors);
}
//
// size is less than TIGHT_MIN_TO_COMPRESS bytes.
//
-static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
- const void *buf, const PixelFormat& pf,
- unsigned int length, int zlibLevel)
+void TightEncoder::compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
+ const void *buf, unsigned int length,
+ int zlibLevel)
{
if (length < TIGHT_MIN_TO_COMPRESS) {
os->writeBytes(buf, length);
} else {
// FIXME: Using a temporary MemOutStream may be not efficient.
// Maybe use the same static object used in the JPEG coder?
- int maxBeforeSize = s_pconf->maxRectSize * (pf.bpp / 8);
+ int maxBeforeSize = pconf->maxRectSize * (clientpf.bpp / 8);
int maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
rdr::MemOutStream mem_os(maxAfterSize);
zos->setUnderlying(&mem_os);
#endif // #ifndef TIGHT_ONCE
-static void ENCODE_SOLID_RECT (rdr::OutStream *os,
- PIXEL_T *buf, const PixelFormat& pf);
-static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-#if (BPP != 8)
-static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc,
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-#endif
-
-static void FILL_PALETTE (PIXEL_T *data, int count);
-
//
// Convert 32-bit color samples into 24-bit colors, in place.
// Performs packing only when redMax, greenMax and blueMax are all 255.
// Color components are assumed to be byte-aligned.
//
-static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count,
- const PixelFormat& pf)
+unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count)
{
#if (BPP != 32)
return count * sizeof(PIXEL_T);
#else
- if (!s_pack24)
+ if (!pack24)
return count * sizeof(PIXEL_T);
rdr::U32 pix;
rdr::U8 *dst = (rdr::U8 *)buf;
for (unsigned int i = 0; i < count; i++) {
pix = *buf++;
- pf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL);
+ clientpf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL);
dst += 3;
}
return count * 3;
// Main function of the Tight encoder
//
-void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os,
- rdr::ZlibOutStream zos[4], JpegCompressor &jc, void* buf,
- ConnParams* cp
-#ifdef EXTRA_ARGS
- , EXTRA_ARGS,
-#endif
- bool forceSolid)
+void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, bool forceSolid)
{
- const PixelFormat& pf = cp->pf();
- if(forceSolid) {
- GET_IMAGE_INTO_BUF(Rect(r.tl.x, r.tl.y, r.tl.x + 1, r.tl.y + 1), buf);
- }
- else {
- GET_IMAGE_INTO_BUF(r, buf);
- }
- PIXEL_T* pixels = (PIXEL_T*)buf;
+ int stride = r.width();
+ PIXEL_T *pixels = (PIXEL_T *)ig->getPixelsRW(r, &stride);
#if (BPP == 32)
// Check if it's necessary to pack 24-bit pixels, and
// compute appropriate shift values if necessary.
- s_pack24 = pf.is888();
+ pack24 = clientpf.is888();
#endif
if (forceSolid)
- s_palNumColors = 1;
+ palNumColors = 1;
else {
- s_palMaxColors = r.area() / s_pconf->idxMaxColorsDivisor;
- if (s_pjconf != NULL) s_palMaxColors = s_pconf->palMaxColorsWithJPEG;
- if (s_palMaxColors < 2 && r.area() >= s_pconf->monoMinRectSize) {
- s_palMaxColors = 2;
+ palMaxColors = r.area() / pconf->idxMaxColorsDivisor;
+ if (pjconf != NULL) palMaxColors = pconf->palMaxColorsWithJPEG;
+ if (palMaxColors < 2 && r.area() >= pconf->monoMinRectSize) {
+ palMaxColors = 2;
}
- FILL_PALETTE(pixels, r.area());
+ if (clientpf.equal(serverpf) && clientpf.bpp >= 16) {
+ // This is so we can avoid translating the pixels when compressing
+ // with JPEG, since it is unnecessary
+ FAST_FILL_PALETTE(r, pixels, stride);
+ if(palNumColors != 0 || pjconf == NULL) {
+ pixels = (PIXEL_T *)writer->getImageBuf(r.area());
+ stride = r.width();
+ ig->getImage(pixels, r);
+ }
+ }
+ else {
+ pixels = (PIXEL_T *)writer->getImageBuf(r.area());
+ stride = r.width();
+ ig->getImage(pixels, r);
+ FILL_PALETTE(pixels, r.area());
+ }
}
- switch (s_palNumColors) {
+ switch (palNumColors) {
case 0:
// Truecolor image
#if (BPP != 8)
- if (s_pjconf != NULL) {
- ENCODE_JPEG_RECT(os, jc, pixels, pf, r);
+ if (pjconf != NULL) {
+ ENCODE_JPEG_RECT(os, pixels, stride, r);
break;
}
#endif
- ENCODE_FULLCOLOR_RECT(os, zos, pixels, pf, r);
+ ENCODE_FULLCOLOR_RECT(os, pixels, r);
break;
case 1:
// Solid rectangle
- ENCODE_SOLID_RECT(os, pixels, pf);
+ ENCODE_SOLID_RECT(os, pixels);
break;
case 2:
// Two-color rectangle
- ENCODE_MONO_RECT(os, zos, pixels, pf, r);
+ ENCODE_MONO_RECT(os, pixels, r);
break;
#if (BPP != 8)
default:
// Up to 256 different colors
- ENCODE_INDEXED_RECT(os, zos, pixels, pf, r);
+ ENCODE_INDEXED_RECT(os, pixels, r);
#endif
}
}
// Subencoding implementations.
//
-static void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf, const PixelFormat& pf)
+void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf)
{
os->writeU8(0x08 << 4);
- int length = PACK_PIXELS(buf, 1, pf);
+ int length = PACK_PIXELS(buf, 1);
os->writeBytes(buf, length);
}
-static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r)
+void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r)
{
const int streamId = 0;
os->writeU8(streamId << 4);
- int length = PACK_PIXELS(buf, r.area(), pf);
- compressData(os, &zos[streamId], buf, pf, length, s_pconf->rawZlibLevel);
+ int length = PACK_PIXELS(buf, r.area());
+ compressData(os, &zos[streamId], buf, length, pconf->rawZlibLevel);
}
-static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r)
+void ENCODE_MONO_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r)
{
const int streamId = 1;
os->writeU8((streamId | 0x04) << 4);
os->writeU8(0x01);
// Write the palette
- PIXEL_T pal[2] = { (PIXEL_T)s_monoBackground, (PIXEL_T)s_monoForeground };
+ PIXEL_T pal[2] = { (PIXEL_T)monoBackground, (PIXEL_T)monoForeground };
os->writeU8(1);
- os->writeBytes(pal, PACK_PIXELS(pal, 2, pf));
+ os->writeBytes(pal, PACK_PIXELS(pal, 2));
// Encode the data in-place
PIXEL_T *src = buf;
int aligned_width;
int x, y, bg_bits;
- bg = (PIXEL_T) s_monoBackground;
+ bg = (PIXEL_T) monoBackground;
aligned_width = w - w % 8;
for (y = 0; y < h; y++) {
// Write the data
int length = (w + 7) / 8;
length *= h;
- compressData(os, &zos[streamId], buf, pf, length, s_pconf->monoZlibLevel);
+ compressData(os, &zos[streamId], buf, length, pconf->monoZlibLevel);
}
#if (BPP != 8)
-static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
- PIXEL_T *buf, const PixelFormat& pf, const Rect& r)
+void ENCODE_INDEXED_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r)
{
const int streamId = 2;
os->writeU8((streamId | 0x04) << 4);
// Write the palette
{
PIXEL_T pal[256];
- for (int i = 0; i < s_palNumColors; i++)
- pal[i] = (PIXEL_T)s_palette.entry[i].listNode->rgb;
- os->writeU8((rdr::U8)(s_palNumColors - 1));
- os->writeBytes(pal, PACK_PIXELS(pal, s_palNumColors, pf));
+ for (int i = 0; i < palNumColors; i++)
+ pal[i] = (PIXEL_T)palette.entry[i].listNode->rgb;
+ os->writeU8((rdr::U8)(palNumColors - 1));
+ os->writeBytes(pal, PACK_PIXELS(pal, palNumColors));
}
// Encode data in-place
while (count && *src == rgb) {
rep++, src++, count--;
}
- pnode = s_palette.hash[HASH_FUNCTION(rgb)];
+ pnode = palette.hash[HASH_FUNCTION(rgb)];
while (pnode != NULL) {
if ((PIXEL_T)pnode->rgb == rgb) {
*dst++ = (rdr::U8)pnode->idx;
}
// Write the data
- compressData(os, &zos[streamId], buf, pf, r.area(), s_pconf->idxZlibLevel);
+ compressData(os, &zos[streamId], buf, r.area(), pconf->idxZlibLevel);
}
#endif // #if (BPP != 8)
//
#if (BPP != 8)
-static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc,
- PIXEL_T *buf, const PixelFormat& pf,
- const Rect& r)
+void ENCODE_JPEG_RECT (rdr::OutStream *os, PIXEL_T *buf, int stride,
+ const Rect& r)
{
jc.clear();
- jc.compress((rdr::U8 *)buf, r, pf, s_pjconf->jpegQuality,
- s_pjconf->jpegSubSample);
+ jc.compress((rdr::U8 *)buf, stride * serverpf.bpp / 8, r, serverpf,
+ pjconf->jpegQuality, pjconf->jpegSubSample);
os->writeU8(0x09 << 4);
os->writeCompactLength(jc.length());
os->writeBytes(jc.data(), jc.length());
//
#if (BPP == 8)
-static void FILL_PALETTE (PIXEL_T *data, int count)
+
+void FILL_PALETTE (PIXEL_T *data, int count)
{
PIXEL_T c0, c1;
int i, n0, n1;
- s_palNumColors = 0;
+ palNumColors = 0;
c0 = data[0];
for (i = 1; i < count && data[i] == c0; i++);
if (i == count) {
- s_palNumColors = 1;
+ palNumColors = 1;
return; // Solid rectangle
}
- if (s_palMaxColors < 2)
+ if (palMaxColors < 2)
return;
n0 = i;
}
if (i == count) {
if (n0 > n1) {
- s_monoBackground = (rdr::U32)c0;
- s_monoForeground = (rdr::U32)c1;
+ monoBackground = (rdr::U32)c0;
+ monoForeground = (rdr::U32)c1;
} else {
- s_monoBackground = (rdr::U32)c1;
- s_monoForeground = (rdr::U32)c0;
+ monoBackground = (rdr::U32)c1;
+ monoForeground = (rdr::U32)c0;
}
- s_palNumColors = 2; // Two colors
+ palNumColors = 2; // Two colors
}
}
+
+void FAST_FILL_PALETTE (const Rect& r, PIXEL_T *data, int stride)
+{
+}
+
#else // (BPP != 8)
-static void FILL_PALETTE (PIXEL_T *data, int count)
+
+void FILL_PALETTE (PIXEL_T *data, int count)
{
PIXEL_T c0, c1, ci = 0;
int i, n0, n1, ni;
c0 = data[0];
for (i = 1; i < count && data[i] == c0; i++);
if (i >= count) {
- s_palNumColors = 1; // Solid rectangle
+ palNumColors = 1; // Solid rectangle
return;
}
- if (s_palMaxColors < 2) {
- s_palNumColors = 0; // Full-color format preferred
+ if (palMaxColors < 2) {
+ palNumColors = 0; // Full-color format preferred
return;
}
}
if (i >= count) {
if (n0 > n1) {
- s_monoBackground = (rdr::U32)c0;
- s_monoForeground = (rdr::U32)c1;
+ monoBackground = (rdr::U32)c0;
+ monoForeground = (rdr::U32)c1;
} else {
- s_monoBackground = (rdr::U32)c1;
- s_monoForeground = (rdr::U32)c0;
+ monoBackground = (rdr::U32)c1;
+ monoForeground = (rdr::U32)c0;
}
- s_palNumColors = 2; // Two colors
+ palNumColors = 2; // Two colors
return;
}
}
paletteInsert (ci, (rdr::U32)ni, BPP);
}
+
+void FAST_FILL_PALETTE (const Rect& r, PIXEL_T *data, int stride)
+{
+ PIXEL_T c0, c1, ci = 0, mask, c0t, c1t, cit;
+ int n0, n1, ni;
+ int w = r.width(), h = r.height();
+ PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2, *dataend = &data[stride * h];
+ bool willTransform = ig->willTransform();
+
+ if (willTransform) {
+ mask = serverpf.redMax << serverpf.redShift;
+ mask |= serverpf.greenMax << serverpf.greenShift;
+ mask |= serverpf.blueMax << serverpf.blueShift;
+ }
+ else mask = ~0;
+
+ c0 = data[0] & mask;
+ n0 = 0;
+ for (rowptr = data; rowptr < dataend; rowptr += stride) {
+ for (colptr = rowptr; colptr < &rowptr[w]; colptr++) {
+ if (((*colptr) & mask) != c0)
+ goto soliddone;
+ n0++;
+ }
+ }
+
+ soliddone:
+ if (rowptr >= dataend) {
+ palNumColors = 1; // Solid rectangle
+ return;
+ }
+ if (palMaxColors < 2) {
+ palNumColors = 0; // Full-color format preferred
+ return;
+ }
+
+ c1 = *colptr & mask;
+ n1 = 0;
+ colptr++;
+ if (colptr >= &rowptr[w]) {
+ rowptr += stride; colptr = rowptr;
+ }
+ colptr2 = colptr;
+ for (rowptr2 = rowptr; rowptr2 < dataend;) {
+ for (; colptr2 < &rowptr2[w]; colptr2++) {
+ ci = (*colptr2) & mask;
+ if (ci == c0) {
+ n0++;
+ } else if (ci == c1) {
+ n1++;
+ } else
+ goto monodone;
+ }
+ rowptr2 += stride;
+ colptr2 = rowptr2;
+ }
+
+ monodone:
+ if (willTransform) {
+ ig->translateRect(&c0, 1, Rect(0, 0, 1, 1), &c0t, 1, Point(0, 0));
+ ig->translateRect(&c1, 1, Rect(0, 0, 1, 1), &c1t, 1, Point(0, 0));
+ }
+ else {
+ c0t = c0; c1t = c1;
+ }
+
+ if (colptr2 >= dataend) {
+ if (n0 > n1) {
+ monoBackground = (rdr::U32)c0t;
+ monoForeground = (rdr::U32)c1t;
+ } else {
+ monoBackground = (rdr::U32)c1t;
+ monoForeground = (rdr::U32)c0t;
+ }
+ palNumColors = 2; // Two colors
+ return;
+ }
+
+ paletteReset();
+ paletteInsert (c0t, (rdr::U32)n0, BPP);
+ paletteInsert (c1t, (rdr::U32)n1, BPP);
+
+ ni = 1;
+ colptr2++;
+ if (colptr2 >= &rowptr2[w]) {
+ rowptr2 += stride; colptr2 = rowptr2;
+ }
+ colptr = colptr2;
+ for (rowptr = rowptr2; rowptr < dataend;) {
+ for (; colptr < &rowptr[w]; colptr++) {
+ if (((*colptr) & mask) == ci) {
+ ni++;
+ } else {
+ if (willTransform)
+ ig->translateRect(&ci, 1, Rect(0, 0, 1, 1), &cit, 1, Point(0, 0));
+ else
+ cit = ci;
+ if (!paletteInsert (cit, (rdr::U32)ni, BPP))
+ return;
+ ci = (*colptr) & mask;
+ ni = 1;
+ }
+ }
+ rowptr += stride;
+ colptr = rowptr;
+ }
+ ig->translateRect(&ci, 1, Rect(0, 0, 1, 1), &cit, 1, Point(0, 0));
+ paletteInsert (cit, (rdr::U32)ni, BPP);
+}
+
#endif // #if (BPP == 8)
-bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer,
- rdr::U32 *colorPtr, bool needSameColor)
+bool CHECK_SOLID_TILE(Rect& r, rdr::U32 *colorPtr, bool needSameColor)
{
- PIXEL_T *buf;
- PIXEL_T colorValue;
+ PIXEL_T *buf, colorValue;
int dx, dy;
- Rect sr;
+ int w = r.width(), h = r.height();
- buf = (PIXEL_T *)writer->getImageBuf(r.area());
- sr.setXYWH(r.tl.x, r.tl.y, 1, 1);
- GET_IMAGE_INTO_BUF(sr, buf);
+ int stride = w;
+ buf = (PIXEL_T *)ig->getPixelsRW(r, &stride);
colorValue = *buf;
if (needSameColor && (rdr::U32)colorValue != *colorPtr)
return false;
- for (dy = 0; dy < r.height(); dy++) {
- Rect sr;
- sr.setXYWH(r.tl.x, r.tl.y + dy, r.width(), 1);
- GET_IMAGE_INTO_BUF(sr, buf);
- for (dx = 0; dx < r.width(); dx++) {
+ for (dy = 0; dy < h; dy++) {
+ for (dx = 0; dx < w; dx++) {
if (colorValue != buf[dx])
return false;
}
+ buf += stride;
}
*colorPtr = (rdr::U32)colorValue;
}
#undef PIXEL_T
-#undef WRITE_PIXEL
#undef TIGHT_ENCODE
-#undef SWAP_PIXEL
#undef HASH_FUNCTION
#undef PACK_PIXELS
#undef ENCODE_SOLID_RECT
#undef ENCODE_MONO_RECT
#undef ENCODE_INDEXED_RECT
#undef ENCODE_JPEG_RECT
+#undef FAST_FILL_PALETTE
#undef FILL_PALETTE
#undef CHECK_SOLID_TILE
}