2
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
3
* Copyright (C) 2003 Sun Microsystems, Inc.
5
* This is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This software is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this software; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22
* Before including this file, you must define a number of CPP macros.
24
* BPP should be 8, 16 or 32 depending on the bits per pixel.
25
* GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
26
* into the given buffer. EXTRA_ARGS can be defined to pass any other
27
* arguments needed by GET_IMAGE_INTO_BUF.
29
* Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
30
* bigger than the largest tile of pixel data, since the ZRLE encoding
31
* algorithm writes to the position one past the end of the pixel data.
34
#include "zrleoutstream.h"
35
#include "zrlepalettehelper.h"
38
/* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same
39
but also expands its arguments if they are macros */
41
#ifndef __RFB_CONCAT2E
42
#define __RFB_CONCAT2(a,b) a##b
43
#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
46
#ifndef __RFB_CONCAT3E
47
#define __RFB_CONCAT3(a,b,c) a##b##c
48
#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
52
#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
54
#elif ZYWRLE_ENDIAN == ENDIAN_BIG
61
#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
62
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
63
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
64
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
67
#define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
68
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
69
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
70
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
73
#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
74
#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
75
#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
76
#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
83
static const int bitsPerPackedPixel[] = {
84
0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
87
static zrlePaletteHelper paletteHelper;
89
#endif /* ZRLE_ONCE */
91
void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
92
int zywrle_level, int *zywrleBuf);
96
#include "zywrletemplate.c"
99
static void ZRLE_ENCODE (int x, int y, int w, int h,
100
zrleOutStream* os, void* buf
105
for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
106
int tx, th = rfbZRLETileHeight;
107
if (th > y+h-ty) th = y+h-ty;
108
for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
109
int tw = rfbZRLETileWidth;
110
if (tw > x+w-tx) tw = x+w-tx;
112
GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
114
ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
115
cl->zywrleLevel, cl->zywrleBuf);
118
zrleOutStreamFlush(os);
122
void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
123
int zywrle_level, int *zywrleBuf)
125
/* First find the palette and the number of runs */
127
zrlePaletteHelper *ph;
130
int singlePixels = 0;
140
PIXEL_T* end = ptr + h * w;
141
*end = ~*(end-1); /* one past the end is different so the while loop ends */
144
zrlePaletteHelperInit(ph);
151
while (*++ptr == pix) ;
154
zrlePaletteHelperInsert(ph, pix);
157
/* Solid tile is a special case */
160
zrleOutStreamWriteU8(os, 1);
161
zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
165
/* Try to work out whether to use RLE and/or a palette. We do this by
166
estimating the number of bytes which will be generated and picking the
167
method which results in the fewest bytes. Of course this may not result
168
in the fewest bytes after compression... */
173
estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
176
if (zywrle_level > 0 && !(zywrle_level & 0x80))
177
estimatedBytes >>= zywrle_level;
180
plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
182
if (plainRleBytes < estimatedBytes) {
184
estimatedBytes = plainRleBytes;
187
if (ph->size < 128) {
188
int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
190
if (paletteRleBytes < estimatedBytes) {
193
estimatedBytes = paletteRleBytes;
197
int packedBytes = ((BPPOUT/8) * ph->size +
198
w * h * bitsPerPackedPixel[ph->size-1] / 8);
200
if (packedBytes < estimatedBytes) {
203
estimatedBytes = packedBytes;
208
if (!usePalette) ph->size = 0;
210
zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
212
for (i = 0; i < ph->size; i++) {
213
zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
219
PIXEL_T* end = ptr + w * h;
226
while (*ptr == pix && ptr < end)
228
len = ptr - runStart;
229
if (len <= 2 && usePalette) {
230
int index = zrlePaletteHelperLookup(ph, pix);
232
zrleOutStreamWriteU8(os, index);
233
zrleOutStreamWriteU8(os, index);
237
int index = zrlePaletteHelperLookup(ph, pix);
238
zrleOutStreamWriteU8(os, index | 128);
240
zrleOutStreamWRITE_PIXEL(os, pix);
244
zrleOutStreamWriteU8(os, 255);
247
zrleOutStreamWriteU8(os, len);
260
assert (ph->size < 17);
262
bppp = bitsPerPackedPixel[ph->size-1];
264
for (i = 0; i < h; i++) {
268
PIXEL_T* eol = ptr + w;
271
PIXEL_T pix = *ptr++;
272
zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
273
byte = (byte << bppp) | index;
276
zrleOutStreamWriteU8(os, byte);
282
zrleOutStreamWriteU8(os, byte);
290
if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
291
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
292
ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf);
299
for (ptr = data; ptr < data+w*h; ptr++)
300
zrleOutStreamWRITE_PIXEL(os, *ptr);
302
zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
310
#undef zrleOutStreamWRITE_PIXEL
312
#undef ZRLE_ENCODE_TILE
313
#undef ZYWRLE_ENCODE_TILE