/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2014-2018 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 Pierre Ossman for Cendio AB
* Copyright 2018 Peter Astrand for Cendio AB
*
* This is free software; you can redistribute it and/or modify
throw rfb::Exception("Invalid write attempt to OffsetPixelBuffer");
}
-// Preprocessor generated, optimised methods
-
-#define BPP 8
-#include "EncodeManagerBPP.cxx"
-#undef BPP
-#define BPP 16
-#include "EncodeManagerBPP.cxx"
-#undef BPP
-#define BPP 32
-#include "EncodeManagerBPP.cxx"
-#undef BPP
+template<class T>
+inline bool EncodeManager::checkSolidTile(const Rect& r,
+ const T colourValue,
+ const PixelBuffer *pb)
+{
+ int w, h;
+ const T* buffer;
+ int stride, pad;
+
+ w = r.width();
+ h = r.height();
+
+ buffer = (const T*)pb->getBuffer(r, &stride);
+ pad = stride - w;
+
+ while (h--) {
+ int w_ = w;
+ while (w_--) {
+ if (*buffer != colourValue)
+ return false;
+ buffer++;
+ }
+ buffer += pad;
+ }
+
+ return true;
+}
+
+template<class T>
+inline bool EncodeManager::analyseRect(int width, int height,
+ const T* buffer, int stride,
+ struct RectInfo *info, int maxColours)
+{
+ int pad;
+
+ T colour;
+ int count;
+
+ info->rleRuns = 0;
+ info->palette.clear();
+
+ pad = stride - width;
+
+ // For efficiency, we only update the palette on changes in colour
+ colour = buffer[0];
+ count = 0;
+ while (height--) {
+ int w_ = width;
+ while (w_--) {
+ if (*buffer != colour) {
+ if (!info->palette.insert(colour, count))
+ return false;
+ if (info->palette.size() > maxColours)
+ return false;
+
+ // FIXME: This doesn't account for switching lines
+ info->rleRuns++;
+
+ colour = *buffer;
+ count = 0;
+ }
+ buffer++;
+ count++;
+ }
+ buffer += pad;
+ }
+
+ // Make sure the final pixels also get counted
+ if (!info->palette.insert(colour, count))
+ return false;
+ if (info->palette.size() > maxColours)
+ return false;
+
+ return true;
+}
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2014-2018 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
struct RectInfo *info, int maxColours);
protected:
- // Preprocessor generated, optimised methods
- inline bool checkSolidTile(const Rect& r, rdr::U8 colourValue,
+ // Templated, optimised methods
+ template<class T>
+ inline bool checkSolidTile(const Rect& r, const T,
const PixelBuffer *pb);
- inline bool checkSolidTile(const Rect& r, rdr::U16 colourValue,
- const PixelBuffer *pb);
- inline bool checkSolidTile(const Rect& r, rdr::U32 colourValue,
- const PixelBuffer *pb);
-
- inline bool analyseRect(int width, int height,
- const rdr::U8* buffer, int stride,
- struct RectInfo *info, int maxColours);
- inline bool analyseRect(int width, int height,
- const rdr::U16* buffer, int stride,
- struct RectInfo *info, int maxColours);
+ template<class T>
inline bool analyseRect(int width, int height,
- const rdr::U32* buffer, int stride,
+ const T* buffer, int stride,
struct RectInfo *info, int maxColours);
protected:
+++ /dev/null
-/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
- * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2014 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-
-#define UBPP CONCAT2E(U,BPP)
-
-inline bool EncodeManager::checkSolidTile(const Rect& r,
- rdr::UBPP colourValue,
- const PixelBuffer *pb)
-{
- int w, h;
- const rdr::UBPP* buffer;
- int stride, pad;
-
- w = r.width();
- h = r.height();
-
- buffer = (const rdr::UBPP*)pb->getBuffer(r, &stride);
- pad = stride - w;
-
- while (h--) {
- int w_ = w;
- while (w_--) {
- if (*buffer != colourValue)
- return false;
- buffer++;
- }
- buffer += pad;
- }
-
- return true;
-}
-
-inline bool EncodeManager::analyseRect(int width, int height,
- const rdr::UBPP* buffer, int stride,
- struct RectInfo *info, int maxColours)
-{
- int pad;
-
- rdr::UBPP colour;
- int count;
-
- info->rleRuns = 0;
- info->palette.clear();
-
- pad = stride - width;
-
- // For efficiency, we only update the palette on changes in colour
- colour = buffer[0];
- count = 0;
- while (height--) {
- int w_ = width;
- while (w_--) {
- if (*buffer != colour) {
- if (!info->palette.insert(colour, count))
- return false;
- if (info->palette.size() > maxColours)
- return false;
-
- // FIXME: This doesn't account for switching lines
- info->rleRuns++;
-
- colour = *buffer;
- count = 0;
- }
- buffer++;
- count++;
- }
- buffer += pad;
- }
-
- // Make sure the final pixels also get counted
- if (!info->palette.insert(colour, count))
- return false;
- if (info->palette.size() > maxColours)
- return false;
-
- return true;
-}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2014-2022 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
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
+#include <rfb/Exception.h>
#include <rfb/ServerParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/HextileDecoder.h>
+#include <rfb/hextileConstants.h>
using namespace rfb;
-#define BPP 8
-#include <rfb/hextileDecode.h>
-#undef BPP
-#define BPP 16
-#include <rfb/hextileDecode.h>
-#undef BPP
-#define BPP 32
-#include <rfb/hextileDecode.h>
-#undef BPP
-
HextileDecoder::HextileDecoder() : Decoder(DecoderPlain)
{
}
rdr::MemInStream is(buffer, buflen);
const PixelFormat& pf = server.pf();
switch (pf.bpp) {
- case 8: hextileDecode8 (r, &is, pf, pb); break;
- case 16: hextileDecode16(r, &is, pf, pb); break;
- case 32: hextileDecode32(r, &is, pf, pb); break;
+ case 8: hextileDecode<rdr::U8 >(r, &is, pf, pb); break;
+ case 16: hextileDecode<rdr::U16>(r, &is, pf, pb); break;
+ case 32: hextileDecode<rdr::U32>(r, &is, pf, pb); break;
+ }
+}
+
+template<class T>
+inline T HextileDecoder::readPixel(rdr::InStream* is)
+{
+ if (sizeof(T) == 1)
+ return is->readOpaque8();
+ if (sizeof(T) == 2)
+ return is->readOpaque16();
+ if (sizeof(T) == 4)
+ return is->readOpaque32();
+}
+
+template<class T>
+void HextileDecoder::hextileDecode(const Rect& r, rdr::InStream* is,
+ const PixelFormat& pf,
+ ModifiablePixelBuffer* pb)
+{
+ Rect t;
+ T bg = 0;
+ T fg = 0;
+ T buf[16 * 16];
+
+ 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) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+
+ int tileType = is->readU8();
+
+ if (tileType & hextileRaw) {
+ is->readBytes(buf, t.area() * sizeof(T));
+ pb->imageRect(pf, t, buf);
+ continue;
+ }
+
+ if (tileType & hextileBgSpecified)
+ bg = readPixel<T>(is);
+
+ int len = t.area();
+ T* ptr = buf;
+ while (len-- > 0) *ptr++ = bg;
+
+ if (tileType & hextileFgSpecified)
+ fg = readPixel<T>(is);
+
+ if (tileType & hextileAnySubrects) {
+ int nSubrects = is->readU8();
+
+ for (int i = 0; i < nSubrects; i++) {
+
+ if (tileType & hextileSubrectsColoured)
+ fg = readPixel<T>(is);
+
+ int xy = is->readU8();
+ int wh = is->readU8();
+
+ int x = ((xy >> 4) & 15);
+ int y = (xy & 15);
+ int w = ((wh >> 4) & 15) + 1;
+ int h = (wh & 15) + 1;
+ if (x + w > 16 || y + h > 16) {
+ throw rfb::Exception("HEXTILE_DECODE: Hextile out of bounds");
+ }
+ T* ptr = buf + y * t.width() + x;
+ int rowAdd = t.width() - w;
+ while (h-- > 0) {
+ int len = w;
+ while (len-- > 0) *ptr++ = fg;
+ ptr += rowAdd;
+ }
+ }
+ }
+ pb->imageRect(pf, t, buf);
+ }
}
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2014-2022 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
namespace rfb {
+ class PixelFormat;
+
class HextileDecoder : public Decoder {
public:
HextileDecoder();
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
+ private:
+ template<class T>
+ inline T readPixel(rdr::InStream* is);
+ template<class T>
+ void hextileDecode(const Rect& r, rdr::InStream* is,
+ const PixelFormat& pf,
+ ModifiablePixelBuffer* pb);
};
}
#endif
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2005 Constantin Kaplinsky. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
#include <rfb/encodings.h>
#include <rfb/SConnection.h>
#include <rfb/HextileEncoder.h>
+#include <rfb/Palette.h>
#include <rfb/PixelBuffer.h>
#include <rfb/Configuration.h>
+#include <rfb/hextileConstants.h>
using namespace rfb;
"ratios by the cost of using more CPU time",
true);
-#define BPP 8
-#include <rfb/hextileEncode.h>
-#include <rfb/hextileEncodeBetter.h>
-#undef BPP
-#define BPP 16
-#include <rfb/hextileEncode.h>
-#include <rfb/hextileEncodeBetter.h>
-#undef BPP
-#define BPP 32
-#include <rfb/hextileEncode.h>
-#include <rfb/hextileEncodeBetter.h>
-#undef BPP
-
HextileEncoder::HextileEncoder(SConnection* conn) :
Encoder(conn, encodingHextile, EncoderPlain)
{
switch (pb->getPF().bpp) {
case 8:
if (improvedHextile) {
- hextileEncodeBetter8(os, pb);
+ hextileEncodeBetter<rdr::U8>(os, pb);
} else {
- hextileEncode8(os, pb);
+ hextileEncode<rdr::U8>(os, pb);
}
break;
case 16:
if (improvedHextile) {
- hextileEncodeBetter16(os, pb);
+ hextileEncodeBetter<rdr::U16>(os, pb);
} else {
- hextileEncode16(os, pb);
+ hextileEncode<rdr::U16>(os, pb);
}
break;
case 32:
if (improvedHextile) {
- hextileEncodeBetter32(os, pb);
+ hextileEncodeBetter<rdr::U32>(os, pb);
} else {
- hextileEncode32(os, pb);
+ hextileEncode<rdr::U32>(os, pb);
}
break;
}
while (tiles--)
os->writeU8(0);
}
+
+template<class T>
+inline void HextileEncoder::writePixel(rdr::OutStream* os, T pixel)
+{
+ if (sizeof(T) == 1)
+ os->writeOpaque8(pixel);
+ else if (sizeof(T) == 2)
+ os->writeOpaque16(pixel);
+ else if (sizeof(T) == 4)
+ os->writeOpaque32(pixel);
+}
+
+template<class T>
+void HextileEncoder::hextileEncode(rdr::OutStream* os,
+ const PixelBuffer* pb)
+{
+ Rect t;
+ T buf[256];
+ T oldBg = 0, oldFg = 0;
+ bool oldBgValid = false;
+ bool oldFgValid = false;
+ rdr::U8 encoded[256*sizeof(T)];
+
+ for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
+
+ t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
+
+ for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
+
+ t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
+
+ pb->getImage(buf, t);
+
+ T bg = 0, fg = 0;
+ int tileType = testTileType(buf, t.width(), t.height(), &bg, &fg);
+
+ if (!oldBgValid || oldBg != bg) {
+ tileType |= hextileBgSpecified;
+ oldBg = bg;
+ oldBgValid = true;
+ }
+
+ int encodedLen = 0;
+
+ if (tileType & hextileAnySubrects) {
+
+ if (tileType & hextileSubrectsColoured) {
+ oldFgValid = false;
+ } else {
+ if (!oldFgValid || oldFg != fg) {
+ tileType |= hextileFgSpecified;
+ oldFg = fg;
+ oldFgValid = true;
+ }
+ }
+
+ encodedLen = hextileEncodeTile(buf, t.width(), t.height(),
+ tileType, encoded, bg);
+
+ if (encodedLen < 0) {
+ pb->getImage(buf, t);
+ os->writeU8(hextileRaw);
+ os->writeBytes(buf, t.width() * t.height() * sizeof(T));
+ oldBgValid = oldFgValid = false;
+ continue;
+ }
+ }
+
+ os->writeU8(tileType);
+ if (tileType & hextileBgSpecified) writePixel(os, bg);
+ if (tileType & hextileFgSpecified) writePixel(os, fg);
+ if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
+ }
+ }
+}
+
+template<class T>
+int HextileEncoder::hextileEncodeTile(T* data, int w, int h,
+ int tileType, rdr::U8* encoded,
+ T bg)
+{
+ rdr::U8* nSubrectsPtr = encoded;
+ *nSubrectsPtr = 0;
+ encoded++;
+
+ for (int y = 0; y < h; y++)
+ {
+ int x = 0;
+ while (x < w) {
+ if (*data == bg) {
+ x++;
+ data++;
+ continue;
+ }
+
+ // Find horizontal subrect first
+ T* ptr = data+1;
+ T* eol = data+w-x;
+ while (ptr < eol && *ptr == *data) ptr++;
+ int sw = ptr - data;
+
+ ptr = data + w;
+ int sh = 1;
+ while (sh < h-y) {
+ eol = ptr + sw;
+ while (ptr < eol)
+ if (*ptr++ != *data) goto endOfSubrect;
+ ptr += w - sw;
+ sh++;
+ }
+ endOfSubrect:
+
+ (*nSubrectsPtr)++;
+
+ if (tileType & hextileSubrectsColoured) {
+ if (encoded - nSubrectsPtr + sizeof(T) > w*h*sizeof(T))
+ return -1;
+
+ if (sizeof(T) == 1) {
+ *encoded++ = *data;
+ } else if (sizeof(T) == 2) {
+ *encoded++ = ((rdr::U8*)data)[0];
+ *encoded++ = ((rdr::U8*)data)[1];
+ } else if (sizeof(T) == 4) {
+ *encoded++ = ((rdr::U8*)data)[0];
+ *encoded++ = ((rdr::U8*)data)[1];
+ *encoded++ = ((rdr::U8*)data)[2];
+ *encoded++ = ((rdr::U8*)data)[3];
+ }
+ }
+
+ if ((size_t)(encoded - nSubrectsPtr + 2) > w*h*sizeof(T))
+ return -1;
+ *encoded++ = (x << 4) | y;
+ *encoded++ = ((sw-1) << 4) | (sh-1);
+
+ ptr = data+w;
+ T* eor = data+w*sh;
+ while (ptr < eor) {
+ eol = ptr + sw;
+ while (ptr < eol) *ptr++ = bg;
+ ptr += w - sw;
+ }
+ x += sw;
+ data += sw;
+ }
+ }
+ return encoded - nSubrectsPtr;
+}
+
+template<class T>
+int HextileEncoder::testTileType(T* data, int w, int h, T* bg, T* fg)
+{
+ T pix1 = *data;
+ T* end = data + w * h;
+
+ T* ptr = data + 1;
+ while (ptr < end && *ptr == pix1)
+ ptr++;
+
+ if (ptr == end) {
+ *bg = pix1;
+ return 0; // solid-color tile
+ }
+
+ int count1 = ptr - data;
+ int count2 = 1;
+ T pix2 = *ptr++;
+ int tileType = hextileAnySubrects;
+
+ for (; ptr < end; ptr++) {
+ if (*ptr == pix1) {
+ count1++;
+ } else if (*ptr == pix2) {
+ count2++;
+ } else {
+ tileType |= hextileSubrectsColoured;
+ break;
+ }
+ }
+
+ if (count1 >= count2) {
+ *bg = pix1; *fg = pix2;
+ } else {
+ *bg = pix2; *fg = pix1;
+ }
+ return tileType;
+}
+
+//
+// This class analyzes a separate tile and encodes its subrectangles.
+//
+
+template<class T>
+class HextileTile {
+
+ public:
+
+ HextileTile ();
+
+ //
+ // Initialize existing object instance with new tile data.
+ //
+ void newTile(const T *src, int w, int h);
+
+ //
+ // Flags can include: hextileRaw, hextileAnySubrects and
+ // hextileSubrectsColoured. Note that if hextileRaw is set, other
+ // flags make no sense. Also, hextileSubrectsColoured is meaningful
+ // only when hextileAnySubrects is set as well.
+ //
+ int getFlags() const { return m_flags; }
+
+ //
+ // Returns the size of encoded subrects data, including subrect count.
+ // The size is zero if flags do not include hextileAnySubrects.
+ //
+ size_t getSize() const { return m_size; }
+
+ //
+ // Return optimal background.
+ //
+ int getBackground() const { return m_background; }
+
+ //
+ // Return foreground if flags include hextileSubrectsColoured.
+ //
+ int getForeground() const { return m_foreground; }
+
+ //
+ // Encode subrects. This function may be called only if
+ // hextileAnySubrects bit is set in flags. The buffer size should be
+ // big enough to store at least the number of bytes returned by the
+ // getSize() method.
+ //
+ void encode(rdr::U8* dst) const;
+
+ protected:
+
+ //
+ // Analyze the tile pixels, fill in all the data fields.
+ //
+ void analyze();
+
+ const T *m_tile;
+ int m_width;
+ int m_height;
+
+ size_t m_size;
+ int m_flags;
+ T m_background;
+ T m_foreground;
+
+ int m_numSubrects;
+ rdr::U8 m_coords[256 * 2];
+ T m_colors[256];
+
+ private:
+
+ bool m_processed[16][16];
+ Palette m_pal;
+};
+
+template<class T>
+HextileTile<T>::HextileTile()
+ : m_tile(NULL), m_width(0), m_height(0),
+ m_size(0), m_flags(0), m_background(0), m_foreground(0),
+ m_numSubrects(0)
+{
+}
+
+template<class T>
+void HextileTile<T>::newTile(const T *src, int w, int h)
+{
+ m_tile = src;
+ m_width = w;
+ m_height = h;
+
+ analyze();
+}
+
+template<class T>
+void HextileTile<T>::analyze()
+{
+ assert(m_tile && m_width && m_height);
+
+ const T *ptr = m_tile;
+ const T *end = &m_tile[m_width * m_height];
+ T color = *ptr++;
+ while (ptr != end && *ptr == color)
+ ptr++;
+
+ // Handle solid tile
+ if (ptr == end) {
+ m_background = m_tile[0];
+ m_flags = 0;
+ m_size = 0;
+ return;
+ }
+
+ // Compute number of complete rows of the same color, at the top
+ int y = (ptr - m_tile) / m_width;
+
+ T *colorsPtr = m_colors;
+ rdr::U8 *coordsPtr = m_coords;
+ m_pal.clear();
+ m_numSubrects = 0;
+
+ // Have we found the first subrect already?
+ if (y > 0) {
+ *colorsPtr++ = color;
+ *coordsPtr++ = 0;
+ *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F));
+ m_pal.insert(color, 1);
+ m_numSubrects++;
+ }
+
+ memset(m_processed, 0, 16 * 16 * sizeof(bool));
+
+ int x, sx, sy, sw, sh, max_x;
+
+ for (; y < m_height; y++) {
+ for (x = 0; x < m_width; x++) {
+ // Skip pixels that were processed earlier
+ if (m_processed[y][x]) {
+ continue;
+ }
+ // Determine dimensions of the horizontal subrect
+ color = m_tile[y * m_width + x];
+ for (sx = x + 1; sx < m_width; sx++) {
+ if (m_tile[y * m_width + sx] != color)
+ break;
+ }
+ sw = sx - x;
+ max_x = sx;
+ for (sy = y + 1; sy < m_height; sy++) {
+ for (sx = x; sx < max_x; sx++) {
+ if (m_tile[sy * m_width + sx] != color)
+ goto done;
+ }
+ }
+ done:
+ sh = sy - y;
+
+ // Save properties of this subrect
+ *colorsPtr++ = color;
+ *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F));
+ *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F));
+
+ if (!m_pal.insert(color, 1) ||
+ ((size_t)m_pal.size() > (48 + 2 * sizeof(T)*8))) {
+ // Handle palette overflow
+ m_flags = hextileRaw;
+ m_size = 0;
+ return;
+ }
+
+ m_numSubrects++;
+
+ // Mark pixels of this subrect as processed, below this row
+ for (sy = y + 1; sy < y + sh; sy++) {
+ for (sx = x; sx < x + sw; sx++)
+ m_processed[sy][sx] = true;
+ }
+
+ // Skip processed pixels of this row
+ x += (sw - 1);
+ }
+ }
+
+ // Save number of colors in this tile (should be no less than 2)
+ int numColors = m_pal.size();
+ assert(numColors >= 2);
+
+ m_background = (T)m_pal.getColour(0);
+ m_flags = hextileAnySubrects;
+ int numSubrects = m_numSubrects - m_pal.getCount(0);
+
+ if (numColors == 2) {
+ // Monochrome tile
+ m_foreground = (T)m_pal.getColour(1);
+ m_size = 1 + 2 * numSubrects;
+ } else {
+ // Colored tile
+ m_flags |= hextileSubrectsColoured;
+ m_size = 1 + (2 + sizeof(T)) * numSubrects;
+ }
+}
+
+template<class T>
+void HextileTile<T>::encode(rdr::U8 *dst) const
+{
+ assert(m_numSubrects && (m_flags & hextileAnySubrects));
+
+ // Zero subrects counter
+ rdr::U8 *numSubrectsPtr = dst;
+ *dst++ = 0;
+
+ for (int i = 0; i < m_numSubrects; i++) {
+ if (m_colors[i] == m_background)
+ continue;
+
+ if (m_flags & hextileSubrectsColoured) {
+ if (sizeof(T) == 1) {
+ *dst++ = m_colors[i];
+ } else if (sizeof(T) == 2) {
+ *dst++ = ((rdr::U8*)&m_colors[i])[0];
+ *dst++ = ((rdr::U8*)&m_colors[i])[1];
+ } else if (sizeof(T) == 4) {
+ *dst++ = ((rdr::U8*)&m_colors[i])[0];
+ *dst++ = ((rdr::U8*)&m_colors[i])[1];
+ *dst++ = ((rdr::U8*)&m_colors[i])[2];
+ *dst++ = ((rdr::U8*)&m_colors[i])[3];
+ }
+ }
+ *dst++ = m_coords[i * 2];
+ *dst++ = m_coords[i * 2 + 1];
+
+ (*numSubrectsPtr)++;
+ }
+
+ assert((size_t)(dst - numSubrectsPtr) == m_size);
+}
+
+//
+// Main encoding function.
+//
+
+template<class T>
+void HextileEncoder::hextileEncodeBetter(rdr::OutStream* os,
+ const PixelBuffer* pb)
+{
+ Rect t;
+ T buf[256];
+ T oldBg = 0, oldFg = 0;
+ bool oldBgValid = false;
+ bool oldFgValid = false;
+ rdr::U8 encoded[256*sizeof(T)];
+
+ HextileTile<T> tile;
+
+ for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
+
+ t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
+
+ for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
+
+ t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
+
+ pb->getImage(buf, t);
+
+ tile.newTile(buf, t.width(), t.height());
+ int tileType = tile.getFlags();
+ size_t encodedLen = tile.getSize();
+
+ if ( (tileType & hextileRaw) != 0 ||
+ encodedLen >= t.width() * t.height() * sizeof(T)) {
+ os->writeU8(hextileRaw);
+ os->writeBytes(buf, t.width() * t.height() * sizeof(T));
+ oldBgValid = oldFgValid = false;
+ continue;
+ }
+
+ T bg = tile.getBackground();
+ T fg = 0;
+
+ if (!oldBgValid || oldBg != bg) {
+ tileType |= hextileBgSpecified;
+ oldBg = bg;
+ oldBgValid = true;
+ }
+
+ if (tileType & hextileAnySubrects) {
+ if (tileType & hextileSubrectsColoured) {
+ oldFgValid = false;
+ } else {
+ fg = tile.getForeground();
+ if (!oldFgValid || oldFg != fg) {
+ tileType |= hextileFgSpecified;
+ oldFg = fg;
+ oldFgValid = true;
+ }
+ }
+ tile.encode(encoded);
+ }
+
+ os->writeU8(tileType);
+ if (tileType & hextileBgSpecified) writePixel(os, bg);
+ if (tileType & hextileFgSpecified) writePixel(os, fg);
+ if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
+ }
+ }
+}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
virtual void writeSolidRect(int width, int height,
const PixelFormat& pf,
const rdr::U8* colour);
+ private:
+ template<class T>
+ inline void writePixel(rdr::OutStream* os, T pixel);
+
+ template<class T>
+ void hextileEncode(rdr::OutStream* os, const PixelBuffer* pb);
+ template<class T>
+ int hextileEncodeTile(T* data, int w, int h, int tileType,
+ rdr::U8* encoded, T bg);
+ template<class T>
+ int testTileType(T* data, int w, int h, T* bg, T* fg);
+
+ template<class T>
+ void hextileEncodeBetter(rdr::OutStream* os, const PixelBuffer* pb);
};
}
#endif
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2022 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
return true;
}
-// Preprocessor generated, optimised methods
-
-#define INBPP 8
-#define OUTBPP 8
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#define OUTBPP 16
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#define OUTBPP 32
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#undef INBPP
-
-#define INBPP 16
-#define OUTBPP 8
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#define OUTBPP 16
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#define OUTBPP 32
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#undef INBPP
-
-#define INBPP 32
-#define OUTBPP 8
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#define OUTBPP 16
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#define OUTBPP 32
-#include "PixelFormatBPP.cxx"
-#undef OUTBPP
-#undef INBPP
+static inline uint8_t swap(uint8_t n)
+{
+ return n;
+}
+
+static inline uint16_t swap(uint16_t n)
+{
+ return (((n) & 0xff) << 8) | (((n) >> 8) & 0xff);
+}
+
+static inline uint32_t swap(uint32_t n)
+{
+ return ((n) >> 24) | (((n) & 0x00ff0000) >> 8) |
+ (((n) & 0x0000ff00) << 8) | ((n) << 24);
+}
+
+template<class T>
+void PixelFormat::directBufferFromBufferFrom888(T* dst,
+ const PixelFormat &srcPF,
+ const uint8_t* src,
+ int w, int h,
+ int dstStride,
+ int srcStride) const
+{
+ const uint8_t *r, *g, *b;
+ int dstPad, srcPad;
+
+ const uint8_t *redDownTable, *greenDownTable, *blueDownTable;
+
+ redDownTable = &downconvTable[(redBits-1)*256];
+ greenDownTable = &downconvTable[(greenBits-1)*256];
+ blueDownTable = &downconvTable[(blueBits-1)*256];
+
+ if (srcPF.bigEndian) {
+ r = src + (24 - srcPF.redShift)/8;
+ g = src + (24 - srcPF.greenShift)/8;
+ b = src + (24 - srcPF.blueShift)/8;
+ } else {
+ r = src + srcPF.redShift/8;
+ g = src + srcPF.greenShift/8;
+ b = src + srcPF.blueShift/8;
+ }
+
+ dstPad = (dstStride - w);
+ srcPad = (srcStride - w) * 4;
+ while (h--) {
+ int w_ = w;
+ while (w_--) {
+ T d;
+
+ d = redDownTable[*r] << redShift;
+ d |= greenDownTable[*g] << greenShift;
+ d |= blueDownTable[*b] << blueShift;
+
+ if (endianMismatch)
+ d = swap(d);
+
+ *dst = d;
+ dst++;
+ r += 4;
+ g += 4;
+ b += 4;
+ }
+ dst += dstPad;
+ r += srcPad;
+ g += srcPad;
+ b += srcPad;
+ }
+}
+
+template<class T>
+void PixelFormat::directBufferFromBufferTo888(uint8_t* dst,
+ const PixelFormat &srcPF,
+ const T* src,
+ int w, int h,
+ int dstStride,
+ int srcStride) const
+{
+ uint8_t *r, *g, *b, *x;
+ int dstPad, srcPad;
+
+ const uint8_t *redUpTable, *greenUpTable, *blueUpTable;
+
+ redUpTable = &upconvTable[(srcPF.redBits-1)*256];
+ greenUpTable = &upconvTable[(srcPF.greenBits-1)*256];
+ blueUpTable = &upconvTable[(srcPF.blueBits-1)*256];
+
+ if (bigEndian) {
+ r = dst + (24 - redShift)/8;
+ g = dst + (24 - greenShift)/8;
+ b = dst + (24 - blueShift)/8;
+ x = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
+ } else {
+ r = dst + redShift/8;
+ g = dst + greenShift/8;
+ b = dst + blueShift/8;
+ x = dst + (48 - redShift - greenShift - blueShift)/8;
+ }
+
+ dstPad = (dstStride - w) * 4;
+ srcPad = (srcStride - w);
+ while (h--) {
+ int w_ = w;
+ while (w_--) {
+ T s;
+
+ s = *src;
+
+ if (srcPF.endianMismatch)
+ s = swap(s);
+
+ *r = redUpTable[(s >> srcPF.redShift) & 0xff];
+ *g = greenUpTable[(s >> srcPF.greenShift) & 0xff];
+ *b = blueUpTable[(s >> srcPF.blueShift) & 0xff];
+ *x = 0;
+
+ r += 4;
+ g += 4;
+ b += 4;
+ x += 4;
+ src++;
+ }
+ r += dstPad;
+ g += dstPad;
+ b += dstPad;
+ x += dstPad;
+ src += srcPad;
+ }
+}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2022 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
bool isSane(void);
private:
- // Preprocessor generated, optimised methods
-
- void directBufferFromBufferFrom888(rdr::U8* dst, const PixelFormat &srcPF,
- const rdr::U8* src, int w, int h,
- int dstStride, int srcStride) const;
- void directBufferFromBufferFrom888(rdr::U16* dst, const PixelFormat &srcPF,
- const rdr::U8* src, int w, int h,
- int dstStride, int srcStride) const;
- void directBufferFromBufferFrom888(rdr::U32* dst, const PixelFormat &srcPF,
+ // Templated, optimised methods
+ template<class T>
+ void directBufferFromBufferFrom888(T* dst, const PixelFormat &srcPF,
const rdr::U8* src, int w, int h,
int dstStride, int srcStride) const;
-
- void directBufferFromBufferTo888(rdr::U8* dst, const PixelFormat &srcPF,
- const rdr::U8* src, int w, int h,
- int dstStride, int srcStride) const;
- void directBufferFromBufferTo888(rdr::U8* dst, const PixelFormat &srcPF,
- const rdr::U16* src, int w, int h,
- int dstStride, int srcStride) const;
+ template<class T>
void directBufferFromBufferTo888(rdr::U8* dst, const PixelFormat &srcPF,
- const rdr::U32* src, int w, int h,
+ const T* src, int w, int h,
int dstStride, int srcStride) const;
public:
+++ /dev/null
-/* Copyright 2014 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-
-#define UIN CONCAT2E(U,INBPP)
-#define UOUT CONCAT2E(U,OUTBPP)
-
-#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
-#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
- (((n) & 0x0000ff00) << 8) | ((n) << 24))
-
-#define SWAPIN CONCAT2E(SWAP,INBPP)
-#define SWAPOUT CONCAT2E(SWAP,OUTBPP)
-
-#if INBPP == 32
-
-void PixelFormat::directBufferFromBufferFrom888(rdr::UOUT* dst,
- const PixelFormat &srcPF,
- const rdr::U8* src,
- int w, int h,
- int dstStride,
- int srcStride) const
-{
- const rdr::U8 *r, *g, *b;
- int dstPad, srcPad;
-
- const rdr::U8 *redDownTable, *greenDownTable, *blueDownTable;
-
- redDownTable = &downconvTable[(redBits-1)*256];
- greenDownTable = &downconvTable[(greenBits-1)*256];
- blueDownTable = &downconvTable[(blueBits-1)*256];
-
- if (srcPF.bigEndian) {
- r = src + (24 - srcPF.redShift)/8;
- g = src + (24 - srcPF.greenShift)/8;
- b = src + (24 - srcPF.blueShift)/8;
- } else {
- r = src + srcPF.redShift/8;
- g = src + srcPF.greenShift/8;
- b = src + srcPF.blueShift/8;
- }
-
- dstPad = (dstStride - w);
- srcPad = (srcStride - w) * 4;
- while (h--) {
- int w_ = w;
- while (w_--) {
- rdr::UOUT d;
-
- d = redDownTable[*r] << redShift;
- d |= greenDownTable[*g] << greenShift;
- d |= blueDownTable[*b] << blueShift;
-
-#if OUTBPP != 8
- if (endianMismatch)
- d = SWAPOUT(d);
-#endif
-
- *dst = d;
-
- dst++;
- r += 4;
- g += 4;
- b += 4;
- }
- dst += dstPad;
- r += srcPad;
- g += srcPad;
- b += srcPad;
- }
-}
-
-#endif /* INBPP == 32 */
-
-#if OUTBPP == 32
-
-void PixelFormat::directBufferFromBufferTo888(rdr::U8* dst,
- const PixelFormat &srcPF,
- const rdr::UIN* src,
- int w, int h,
- int dstStride,
- int srcStride) const
-{
- rdr::U8 *r, *g, *b, *x;
- int dstPad, srcPad;
-
- const rdr::U8 *redUpTable, *greenUpTable, *blueUpTable;
-
- redUpTable = &upconvTable[(srcPF.redBits-1)*256];
- greenUpTable = &upconvTable[(srcPF.greenBits-1)*256];
- blueUpTable = &upconvTable[(srcPF.blueBits-1)*256];
-
- if (bigEndian) {
- r = dst + (24 - redShift)/8;
- g = dst + (24 - greenShift)/8;
- b = dst + (24 - blueShift)/8;
- x = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
- } else {
- r = dst + redShift/8;
- g = dst + greenShift/8;
- b = dst + blueShift/8;
- x = dst + (48 - redShift - greenShift - blueShift)/8;
- }
-
- dstPad = (dstStride - w) * 4;
- srcPad = (srcStride - w);
- while (h--) {
- int w_ = w;
- while (w_--) {
- rdr::UIN s;
-
- s = *src;
-
-#if INBPP != 8
- if (srcPF.endianMismatch)
- s = SWAPIN(s);
-#endif
-
- *r = redUpTable[(s >> srcPF.redShift) & 0xff];
- *g = greenUpTable[(s >> srcPF.greenShift) & 0xff];
- *b = blueUpTable[(s >> srcPF.blueShift) & 0xff];
- *x = 0;
-
- r += 4;
- g += 4;
- b += 4;
- x += 4;
- src++;
- }
- r += dstPad;
- g += dstPad;
- b += dstPad;
- x += dstPad;
- src += srcPad;
- }
-}
-
-#endif /* OUTBPP == 32 */
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2014-2022 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
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
+#include <rfb/Exception.h>
#include <rfb/ServerParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RREDecoder.h>
using namespace rfb;
-#define BPP 8
-#include <rfb/rreDecode.h>
-#undef BPP
-#define BPP 16
-#include <rfb/rreDecode.h>
-#undef BPP
-#define BPP 32
-#include <rfb/rreDecode.h>
-#undef BPP
-
RREDecoder::RREDecoder() : Decoder(DecoderPlain)
{
}
rdr::MemInStream is(buffer, buflen);
const PixelFormat& pf = server.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: rreDecode<rdr::U8 >(r, &is, pf, pb); break;
+ case 16: rreDecode<rdr::U16>(r, &is, pf, pb); break;
+ case 32: rreDecode<rdr::U32>(r, &is, pf, pb); break;
+ }
+}
+
+template<class T>
+inline T RREDecoder::readPixel(rdr::InStream* is)
+{
+ if (sizeof(T) == 1)
+ return is->readOpaque8();
+ if (sizeof(T) == 2)
+ return is->readOpaque16();
+ if (sizeof(T) == 4)
+ return is->readOpaque32();
+}
+
+template<class T>
+void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is,
+ const PixelFormat& pf,
+ ModifiablePixelBuffer* pb)
+{
+ int nSubrects = is->readU32();
+ T bg = readPixel<T>(is);
+ pb->fillRect(pf, r, &bg);
+
+ for (int i = 0; i < nSubrects; i++) {
+ T pix = readPixel<T>(is);
+ int x = is->readU16();
+ int y = is->readU16();
+ int w = is->readU16();
+ int h = is->readU16();
+
+ if (((x+w) > r.width()) || ((y+h) > r.height()))
+ throw Exception ("RRE decode error");
+
+ pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), &pix);
}
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2014-2022 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
namespace rfb {
+ class PixelFormat;
+
class RREDecoder : public Decoder {
public:
RREDecoder();
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
+ private:
+ template<class T>
+ inline T readPixel(rdr::InStream* is);
+ template<class T>
+ void rreDecode(const Rect& r, rdr::InStream* is,
+ const PixelFormat& pf, ModifiablePixelBuffer* pb);
};
}
#endif
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
using namespace rfb;
-#define BPP 8
-#include <rfb/rreEncode.h>
-#undef BPP
-#define BPP 16
-#include <rfb/rreEncode.h>
-#undef BPP
-#define BPP 32
-#include <rfb/rreEncode.h>
-#undef BPP
-
RREEncoder::RREEncoder(SConnection* conn) :
Encoder(conn, encodingRRE, EncoderPlain)
{
int nSubrects = -1;
switch (pb->getPF().bpp) {
case 8:
- nSubrects = rreEncode8((rdr::U8*)imageBuf, w, h, &mos, bg);
+ nSubrects = rreEncode<rdr::U8>((rdr::U8*)imageBuf, w, h, &mos, bg);
break;
case 16:
- nSubrects = rreEncode16((rdr::U16*)imageBuf, w, h, &mos, bg);
+ nSubrects = rreEncode<rdr::U16>((rdr::U16*)imageBuf, w, h, &mos, bg);
break;
case 32:
- nSubrects = rreEncode32((rdr::U32*)imageBuf, w, h, &mos, bg);
+ nSubrects = rreEncode<rdr::U32>((rdr::U32*)imageBuf, w, h, &mos, bg);
break;
}
os->writeU32(0);
os->writeBytes(colour, pf.bpp/8);
}
+
+template<class T>
+inline void RREEncoder::writePixel(rdr::OutStream* os, T pixel)
+{
+ if (sizeof(T) == 1)
+ os->writeOpaque8(pixel);
+ else if (sizeof(T) == 2)
+ os->writeOpaque16(pixel);
+ else if (sizeof(T) == 4)
+ os->writeOpaque32(pixel);
+}
+
+template<class T>
+int RREEncoder::rreEncode(T* data, int w, int h,
+ rdr::OutStream* os, T bg)
+{
+ writePixel(os, bg);
+
+ int nSubrects = 0;
+
+ for (int y = 0; y < h; y++)
+ {
+ int x = 0;
+ while (x < w) {
+ if (*data == bg) {
+ x++;
+ data++;
+ continue;
+ }
+
+ // Find horizontal subrect first
+ T* ptr = data+1;
+ T* eol = data+w-x;
+ while (ptr < eol && *ptr == *data) ptr++;
+ int sw = ptr - data;
+
+ ptr = data + w;
+ int sh = 1;
+ while (sh < h-y) {
+ eol = ptr + sw;
+ while (ptr < eol)
+ if (*ptr++ != *data) goto endOfHorizSubrect;
+ ptr += w - sw;
+ sh++;
+ }
+ endOfHorizSubrect:
+
+ // Find vertical subrect
+ int vh;
+ for (vh = sh; vh < h-y; vh++)
+ if (data[vh*w] != *data) break;
+
+ if (vh != sh) {
+ ptr = data+1;
+ int vw;
+ for (vw = 1; vw < sw; vw++) {
+ for (int i = 0; i < vh; i++)
+ if (ptr[i*w] != *data) goto endOfVertSubrect;
+ ptr++;
+ }
+ endOfVertSubrect:
+
+ // If vertical subrect bigger than horizontal then use that.
+ if (sw*sh < vw*vh) {
+ sw = vw;
+ sh = vh;
+ }
+ }
+
+ nSubrects++;
+ writePixel(os, *data);
+ os->writeU16(x);
+ os->writeU16(y);
+ os->writeU16(sw);
+ os->writeU16(sh);
+
+ ptr = data+w;
+ T* eor = data+w*sh;
+ while (ptr < eor) {
+ eol = ptr + sw;
+ while (ptr < eol) *ptr++ = bg;
+ ptr += w - sw;
+ }
+ x += sw;
+ data += sw;
+ }
+ }
+
+ return nSubrects;
+}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
virtual void writeSolidRect(int width, int height,
const PixelFormat& pf,
const rdr::U8* colour);
+ private:
+ template<class T>
+ inline void writePixel(rdr::OutStream* os, T pixel);
+ template<class T>
+ int rreEncode(T* data, int w, int h, rdr::OutStream* os, T bg);
private:
rdr::MemOutStream mos;
ManagedPixelBuffer bufferCopy;
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright 2004-2005 Cendio AB.
- * Copyright 2009-2015 Pierre Ossman for Cendio AB
+ * Copyright 2009-2022 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
static const int TIGHT_MAX_WIDTH = 2048;
static const int TIGHT_MIN_TO_COMPRESS = 12;
-#define BPP 8
-#include <rfb/tightDecode.h>
-#undef BPP
-#define BPP 16
-#include <rfb/tightDecode.h>
-#undef BPP
-#define BPP 32
-#include <rfb/tightDecode.h>
-#undef BPP
-
TightDecoder::TightDecoder() : Decoder(DecoderPartiallyOrdered)
{
}
return result;
}
+
+void
+TightDecoder::FilterGradient24(const rdr::U8 *inbuf,
+ const PixelFormat& pf, rdr::U32* outbuf,
+ int stride, const Rect& r)
+{
+ int x, y, c;
+ rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+ rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
+ rdr::U8 pix[3];
+ int est[3];
+
+ memset(prevRow, 0, sizeof(prevRow));
+
+ // Set up shortcut variables
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ for (x = 0; x < rectWidth; x++) {
+ /* First pixel in a row */
+ if (x == 0) {
+ for (c = 0; c < 3; c++) {
+ pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c];
+ thisRow[c] = pix[c];
+ }
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
+ continue;
+ }
+
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 0xff) {
+ est[c] = 0xff;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c];
+ thisRow[x*3+c] = pix[c];
+ }
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
+ }
+
+ memcpy(prevRow, thisRow, sizeof(prevRow));
+ }
+}
+
+template<class T>
+void TightDecoder::FilterGradient(const rdr::U8* inbuf,
+ const PixelFormat& pf, 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 pix[3];
+ int est[3];
+
+ memset(prevRow, 0, sizeof(prevRow));
+
+ // Set up shortcut variables
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ for (x = 0; x < rectWidth; x++) {
+ /* First pixel in a row */
+ if (x == 0) {
+ pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1);
+ for (c = 0; c < 3; c++)
+ pix[c] += prevRow[c];
+
+ memcpy(thisRow, pix, sizeof(pix));
+
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
+
+ continue;
+ }
+
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 255) {
+ est[c] = 255;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ }
+
+ 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));
+
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
+ }
+
+ memcpy(prevRow, thisRow, sizeof(prevRow));
+ }
+}
+
+template<class T>
+void TightDecoder::FilterPalette(const T* palette, int palSize,
+ const rdr::U8* inbuf, T* outbuf,
+ int stride, const Rect& r)
+{
+ // Indexed color
+ int x, h = r.height(), w = r.width(), b, pad = stride - w;
+ 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) {
+ T *endOfRow = ptr + w;
+ while (ptr < endOfRow) {
+ *ptr++ = palette[*srcPtr++];
+ }
+ ptr += pad;
+ h--;
+ }
+ }
+}
/* 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
+ * Copyright 2009-2022 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
void FilterGradient24(const rdr::U8* inbuf, const PixelFormat& pf,
rdr::U32* outbuf, int stride, const Rect& r);
+ template<class T>
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);
+ T* outbuf, 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,
+ template<class T>
+ void FilterPalette(const T* palette, int palSize,
+ const rdr::U8* inbuf, T* outbuf,
int stride, const Rect& r);
private:
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
memStream.clear();
}
-//
-// Including BPP-dependent implementation of the encoder.
-//
+template<class T>
+void TightEncoder::writeMonoRect(int width, int height,
+ const T* buffer, int stride,
+ const PixelFormat& pf,
+ const Palette& palette)
+{
+ rdr::OutStream* os;
+
+ const int streamId = 1;
+ T pal[2];
+
+ int length;
+ rdr::OutStream* zos;
+
+ assert(palette.size() == 2);
+
+ os = conn->getOutStream();
+
+ os->writeU8((streamId | tightExplicitFilter) << 4);
+ os->writeU8(tightFilterPalette);
-#define BPP 8
-#include <rfb/TightEncoderBPP.cxx>
-#undef BPP
-#define BPP 16
-#include <rfb/TightEncoderBPP.cxx>
-#undef BPP
-#define BPP 32
-#include <rfb/TightEncoderBPP.cxx>
-#undef BPP
+ // Write the palette
+ pal[0] = (T)palette.getColour(0);
+ pal[1] = (T)palette.getColour(1);
+
+ os->writeU8(1);
+ writePixels((rdr::U8*)pal, pf, 2, os);
+
+ // Set up compression
+ length = (width + 7)/8 * height;
+ zos = getZlibOutStream(streamId, monoZlibLevel, length);
+
+ // Encode the data
+ T bg;
+ unsigned int value, mask;
+ int pad, aligned_width;
+ int x, y, bg_bits;
+
+ bg = pal[0];
+ aligned_width = width - width % 8;
+ pad = stride - width;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < aligned_width; x += 8) {
+ for (bg_bits = 0; bg_bits < 8; bg_bits++) {
+ if (*buffer++ != bg)
+ break;
+ }
+ if (bg_bits == 8) {
+ zos->writeU8(0);
+ continue;
+ }
+ mask = 0x80 >> bg_bits;
+ value = mask;
+ for (bg_bits++; bg_bits < 8; bg_bits++) {
+ mask >>= 1;
+ if (*buffer++ != bg) {
+ value |= mask;
+ }
+ }
+ zos->writeU8(value);
+ }
+
+ if (x < width) {
+ mask = 0x80;
+ value = 0;
+
+ for (; x < width; x++) {
+ if (*buffer++ != bg) {
+ value |= mask;
+ }
+ mask >>= 1;
+ }
+ zos->writeU8(value);
+ }
+
+ buffer += pad;
+ }
+
+ // Finish the zlib stream
+ flushZlibOutStream(zos);
+}
+
+template<class T>
+void TightEncoder::writeIndexedRect(int width, int height,
+ const T* buffer, int stride,
+ const PixelFormat& pf,
+ const Palette& palette)
+{
+ rdr::OutStream* os;
+
+ const int streamId = 2;
+ T pal[256];
+
+ rdr::OutStream* zos;
+
+ int pad;
+ T prevColour;
+ unsigned char idx;
+
+ assert(palette.size() > 0);
+ assert(palette.size() <= 256);
+
+ os = conn->getOutStream();
+
+ os->writeU8((streamId | tightExplicitFilter) << 4);
+ os->writeU8(tightFilterPalette);
+
+ // Write the palette
+ for (int i = 0; i < palette.size(); i++)
+ pal[i] = (T)palette.getColour(i);
+
+ os->writeU8(palette.size() - 1);
+ writePixels((rdr::U8*)pal, pf, palette.size(), os);
+
+ // Set up compression
+ zos = getZlibOutStream(streamId, idxZlibLevel, width * height);
+
+ // Encode the data
+ pad = stride - width;
+
+ prevColour = *buffer;
+ idx = palette.lookup(*buffer);
+
+ while (height--) {
+ int w = width;
+ while (w--) {
+ if (*buffer != prevColour) {
+ prevColour = *buffer;
+ idx = palette.lookup(*buffer);
+ }
+ zos->writeU8(idx);
+ buffer++;
+ }
+ buffer += pad;
+ }
+
+ // Finish the zlib stream
+ flushZlibOutStream(zos);
+}
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
void flushZlibOutStream(rdr::OutStream* os);
protected:
- // Preprocessor generated, optimised methods
+ // Templated, optimised methods
+ template<class T>
void writeMonoRect(int width, int height,
- const rdr::U8* buffer, int stride,
+ const T* buffer, int stride,
const PixelFormat& pf, const Palette& palette);
- void writeMonoRect(int width, int height,
- const rdr::U16* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
- void writeMonoRect(int width, int height,
- const rdr::U32* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
-
- void writeIndexedRect(int width, int height,
- const rdr::U16* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
+ template<class T>
void writeIndexedRect(int width, int height,
- const rdr::U32* buffer, int stride,
+ const T* buffer, int stride,
const PixelFormat& pf, const Palette& palette);
rdr::ZlibOutStream zlibStreams[4];
+++ /dev/null
-/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
- * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2014 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-
-#define UBPP CONCAT2E(U,BPP)
-
-void TightEncoder::writeMonoRect(int width, int height,
- const rdr::UBPP* buffer, int stride,
- const PixelFormat& pf,
- const Palette& palette)
-{
- rdr::OutStream* os;
-
- const int streamId = 1;
- rdr::UBPP pal[2];
-
- int length;
- rdr::OutStream* zos;
-
- assert(palette.size() == 2);
-
- os = conn->getOutStream();
-
- os->writeU8((streamId | tightExplicitFilter) << 4);
- os->writeU8(tightFilterPalette);
-
- // Write the palette
- pal[0] = (rdr::UBPP)palette.getColour(0);
- pal[1] = (rdr::UBPP)palette.getColour(1);
-
- os->writeU8(1);
- writePixels((rdr::U8*)pal, pf, 2, os);
-
- // Set up compression
- length = (width + 7)/8 * height;
- zos = getZlibOutStream(streamId, monoZlibLevel, length);
-
- // Encode the data
- rdr::UBPP bg;
- unsigned int value, mask;
- int pad, aligned_width;
- int x, y, bg_bits;
-
- bg = pal[0];
- aligned_width = width - width % 8;
- pad = stride - width;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < aligned_width; x += 8) {
- for (bg_bits = 0; bg_bits < 8; bg_bits++) {
- if (*buffer++ != bg)
- break;
- }
- if (bg_bits == 8) {
- zos->writeU8(0);
- continue;
- }
- mask = 0x80 >> bg_bits;
- value = mask;
- for (bg_bits++; bg_bits < 8; bg_bits++) {
- mask >>= 1;
- if (*buffer++ != bg) {
- value |= mask;
- }
- }
- zos->writeU8(value);
- }
-
- if (x < width) {
- mask = 0x80;
- value = 0;
-
- for (; x < width; x++) {
- if (*buffer++ != bg) {
- value |= mask;
- }
- mask >>= 1;
- }
- zos->writeU8(value);
- }
-
- buffer += pad;
- }
-
- // Finish the zlib stream
- flushZlibOutStream(zos);
-}
-
-#if (BPP != 8)
-void TightEncoder::writeIndexedRect(int width, int height,
- const rdr::UBPP* buffer, int stride,
- const PixelFormat& pf,
- const Palette& palette)
-{
- rdr::OutStream* os;
-
- const int streamId = 2;
- rdr::UBPP pal[256];
-
- rdr::OutStream* zos;
-
- int pad;
- rdr::UBPP prevColour;
- unsigned char idx;
-
- assert(palette.size() > 0);
- assert(palette.size() <= 256);
-
- os = conn->getOutStream();
-
- os->writeU8((streamId | tightExplicitFilter) << 4);
- os->writeU8(tightFilterPalette);
-
- // Write the palette
- for (int i = 0; i < palette.size(); i++)
- pal[i] = (rdr::UBPP)palette.getColour(i);
-
- os->writeU8(palette.size() - 1);
- writePixels((rdr::U8*)pal, pf, palette.size(), os);
-
- // Set up compression
- zos = getZlibOutStream(streamId, idxZlibLevel, width * height);
-
- // Encode the data
- pad = stride - width;
-
- prevColour = *buffer;
- idx = palette.lookup(*buffer);
-
- while (height--) {
- int w = width;
- while (w--) {
- if (*buffer != prevColour) {
- prevColour = *buffer;
- idx = palette.lookup(*buffer);
- }
- zos->writeU8(idx);
- buffer++;
- }
- buffer += pad;
- }
-
- // Finish the zlib stream
- flushZlibOutStream(zos);
-}
-#endif // #if (BPP != 8)
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2017 Pierre Ossman for Cendio AB
+ * Copyright 2009-2022 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
return r;
}
+template<class T>
+static inline T readPixel(rdr::ZlibInStream* zis)
+{
+ if (sizeof(T) == 1)
+ return zis->readOpaque8();
+ if (sizeof(T) == 2)
+ return zis->readOpaque16();
+ if (sizeof(T) == 4)
+ return zis->readOpaque32();
+}
+
static inline void zlibHasData(rdr::ZlibInStream* zis, size_t length)
{
if (!zis->hasData(length))
throw Exception("ZRLE decode error");
}
-#define BPP 8
-#include <rfb/zrleDecode.h>
-#undef BPP
-#define BPP 16
-#include <rfb/zrleDecode.h>
-#undef BPP
-#define BPP 32
-#include <rfb/zrleDecode.h>
-#define CPIXEL 24A
-#include <rfb/zrleDecode.h>
-#undef CPIXEL
-#define CPIXEL 24B
-#include <rfb/zrleDecode.h>
-#undef CPIXEL
-#undef BPP
-
ZRLEDecoder::ZRLEDecoder() : Decoder(DecoderOrdered)
{
}
rdr::MemInStream is(buffer, buflen);
const rfb::PixelFormat& pf = server.pf();
switch (pf.bpp) {
- case 8: zrleDecode8 (r, &is, &zis, pf, pb); break;
- case 16: zrleDecode16(r, &is, &zis, pf, pb); break;
- case 32:
- {
- if (pf.depth <= 24) {
- Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
- bool fitsInLS3Bytes = maxPixel < (1<<24);
- bool fitsInMS3Bytes = (maxPixel & 0xff) == 0;
-
- if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
- (fitsInMS3Bytes && pf.isBigEndian()))
- {
- zrleDecode24A(r, &is, &zis, pf, pb);
- break;
+ case 8: zrleDecode<rdr::U8>(r, &is, &zis, pf, pb); break;
+ case 16: zrleDecode<rdr::U16>(r, &is, &zis, pf, pb); break;
+ case 32: zrleDecode<rdr::U32>(r, &is, &zis, pf, pb); break;
+ }
+}
+
+template<class T>
+void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is,
+ rdr::ZlibInStream* zis,
+ const PixelFormat& pf,
+ ModifiablePixelBuffer* pb)
+{
+ int length = is->readU32();
+ zis->setUnderlying(is, length);
+ Rect t;
+ T buf[64 * 64];
+
+ Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
+ bool fitsInLS3Bytes = maxPixel < (1<<24);
+ bool fitsInMS3Bytes = (maxPixel & 0xff) == 0;
+ bool isLowCPixel = (sizeof(T) == 4) &&
+ ((fitsInLS3Bytes && pf.isLittleEndian()) ||
+ (fitsInMS3Bytes && pf.isBigEndian()));
+ bool isHighCPixel = (sizeof(T) == 4) &&
+ ((fitsInLS3Bytes && pf.isBigEndian()) ||
+ (fitsInMS3Bytes && pf.isLittleEndian()));
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
+
+ zlibHasData(zis, 1);
+ int mode = zis->readU8();
+ bool rle = mode & 128;
+ int palSize = mode & 127;
+ T palette[128];
+
+ if (isLowCPixel || isHighCPixel)
+ zlibHasData(zis, 3 * palSize);
+ else
+ zlibHasData(zis, sizeof(T) * palSize);
+
+ for (int i = 0; i < palSize; i++) {
+ if (isLowCPixel)
+ palette[i] = readOpaque24A(zis);
+ else if (isHighCPixel)
+ palette[i] = readOpaque24B(zis);
+ else
+ palette[i] = readPixel<T>(zis);
+ }
+
+ if (palSize == 1) {
+ T pix = palette[0];
+ pb->fillRect(pf, t, &pix);
+ continue;
+ }
+
+ if (!rle) {
+ if (palSize == 0) {
+
+ // raw
+
+ if (isLowCPixel || isHighCPixel)
+ zlibHasData(zis, 3 * t.area());
+ else
+ zlibHasData(zis, sizeof(T) * t.area());
+
+ if (isLowCPixel || isHighCPixel) {
+ for (T* ptr = buf; ptr < buf+t.area(); ptr++) {
+ if (isLowCPixel)
+ *ptr = readOpaque24A(zis);
+ else
+ *ptr = readOpaque24B(zis);
+ }
+ } else {
+ zis->readBytes(buf, t.area() * sizeof(T));
+ }
+
+ } else {
+
+ // packed pixels
+ int bppp = ((palSize > 16) ? 8 :
+ ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
+
+ T* ptr = buf;
+
+ for (int i = 0; i < t.height(); i++) {
+ T* eol = ptr + t.width();
+ rdr::U8 byte = 0;
+ rdr::U8 nbits = 0;
+
+ while (ptr < eol) {
+ if (nbits == 0) {
+ zlibHasData(zis, 1);
+ byte = zis->readU8();
+ nbits = 8;
+ }
+ nbits -= bppp;
+ rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
+ *ptr++ = palette[index];
+ }
+ }
}
- if ((fitsInLS3Bytes && pf.isBigEndian()) ||
- (fitsInMS3Bytes && pf.isLittleEndian()))
- {
- zrleDecode24B(r, &is, &zis, pf, pb);
- break;
+ } else {
+
+ if (palSize == 0) {
+
+ // plain RLE
+
+ T* ptr = buf;
+ T* end = ptr + t.area();
+ while (ptr < end) {
+ T pix;
+ if (isLowCPixel || isHighCPixel)
+ zlibHasData(zis, 3);
+ else
+ zlibHasData(zis, sizeof(T));
+ if (isLowCPixel)
+ pix = readOpaque24A(zis);
+ else if (isHighCPixel)
+ pix = readOpaque24B(zis);
+ else
+ pix = readPixel<T>(zis);
+ int len = 1;
+ int b;
+ do {
+ zlibHasData(zis, 1);
+ b = zis->readU8();
+ len += b;
+ } while (b == 255);
+
+ if (end - ptr < len) {
+ throw Exception ("ZRLE decode error");
+ }
+
+ while (len-- > 0) *ptr++ = pix;
+
+ }
+ } else {
+
+ // palette RLE
+
+ T* ptr = buf;
+ T* end = ptr + t.area();
+ while (ptr < end) {
+ zlibHasData(zis, 1);
+ int index = zis->readU8();
+ int len = 1;
+ if (index & 128) {
+ int b;
+ do {
+ zlibHasData(zis, 1);
+ b = zis->readU8();
+ len += b;
+ } while (b == 255);
+
+ if (end - ptr < len) {
+ throw Exception ("ZRLE decode error");
+ }
+ }
+
+ index &= 127;
+
+ T pix = palette[index];
+
+ while (len-- > 0) *ptr++ = pix;
+ }
}
}
- zrleDecode32(r, &is, &zis, pf, pb);
- break;
+ pb->imageRect(pf, t, buf);
}
}
+
+ zis->flushUnderlying();
+ zis->setUnderlying(NULL, 0);
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2014-2022 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
namespace rfb {
+ class PixelFormat;
+
class ZRLEDecoder : public Decoder {
public:
ZRLEDecoder();
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
+
+ private:
+ template<class T>
+ void zrleDecode(const Rect& r, rdr::InStream* is,
+ rdr::ZlibInStream* zis,
+ const PixelFormat& pf, ModifiablePixelBuffer* pb);
+
private:
rdr::ZlibInStream zis;
};
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
}
}
-//
-// Including BPP-dependent implementation of the encoder.
-//
-
-#define BPP 8
-#include <rfb/ZRLEEncoderBPP.cxx>
-#undef BPP
-#define BPP 16
-#include <rfb/ZRLEEncoderBPP.cxx>
-#undef BPP
-#define BPP 32
-#include <rfb/ZRLEEncoderBPP.cxx>
-#undef BPP
+template<class T>
+void ZRLEEncoder::writePaletteTile(int width, int height,
+ const T* buffer, int stride,
+ const PixelFormat& pf,
+ const Palette& palette)
+{
+ const int bitsPerPackedPixel[] = {
+ 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+ };
+
+ int bppp;
+ int pad;
+
+ assert(palette.size() > 1);
+ assert(palette.size() <= 16);
+
+ zos.writeU8(palette.size());
+ writePalette(pf, palette);
+
+ bppp = bitsPerPackedPixel[palette.size()-1];
+ pad = stride - width;
+
+ for (int i = 0; i < height; i++) {
+ int w;
+
+ rdr::U8 nbits = 0;
+ rdr::U8 byte = 0;
+
+ w = width;
+ while (w--) {
+ T pix = *buffer++;
+ rdr::U8 index = palette.lookup(pix);
+ byte = (byte << bppp) | index;
+ nbits += bppp;
+ if (nbits >= 8) {
+ zos.writeU8(byte);
+ nbits = 0;
+ }
+ }
+ if (nbits > 0) {
+ byte <<= 8 - nbits;
+ zos.writeU8(byte);
+ }
+
+ buffer += pad;
+ }
+}
+
+template<class T>
+void ZRLEEncoder::writePaletteRLETile(int width, int height,
+ const T* buffer, int stride,
+ const PixelFormat& pf,
+ const Palette& palette)
+{
+ int pad;
+
+ T prevColour;
+ int runLength;
+
+ assert(palette.size() > 1);
+ assert(palette.size() <= 127);
+
+ zos.writeU8(palette.size() | 0x80);
+ writePalette(pf, palette);
+
+ pad = stride - width;
+
+ prevColour = *buffer;
+ runLength = 0;
+
+ while (height--) {
+ int w = width;
+ while (w--) {
+ if (prevColour != *buffer) {
+ if (runLength == 1)
+ zos.writeU8(palette.lookup(prevColour));
+ else {
+ zos.writeU8(palette.lookup(prevColour) | 0x80);
+
+ while (runLength > 255) {
+ zos.writeU8(255);
+ runLength -= 255;
+ }
+ zos.writeU8(runLength - 1);
+ }
+
+ prevColour = *buffer;
+ runLength = 0;
+ }
+
+ runLength++;
+ buffer++;
+ }
+ buffer += pad;
+ }
+ if (runLength == 1)
+ zos.writeU8(palette.lookup(prevColour));
+ else {
+ zos.writeU8(palette.lookup(prevColour) | 0x80);
+
+ while (runLength > 255) {
+ zos.writeU8(255);
+ runLength -= 255;
+ }
+ zos.writeU8(runLength - 1);
+ }
+}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2022 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
unsigned int count);
protected:
- // Preprocessor generated, optimised methods
-
- void writePaletteTile(int width, int height,
- const rdr::U8* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
- void writePaletteTile(int width, int height,
- const rdr::U16* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
+ // Templated, optimised methods
+ template<class T>
void writePaletteTile(int width, int height,
- const rdr::U32* buffer, int stride,
+ const T* buffer, int stride,
const PixelFormat& pf, const Palette& palette);
-
- void writePaletteRLETile(int width, int height,
- const rdr::U8* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
- void writePaletteRLETile(int width, int height,
- const rdr::U16* buffer, int stride,
- const PixelFormat& pf, const Palette& palette);
+ template<class T>
void writePaletteRLETile(int width, int height,
- const rdr::U32* buffer, int stride,
+ const T* buffer, int stride,
const PixelFormat& pf, const Palette& palette);
protected:
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-
-#define UBPP CONCAT2E(U,BPP)
-
-void ZRLEEncoder::writePaletteTile(int width, int height,
- const rdr::UBPP* buffer, int stride,
- const PixelFormat& pf,
- const Palette& palette)
-{
- const int bitsPerPackedPixel[] = {
- 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
- };
-
- int bppp;
- int pad;
-
- assert(palette.size() > 1);
- assert(palette.size() <= 16);
-
- zos.writeU8(palette.size());
- writePalette(pf, palette);
-
- bppp = bitsPerPackedPixel[palette.size()-1];
- pad = stride - width;
-
- for (int i = 0; i < height; i++) {
- int w;
-
- rdr::U8 nbits = 0;
- rdr::U8 byte = 0;
-
- w = width;
- while (w--) {
- rdr::UBPP pix = *buffer++;
- rdr::U8 index = palette.lookup(pix);
- byte = (byte << bppp) | index;
- nbits += bppp;
- if (nbits >= 8) {
- zos.writeU8(byte);
- nbits = 0;
- }
- }
- if (nbits > 0) {
- byte <<= 8 - nbits;
- zos.writeU8(byte);
- }
-
- buffer += pad;
- }
-}
-
-void ZRLEEncoder::writePaletteRLETile(int width, int height,
- const rdr::UBPP* buffer, int stride,
- const PixelFormat& pf,
- const Palette& palette)
-{
- int pad;
-
- rdr::UBPP prevColour;
- int runLength;
-
- assert(palette.size() > 1);
- assert(palette.size() <= 127);
-
- zos.writeU8(palette.size() | 0x80);
- writePalette(pf, palette);
-
- pad = stride - width;
-
- prevColour = *buffer;
- runLength = 0;
-
- while (height--) {
- int w = width;
- while (w--) {
- if (prevColour != *buffer) {
- if (runLength == 1)
- zos.writeU8(palette.lookup(prevColour));
- else {
- zos.writeU8(palette.lookup(prevColour) | 0x80);
-
- while (runLength > 255) {
- zos.writeU8(255);
- runLength -= 255;
- }
- zos.writeU8(runLength - 1);
- }
-
- prevColour = *buffer;
- runLength = 0;
- }
-
- runLength++;
- buffer++;
- }
- buffer += pad;
- }
- if (runLength == 1)
- zos.writeU8(palette.lookup(prevColour));
- else {
- zos.writeU8(palette.lookup(prevColour) | 0x80);
-
- while (runLength > 255) {
- zos.writeU8(255);
- runLength -= 255;
- }
- zos.writeU8(runLength - 1);
- }
-}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-//
-// Hextile decoding function.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-
-#include <rdr/InStream.h>
-#include <rfb/Exception.h>
-#include <rfb/hextileConstants.h>
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define READ_PIXEL CONCAT2E(readOpaque,BPP)
-#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP)
-
-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];
-
- 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) {
-
- t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
-
- int tileType = is->readU8();
-
- if (tileType & hextileRaw) {
- is->readBytes(buf, t.area() * (BPP/8));
- pb->imageRect(pf, t, buf);
- continue;
- }
-
- if (tileType & hextileBgSpecified)
- bg = is->READ_PIXEL();
-
- int len = t.area();
- PIXEL_T* ptr = buf;
- while (len-- > 0) *ptr++ = bg;
-
- if (tileType & hextileFgSpecified)
- fg = is->READ_PIXEL();
-
- if (tileType & hextileAnySubrects) {
- int nSubrects = is->readU8();
-
- for (int i = 0; i < nSubrects; i++) {
-
- if (tileType & hextileSubrectsColoured)
- fg = is->READ_PIXEL();
-
- int xy = is->readU8();
- int wh = is->readU8();
-
- int x = ((xy >> 4) & 15);
- int y = (xy & 15);
- int w = ((wh >> 4) & 15) + 1;
- int h = (wh & 15) + 1;
- if (x + w > 16 || y + h > 16) {
- throw rfb::Exception("HEXTILE_DECODE: Hextile out of bounds");
- }
- PIXEL_T* ptr = buf + y * t.width() + x;
- int rowAdd = t.width() - w;
- while (h-- > 0) {
- int len = w;
- while (len-- > 0) *ptr++ = fg;
- ptr += rowAdd;
- }
- }
- }
- pb->imageRect(pf, t, buf);
- }
- }
-}
-
-#undef PIXEL_T
-#undef READ_PIXEL
-#undef HEXTILE_DECODE
-}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2005 Constantin Kaplinsky. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-//
-// Hextile encoding function.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-
-#include <rdr/OutStream.h>
-#include <rfb/hextileConstants.h>
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
-#define HEXTILE_ENCODE CONCAT2E(hextileEncode,BPP)
-#define HEXTILE_ENCODE_TILE CONCAT2E(hextileEncodeTile,BPP)
-#define TEST_TILE_TYPE CONCAT2E(hextileTestTileType,BPP)
-
-int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg);
-int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
- rdr::U8* encoded, PIXEL_T bg);
-
-void HEXTILE_ENCODE(rdr::OutStream* os, const PixelBuffer* pb)
-{
- Rect t;
- PIXEL_T buf[256];
- PIXEL_T oldBg = 0, oldFg = 0;
- bool oldBgValid = false;
- bool oldFgValid = false;
- rdr::U8 encoded[256*(BPP/8)];
-
- for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
-
- t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
-
- for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
-
- t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
-
- pb->getImage(buf, t);
-
- PIXEL_T bg = 0, fg = 0;
- int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg);
-
- if (!oldBgValid || oldBg != bg) {
- tileType |= hextileBgSpecified;
- oldBg = bg;
- oldBgValid = true;
- }
-
- int encodedLen = 0;
-
- if (tileType & hextileAnySubrects) {
-
- if (tileType & hextileSubrectsColoured) {
- oldFgValid = false;
- } else {
- if (!oldFgValid || oldFg != fg) {
- tileType |= hextileFgSpecified;
- oldFg = fg;
- oldFgValid = true;
- }
- }
-
- encodedLen = HEXTILE_ENCODE_TILE(buf, t.width(), t.height(), tileType,
- encoded, bg);
-
- if (encodedLen < 0) {
- pb->getImage(buf, t);
- os->writeU8(hextileRaw);
- os->writeBytes(buf, t.width() * t.height() * (BPP/8));
- oldBgValid = oldFgValid = false;
- continue;
- }
- }
-
- os->writeU8(tileType);
- if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
- if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
- if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
- }
- }
-}
-
-
-int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
- rdr::U8* encoded, PIXEL_T bg)
-{
- rdr::U8* nSubrectsPtr = encoded;
- *nSubrectsPtr = 0;
- encoded++;
-
- for (int y = 0; y < h; y++)
- {
- int x = 0;
- while (x < w) {
- if (*data == bg) {
- x++;
- data++;
- continue;
- }
-
- // Find horizontal subrect first
- PIXEL_T* ptr = data+1;
- PIXEL_T* eol = data+w-x;
- while (ptr < eol && *ptr == *data) ptr++;
- int sw = ptr - data;
-
- ptr = data + w;
- int sh = 1;
- while (sh < h-y) {
- eol = ptr + sw;
- while (ptr < eol)
- if (*ptr++ != *data) goto endOfSubrect;
- ptr += w - sw;
- sh++;
- }
- endOfSubrect:
-
- (*nSubrectsPtr)++;
-
- if (tileType & hextileSubrectsColoured) {
- if (encoded - nSubrectsPtr + (BPP/8) > w*h*(BPP/8)) return -1;
-#if (BPP == 8)
- *encoded++ = *data;
-#elif (BPP == 16)
- *encoded++ = ((rdr::U8*)data)[0];
- *encoded++ = ((rdr::U8*)data)[1];
-#elif (BPP == 32)
- *encoded++ = ((rdr::U8*)data)[0];
- *encoded++ = ((rdr::U8*)data)[1];
- *encoded++ = ((rdr::U8*)data)[2];
- *encoded++ = ((rdr::U8*)data)[3];
-#endif
- }
-
- if (encoded - nSubrectsPtr + 2 > w*h*(BPP/8)) return -1;
- *encoded++ = (x << 4) | y;
- *encoded++ = ((sw-1) << 4) | (sh-1);
-
- ptr = data+w;
- PIXEL_T* eor = data+w*sh;
- while (ptr < eor) {
- eol = ptr + sw;
- while (ptr < eol) *ptr++ = bg;
- ptr += w - sw;
- }
- x += sw;
- data += sw;
- }
- }
- return encoded - nSubrectsPtr;
-}
-
-
-int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg)
-{
- PIXEL_T pix1 = *data;
- PIXEL_T* end = data + w * h;
-
- PIXEL_T* ptr = data + 1;
- while (ptr < end && *ptr == pix1)
- ptr++;
-
- if (ptr == end) {
- *bg = pix1;
- return 0; // solid-color tile
- }
-
- int count1 = ptr - data;
- int count2 = 1;
- PIXEL_T pix2 = *ptr++;
- int tileType = hextileAnySubrects;
-
- for (; ptr < end; ptr++) {
- if (*ptr == pix1) {
- count1++;
- } else if (*ptr == pix2) {
- count2++;
- } else {
- tileType |= hextileSubrectsColoured;
- break;
- }
- }
-
- if (count1 >= count2) {
- *bg = pix1; *fg = pix2;
- } else {
- *bg = pix2; *fg = pix1;
- }
- return tileType;
-}
-
-#undef PIXEL_T
-#undef WRITE_PIXEL
-#undef HEXTILE_ENCODE
-#undef HEXTILE_ENCODE_TILE
-#undef TEST_TILE_TYPE
-}
+++ /dev/null
-/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2005 Constantin Kaplinsky. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-//
-// Hextile encoding function.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-
-#include <rdr/OutStream.h>
-#include <rfb/hextileConstants.h>
-#include <rfb/Palette.h>
-
-#include <assert.h>
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
-#define HEXTILE_TILE CONCAT2E(HextileTile,BPP)
-#define HEXTILE_ENCODE CONCAT2E(hextileEncodeBetter,BPP)
-
-//
-// This class analyzes a separate tile and encodes its subrectangles.
-//
-
-class HEXTILE_TILE {
-
- public:
-
- HEXTILE_TILE ();
-
- //
- // Initialize existing object instance with new tile data.
- //
- void newTile(const PIXEL_T *src, int w, int h);
-
- //
- // Flags can include: hextileRaw, hextileAnySubrects and
- // hextileSubrectsColoured. Note that if hextileRaw is set, other
- // flags make no sense. Also, hextileSubrectsColoured is meaningful
- // only when hextileAnySubrects is set as well.
- //
- int getFlags() const { return m_flags; }
-
- //
- // Returns the size of encoded subrects data, including subrect count.
- // The size is zero if flags do not include hextileAnySubrects.
- //
- int getSize() const { return m_size; }
-
- //
- // Return optimal background.
- //
- int getBackground() const { return m_background; }
-
- //
- // Return foreground if flags include hextileSubrectsColoured.
- //
- int getForeground() const { return m_foreground; }
-
- //
- // Encode subrects. This function may be called only if
- // hextileAnySubrects bit is set in flags. The buffer size should be
- // big enough to store at least the number of bytes returned by the
- // getSize() method.
- //
- void encode(rdr::U8* dst) const;
-
- protected:
-
- //
- // Analyze the tile pixels, fill in all the data fields.
- //
- void analyze();
-
- const PIXEL_T *m_tile;
- int m_width;
- int m_height;
-
- int m_size;
- int m_flags;
- PIXEL_T m_background;
- PIXEL_T m_foreground;
-
- int m_numSubrects;
- rdr::U8 m_coords[256 * 2];
- PIXEL_T m_colors[256];
-
- private:
-
- bool m_processed[16][16];
- Palette m_pal;
-};
-
-HEXTILE_TILE::HEXTILE_TILE()
- : m_tile(NULL), m_width(0), m_height(0),
- m_size(0), m_flags(0), m_background(0), m_foreground(0),
- m_numSubrects(0)
-{
-}
-
-void HEXTILE_TILE::newTile(const PIXEL_T *src, int w, int h)
-{
- m_tile = src;
- m_width = w;
- m_height = h;
-
- analyze();
-}
-
-void HEXTILE_TILE::analyze()
-{
- assert(m_tile && m_width && m_height);
-
- const PIXEL_T *ptr = m_tile;
- const PIXEL_T *end = &m_tile[m_width * m_height];
- PIXEL_T color = *ptr++;
- while (ptr != end && *ptr == color)
- ptr++;
-
- // Handle solid tile
- if (ptr == end) {
- m_background = m_tile[0];
- m_flags = 0;
- m_size = 0;
- return;
- }
-
- // Compute number of complete rows of the same color, at the top
- int y = (ptr - m_tile) / m_width;
-
- PIXEL_T *colorsPtr = m_colors;
- rdr::U8 *coordsPtr = m_coords;
- m_pal.clear();
- m_numSubrects = 0;
-
- // Have we found the first subrect already?
- if (y > 0) {
- *colorsPtr++ = color;
- *coordsPtr++ = 0;
- *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F));
- m_pal.insert(color, 1);
- m_numSubrects++;
- }
-
- memset(m_processed, 0, 16 * 16 * sizeof(bool));
-
- int x, sx, sy, sw, sh, max_x;
-
- for (; y < m_height; y++) {
- for (x = 0; x < m_width; x++) {
- // Skip pixels that were processed earlier
- if (m_processed[y][x]) {
- continue;
- }
- // Determine dimensions of the horizontal subrect
- color = m_tile[y * m_width + x];
- for (sx = x + 1; sx < m_width; sx++) {
- if (m_tile[y * m_width + sx] != color)
- break;
- }
- sw = sx - x;
- max_x = sx;
- for (sy = y + 1; sy < m_height; sy++) {
- for (sx = x; sx < max_x; sx++) {
- if (m_tile[sy * m_width + sx] != color)
- goto done;
- }
- }
- done:
- sh = sy - y;
-
- // Save properties of this subrect
- *colorsPtr++ = color;
- *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F));
- *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F));
-
- if (!m_pal.insert(color, 1) || (m_pal.size() > (48 + 2 * BPP))) {
- // Handle palette overflow
- m_flags = hextileRaw;
- m_size = 0;
- return;
- }
-
- m_numSubrects++;
-
- // Mark pixels of this subrect as processed, below this row
- for (sy = y + 1; sy < y + sh; sy++) {
- for (sx = x; sx < x + sw; sx++)
- m_processed[sy][sx] = true;
- }
-
- // Skip processed pixels of this row
- x += (sw - 1);
- }
- }
-
- // Save number of colors in this tile (should be no less than 2)
- int numColors = m_pal.size();
- assert(numColors >= 2);
-
- m_background = (PIXEL_T)m_pal.getColour(0);
- m_flags = hextileAnySubrects;
- int numSubrects = m_numSubrects - m_pal.getCount(0);
-
- if (numColors == 2) {
- // Monochrome tile
- m_foreground = (PIXEL_T)m_pal.getColour(1);
- m_size = 1 + 2 * numSubrects;
- } else {
- // Colored tile
- m_flags |= hextileSubrectsColoured;
- m_size = 1 + (2 + (BPP/8)) * numSubrects;
- }
-}
-
-void HEXTILE_TILE::encode(rdr::U8 *dst) const
-{
- assert(m_numSubrects && (m_flags & hextileAnySubrects));
-
- // Zero subrects counter
- rdr::U8 *numSubrectsPtr = dst;
- *dst++ = 0;
-
- for (int i = 0; i < m_numSubrects; i++) {
- if (m_colors[i] == m_background)
- continue;
-
- if (m_flags & hextileSubrectsColoured) {
-#if (BPP == 8)
- *dst++ = m_colors[i];
-#elif (BPP == 16)
- *dst++ = ((rdr::U8*)&m_colors[i])[0];
- *dst++ = ((rdr::U8*)&m_colors[i])[1];
-#elif (BPP == 32)
- *dst++ = ((rdr::U8*)&m_colors[i])[0];
- *dst++ = ((rdr::U8*)&m_colors[i])[1];
- *dst++ = ((rdr::U8*)&m_colors[i])[2];
- *dst++ = ((rdr::U8*)&m_colors[i])[3];
-#endif
- }
- *dst++ = m_coords[i * 2];
- *dst++ = m_coords[i * 2 + 1];
-
- (*numSubrectsPtr)++;
- }
-
- assert(dst - numSubrectsPtr == m_size);
-}
-
-//
-// Main encoding function.
-//
-
-void HEXTILE_ENCODE(rdr::OutStream* os, const PixelBuffer* pb)
-{
- Rect t;
- PIXEL_T buf[256];
- PIXEL_T oldBg = 0, oldFg = 0;
- bool oldBgValid = false;
- bool oldFgValid = false;
- rdr::U8 encoded[256*(BPP/8)];
-
- HEXTILE_TILE tile;
-
- for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
-
- t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
-
- for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
-
- t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
-
- pb->getImage(buf, t);
-
- tile.newTile(buf, t.width(), t.height());
- int tileType = tile.getFlags();
- int encodedLen = tile.getSize();
-
- if ( (tileType & hextileRaw) != 0 ||
- encodedLen >= t.width() * t.height() * (BPP/8)) {
- os->writeU8(hextileRaw);
- os->writeBytes(buf, t.width() * t.height() * (BPP/8));
- oldBgValid = oldFgValid = false;
- continue;
- }
-
- PIXEL_T bg = tile.getBackground();
- PIXEL_T fg = 0;
-
- if (!oldBgValid || oldBg != bg) {
- tileType |= hextileBgSpecified;
- oldBg = bg;
- oldBgValid = true;
- }
-
- if (tileType & hextileAnySubrects) {
- if (tileType & hextileSubrectsColoured) {
- oldFgValid = false;
- } else {
- fg = tile.getForeground();
- if (!oldFgValid || oldFg != fg) {
- tileType |= hextileFgSpecified;
- oldFg = fg;
- oldFgValid = true;
- }
- }
- tile.encode(encoded);
- }
-
- os->writeU8(tileType);
- if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
- if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
- if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
- }
- }
-}
-
-#undef PIXEL_T
-#undef WRITE_PIXEL
-#undef HEXTILE_TILE
-#undef HEXTILE_ENCODE
-}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-//
-// RRE decoding function.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-
-#include <rdr/InStream.h>
-#include <rfb/Exception.h>
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define READ_PIXEL CONCAT2E(readOpaque,BPP)
-#define RRE_DECODE CONCAT2E(rreDecode,BPP)
-
-void RRE_DECODE (const Rect& r, rdr::InStream* is,
- const PixelFormat& pf, ModifiablePixelBuffer* pb)
-{
- int nSubrects = is->readU32();
- PIXEL_T bg = is->READ_PIXEL();
- pb->fillRect(pf, r, &bg);
-
- for (int i = 0; i < nSubrects; i++) {
- PIXEL_T pix = is->READ_PIXEL();
- int x = is->readU16();
- int y = is->readU16();
- int w = is->readU16();
- int h = is->readU16();
-
- if (((x+w) > r.width()) || ((y+h) > r.height()))
- throw Exception ("RRE decode error");
-
- pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), &pix);
- }
-}
-
-#undef PIXEL_T
-#undef READ_PIXEL
-#undef RRE_DECODE
-}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-//
-// RRE encoding function.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-//
-// The data argument to RRE_ENCODE contains the pixel data, and it writes the
-// encoded version to the given OutStream. If the encoded version exceeds w*h
-// it aborts and returns -1, otherwise it returns the number of subrectangles.
-//
-
-#include <rdr/OutStream.h>
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
-#define RRE_ENCODE CONCAT2E(rreEncode,BPP)
-
-int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg)
-{
- os->WRITE_PIXEL(bg);
-
- int nSubrects = 0;
-
- for (int y = 0; y < h; y++)
- {
- int x = 0;
- while (x < w) {
- if (*data == bg) {
- x++;
- data++;
- continue;
- }
-
- // Find horizontal subrect first
- PIXEL_T* ptr = data+1;
- PIXEL_T* eol = data+w-x;
- while (ptr < eol && *ptr == *data) ptr++;
- int sw = ptr - data;
-
- ptr = data + w;
- int sh = 1;
- while (sh < h-y) {
- eol = ptr + sw;
- while (ptr < eol)
- if (*ptr++ != *data) goto endOfHorizSubrect;
- ptr += w - sw;
- sh++;
- }
- endOfHorizSubrect:
-
- // Find vertical subrect
- int vh;
- for (vh = sh; vh < h-y; vh++)
- if (data[vh*w] != *data) break;
-
- if (vh != sh) {
- ptr = data+1;
- int vw;
- for (vw = 1; vw < sw; vw++) {
- for (int i = 0; i < vh; i++)
- if (ptr[i*w] != *data) goto endOfVertSubrect;
- ptr++;
- }
- endOfVertSubrect:
-
- // If vertical subrect bigger than horizontal then use that.
- if (sw*sh < vw*vh) {
- sw = vw;
- sh = vh;
- }
- }
-
- nSubrects++;
- os->WRITE_PIXEL(*data);
- os->writeU16(x);
- os->writeU16(y);
- os->writeU16(sw);
- os->writeU16(sh);
-
- ptr = data+w;
- PIXEL_T* eor = data+w*sh;
- while (ptr < eor) {
- eol = ptr + sw;
- while (ptr < eol) *ptr++ = bg;
- ptr += w - sw;
- }
- x += sw;
- data += sw;
- }
- }
-
- return nSubrects;
-}
-
-#undef PIXEL_T
-#undef WRITE_PIXEL
-#undef RRE_ENCODE
-}
+++ /dev/null
-/* 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
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-//
-// Tight decoding functions.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-
-#if BPP == 32
-
-void
-TightDecoder::FilterGradient24(const rdr::U8 *inbuf,
- const PixelFormat& pf, PIXEL_T* outbuf,
- int stride, const Rect& r)
-{
- int x, y, c;
- rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
- rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
- rdr::U8 pix[3];
- int est[3];
-
- memset(prevRow, 0, sizeof(prevRow));
-
- // Set up shortcut variables
- int rectHeight = r.height();
- int rectWidth = r.width();
-
- for (y = 0; y < rectHeight; y++) {
- for (x = 0; x < rectWidth; x++) {
- /* First pixel in a row */
- if (x == 0) {
- for (c = 0; c < 3; c++) {
- pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c];
- thisRow[c] = pix[c];
- }
- pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
- continue;
- }
-
- for (c = 0; c < 3; c++) {
- est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
- if (est[c] > 0xff) {
- est[c] = 0xff;
- } else if (est[c] < 0) {
- est[c] = 0;
- }
- pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c];
- thisRow[x*3+c] = pix[c];
- }
- pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
- }
-
- memcpy(prevRow, thisRow, sizeof(prevRow));
- }
-}
-
-#endif
-
-#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*3];
- static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
- rdr::U8 pix[3];
- int est[3];
-
- memset(prevRow, 0, sizeof(prevRow));
-
- // Set up shortcut variables
- int rectHeight = r.height();
- int rectWidth = r.width();
-
- for (y = 0; y < rectHeight; y++) {
- for (x = 0; x < rectWidth; x++) {
- /* First pixel in a row */
- if (x == 0) {
- pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1);
- for (c = 0; c < 3; c++)
- pix[c] += prevRow[c];
-
- memcpy(thisRow, pix, sizeof(pix));
-
- pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
-
- continue;
- }
-
- for (c = 0; c < 3; c++) {
- est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
- if (est[c] > 255) {
- est[c] = 255;
- } else if (est[c] < 0) {
- est[c] = 0;
- }
- }
-
- 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));
-
- pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
- }
-
- memcpy(prevRow, thisRow, sizeof(prevRow));
- }
-}
-
-#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
-}
+++ /dev/null
-/* Copyright (C) 2002-2005 RealVNC Ltd. 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-//
-// ZRLE decoding function.
-//
-// This file is #included after having set the following macro:
-// BPP - 8, 16 or 32
-
-namespace rfb {
-
-// CONCAT2E concatenates its arguments, expanding them if they are macros
-
-#ifndef CONCAT2E
-#define CONCAT2(a,b) a##b
-#define CONCAT2E(a,b) CONCAT2(a,b)
-#endif
-
-#ifdef CPIXEL
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define READ_PIXEL(is) CONCAT2E(readOpaque,CPIXEL)(is)
-#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL)
-#else
-#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define READ_PIXEL(is) is->CONCAT2E(readOpaque,BPP)()
-#define ZRLE_DECODE CONCAT2E(zrleDecode,BPP)
-#endif
-
-void ZRLE_DECODE (const Rect& r, rdr::InStream* is,
- rdr::ZlibInStream* zis,
- const PixelFormat& pf, ModifiablePixelBuffer* pb)
-{
- int length = is->readU32();
- zis->setUnderlying(is, length);
- Rect t;
- PIXEL_T buf[64 * 64];
-
- for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
-
- t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
-
- for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
-
- t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
-
- zlibHasData(zis, 1);
- int mode = zis->readU8();
- bool rle = mode & 128;
- int palSize = mode & 127;
- PIXEL_T palette[128];
-
-#ifdef CPIXEL
- zlibHasData(zis, 3 * palSize);
-#else
- zlibHasData(zis, BPP/8 * palSize);
-#endif
- for (int i = 0; i < palSize; i++) {
- palette[i] = READ_PIXEL(zis);
- }
-
- if (palSize == 1) {
- PIXEL_T pix = palette[0];
- pb->fillRect(pf, t, &pix);
- continue;
- }
-
- if (!rle) {
- if (palSize == 0) {
-
- // raw
-
-#ifdef CPIXEL
- zlibHasData(zis, 3 * t.area());
- for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) {
- *ptr = READ_PIXEL(zis);
- }
-#else
- zlibHasData(zis, BPP/8 * t.area());
- zis->readBytes(buf, t.area() * (BPP / 8));
-#endif
-
- } else {
-
- // packed pixels
- int bppp = ((palSize > 16) ? 8 :
- ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
-
- PIXEL_T* ptr = buf;
-
- for (int i = 0; i < t.height(); i++) {
- PIXEL_T* eol = ptr + t.width();
- rdr::U8 byte = 0;
- rdr::U8 nbits = 0;
-
- while (ptr < eol) {
- if (nbits == 0) {
- zlibHasData(zis, 1);
- byte = zis->readU8();
- nbits = 8;
- }
- nbits -= bppp;
- rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
- *ptr++ = palette[index];
- }
- }
- }
-
- } else {
-
- if (palSize == 0) {
-
- // plain RLE
-
- PIXEL_T* ptr = buf;
- PIXEL_T* end = ptr + t.area();
- while (ptr < end) {
-#ifdef CPIXEL
- zlibHasData(zis, 3);
-#else
- zlibHasData(zis, BPP/8);
-#endif
- PIXEL_T pix = READ_PIXEL(zis);
- int len = 1;
- int b;
- do {
- zlibHasData(zis, 1);
- b = zis->readU8();
- len += b;
- } while (b == 255);
-
- if (end - ptr < len) {
- throw Exception ("ZRLE decode error");
- }
-
- while (len-- > 0) *ptr++ = pix;
-
- }
- } else {
-
- // palette RLE
-
- PIXEL_T* ptr = buf;
- PIXEL_T* end = ptr + t.area();
- while (ptr < end) {
- zlibHasData(zis, 1);
- int index = zis->readU8();
- int len = 1;
- if (index & 128) {
- int b;
- do {
- zlibHasData(zis, 1);
- b = zis->readU8();
- len += b;
- } while (b == 255);
-
- if (end - ptr < len) {
- throw Exception ("ZRLE decode error");
- }
- }
-
- index &= 127;
-
- PIXEL_T pix = palette[index];
-
- while (len-- > 0) *ptr++ = pix;
- }
- }
- }
-
- pb->imageRect(pf, t, buf);
- }
- }
-
- zis->flushUnderlying();
- zis->setUnderlying(NULL, 0);
-}
-
-#undef ZRLE_DECODE
-#undef READ_PIXEL
-#undef PIXEL_T
-}