--- /dev/null
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Before including this file, you must define a number of CPP macros.
+ *
+ * BPP should be 8, 16 or 32 depending on the bits per pixel.
+ * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
+ * into the given buffer. EXTRA_ARGS can be defined to pass any other
+ * arguments needed by GET_IMAGE_INTO_BUF.
+ *
+ * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+ * bigger than the largest tile of pixel data, since the ZRLE encoding
+ * algorithm writes to the position one past the end of the pixel data.
+ */
+
+#include "zrleoutstream.h"
+#include "zrlepalettehelper.h"
+#include <assert.h>
+
+/* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same
+ but also expands its arguments if they are macros */
+
+#ifndef __RFB_CONCAT2E
+#define __RFB_CONCAT2(a,b) a##b
+#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
+#endif
+
+#ifndef __RFB_CONCAT3E
+#define __RFB_CONCAT3(a,b,c) a##b##c
+#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
+#endif
+
+#undef END_FIX
+#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
+# define END_FIX LE
+#elif ZYWRLE_ENDIAN == ENDIAN_BIG
+# define END_FIX BE
+#else
+# define END_FIX NE
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
+#define BPPOUT 24
+#elif BPP==15
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
+#define BPPOUT 16
+#else
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
+#define BPPOUT BPP
+#endif
+
+#ifndef ZRLE_ONCE
+#define ZRLE_ONCE
+
+static const int bitsPerPackedPixel[] = {
+ 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+static zrlePaletteHelper paletteHelper;
+
+#endif /* ZRLE_ONCE */
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
+ int zywrle_level, int *zywrleBuf);
+
+#if BPP!=8
+#define ZYWRLE_ENCODE
+#include "zywrletemplate.c"
+#endif
+
+static void ZRLE_ENCODE (int x, int y, int w, int h,
+ zrleOutStream* os, void* buf
+ EXTRA_ARGS
+ )
+{
+ int ty;
+ for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
+ int tx, th = rfbZRLETileHeight;
+ if (th > y+h-ty) th = y+h-ty;
+ for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
+ int tw = rfbZRLETileWidth;
+ if (tw > x+w-tx) tw = x+w-tx;
+
+ GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
+
+ ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
+ cl->zywrleLevel, cl->zywrleBuf);
+ }
+ }
+ zrleOutStreamFlush(os);
+}
+
+
+void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
+ int zywrle_level, int *zywrleBuf)
+{
+ /* First find the palette and the number of runs */
+
+ zrlePaletteHelper *ph;
+
+ int runs = 0;
+ int singlePixels = 0;
+
+ rfbBool useRle;
+ rfbBool usePalette;
+
+ int estimatedBytes;
+ int plainRleBytes;
+ int i;
+
+ PIXEL_T* ptr = data;
+ PIXEL_T* end = ptr + h * w;
+ *end = ~*(end-1); /* one past the end is different so the while loop ends */
+
+ ph = &paletteHelper;
+ zrlePaletteHelperInit(ph);
+
+ while (ptr < end) {
+ PIXEL_T pix = *ptr;
+ if (*++ptr != pix) {
+ singlePixels++;
+ } else {
+ while (*++ptr == pix) ;
+ runs++;
+ }
+ zrlePaletteHelperInsert(ph, pix);
+ }
+
+ /* Solid tile is a special case */
+
+ if (ph->size == 1) {
+ zrleOutStreamWriteU8(os, 1);
+ zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
+ return;
+ }
+
+ /* Try to work out whether to use RLE and/or a palette. We do this by
+ estimating the number of bytes which will be generated and picking the
+ method which results in the fewest bytes. Of course this may not result
+ in the fewest bytes after compression... */
+
+ useRle = FALSE;
+ usePalette = FALSE;
+
+ estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
+
+#if BPP!=8
+ if (zywrle_level > 0 && !(zywrle_level & 0x80))
+ estimatedBytes >>= zywrle_level;
+#endif
+
+ plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
+
+ if (plainRleBytes < estimatedBytes) {
+ useRle = TRUE;
+ estimatedBytes = plainRleBytes;
+ }
+
+ if (ph->size < 128) {
+ int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
+
+ if (paletteRleBytes < estimatedBytes) {
+ useRle = TRUE;
+ usePalette = TRUE;
+ estimatedBytes = paletteRleBytes;
+ }
+
+ if (ph->size < 17) {
+ int packedBytes = ((BPPOUT/8) * ph->size +
+ w * h * bitsPerPackedPixel[ph->size-1] / 8);
+
+ if (packedBytes < estimatedBytes) {
+ useRle = FALSE;
+ usePalette = TRUE;
+ estimatedBytes = packedBytes;
+ }
+ }
+ }
+
+ if (!usePalette) ph->size = 0;
+
+ zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
+
+ for (i = 0; i < ph->size; i++) {
+ zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
+ }
+
+ if (useRle) {
+
+ PIXEL_T* ptr = data;
+ PIXEL_T* end = ptr + w * h;
+ PIXEL_T* runStart;
+ PIXEL_T pix;
+ while (ptr < end) {
+ int len;
+ runStart = ptr;
+ pix = *ptr++;
+ while (*ptr == pix && ptr < end)
+ ptr++;
+ len = ptr - runStart;
+ if (len <= 2 && usePalette) {
+ int index = zrlePaletteHelperLookup(ph, pix);
+ if (len == 2)
+ zrleOutStreamWriteU8(os, index);
+ zrleOutStreamWriteU8(os, index);
+ continue;
+ }
+ if (usePalette) {
+ int index = zrlePaletteHelperLookup(ph, pix);
+ zrleOutStreamWriteU8(os, index | 128);
+ } else {
+ zrleOutStreamWRITE_PIXEL(os, pix);
+ }
+ len -= 1;
+ while (len >= 255) {
+ zrleOutStreamWriteU8(os, 255);
+ len -= 255;
+ }
+ zrleOutStreamWriteU8(os, len);
+ }
+
+ } else {
+
+ /* no RLE */
+
+ if (usePalette) {
+ int bppp;
+ PIXEL_T* ptr = data;
+
+ /* packed pixels */
+
+ assert (ph->size < 17);
+
+ bppp = bitsPerPackedPixel[ph->size-1];
+
+ for (i = 0; i < h; i++) {
+ zrle_U8 nbits = 0;
+ zrle_U8 byte = 0;
+
+ PIXEL_T* eol = ptr + w;
+
+ while (ptr < eol) {
+ PIXEL_T pix = *ptr++;
+ zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
+ byte = (byte << bppp) | index;
+ nbits += bppp;
+ if (nbits >= 8) {
+ zrleOutStreamWriteU8(os, byte);
+ nbits = 0;
+ }
+ }
+ if (nbits > 0) {
+ byte <<= 8 - nbits;
+ zrleOutStreamWriteU8(os, byte);
+ }
+ }
+ } else {
+
+ /* raw */
+
+#if BPP!=8
+ if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
+ ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
+ ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf);
+ }
+ else
+#endif
+ {
+#ifdef CPIXEL
+ PIXEL_T *ptr;
+ for (ptr = data; ptr < data+w*h; ptr++)
+ zrleOutStreamWRITE_PIXEL(os, *ptr);
+#else
+ zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
+#endif
+ }
+ }
+ }
+}
+
+#undef PIXEL_T
+#undef zrleOutStreamWRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef ZYWRLE_ENCODE_TILE
+#undef BPPOUT