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