1 /* 2 * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. 3 * Copyright (C) 2003 Sun Microsystems, Inc. 4 * 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. 9 * 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. 14 * 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, 18 * USA. 19 */ 20 21 /* 22 * Before including this file, you must define a number of CPP macros. 23 * 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. 28 * 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. 32 */ 33 34 #include "zrleoutstream.h" 35 #include "zrlepalettehelper.h" 36 #include <assert.h> 37 38 /* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same 39 but also expands its arguments if they are macros */ 40 41 #ifndef __RFB_CONCAT2E 42 #define __RFB_CONCAT2(a,b) a##b 43 #define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b) 44 #endif 45 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) 49 #endif 50 51 #undef END_FIX 52 #if ZYWRLE_ENDIAN == ENDIAN_LITTLE 53 # define END_FIX LE 54 #elif ZYWRLE_ENDIAN == ENDIAN_BIG 55 # define END_FIX BE 56 #else 57 # define END_FIX NE 58 #endif 59 60 #ifdef CPIXEL 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) 65 #define BPPOUT 24 66 #elif BPP==15 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) 71 #define BPPOUT 16 72 #else 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) 77 #define BPPOUT BPP 78 #endif 79 80 #ifndef ZRLE_ONCE 81 #define ZRLE_ONCE 82 83 static const int bitsPerPackedPixel[] = { 84 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 85 }; 86 87 #endif /* ZRLE_ONCE */ 88 89 void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os, 90 int zywrle_level, int *zywrleBuf, void *paletteHelper); 91 92 #if BPP!=8 93 #define ZYWRLE_ENCODE 94 #include "zywrletemplate.c" 95 #endif 96 97 static void ZRLE_ENCODE (int x, int y, int w, int h, 98 zrleOutStream* os, void* buf 99 EXTRA_ARGS 100 ) 101 { 102 int ty; 103 for (ty = y; ty < y+h; ty += rfbZRLETileHeight) { 104 int tx, th = rfbZRLETileHeight; 105 if (th > y+h-ty) th = y+h-ty; 106 for (tx = x; tx < x+w; tx += rfbZRLETileWidth) { 107 int tw = rfbZRLETileWidth; 108 if (tw > x+w-tx) tw = x+w-tx; 109 110 GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf); 111 112 if (cl->paletteHelper == NULL) { 113 cl->paletteHelper = (void *) calloc(sizeof(zrlePaletteHelper), 1); 114 } 115 116 ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os, 117 cl->zywrleLevel, cl->zywrleBuf, cl->paletteHelper); 118 } 119 } 120 zrleOutStreamFlush(os); 121 } 122 123 124 void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os, 125 int zywrle_level, int *zywrleBuf, void *paletteHelper) 126 { 127 /* First find the palette and the number of runs */ 128 129 zrlePaletteHelper *ph; 130 131 int runs = 0; 132 int singlePixels = 0; 133 134 rfbBool useRle; 135 rfbBool usePalette; 136 137 int estimatedBytes; 138 int plainRleBytes; 139 int i; 140 141 PIXEL_T* ptr = data; 142 PIXEL_T* end = ptr + h * w; 143 *end = ~*(end-1); /* one past the end is different so the while loop ends */ 144 145 ph = (zrlePaletteHelper *) paletteHelper; 146 zrlePaletteHelperInit(ph); 147 148 while (ptr < end) { 149 PIXEL_T pix = *ptr; 150 if (*++ptr != pix) { 151 singlePixels++; 152 } else { 153 while (*++ptr == pix) ; 154 runs++; 155 } 156 zrlePaletteHelperInsert(ph, pix); 157 } 158 159 /* Solid tile is a special case */ 160 161 if (ph->size == 1) { 162 zrleOutStreamWriteU8(os, 1); 163 zrleOutStreamWRITE_PIXEL(os, ph->palette[0]); 164 return; 165 } 166 167 /* Try to work out whether to use RLE and/or a palette. We do this by 168 estimating the number of bytes which will be generated and picking the 169 method which results in the fewest bytes. Of course this may not result 170 in the fewest bytes after compression... */ 171 172 useRle = FALSE; 173 usePalette = FALSE; 174 175 estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */ 176 177 #if BPP!=8 178 if (zywrle_level > 0 && !(zywrle_level & 0x80)) 179 estimatedBytes >>= zywrle_level; 180 #endif 181 182 plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels); 183 184 if (plainRleBytes < estimatedBytes) { 185 useRle = TRUE; 186 estimatedBytes = plainRleBytes; 187 } 188 189 if (ph->size < 128) { 190 int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels; 191 192 if (paletteRleBytes < estimatedBytes) { 193 useRle = TRUE; 194 usePalette = TRUE; 195 estimatedBytes = paletteRleBytes; 196 } 197 198 if (ph->size < 17) { 199 int packedBytes = ((BPPOUT/8) * ph->size + 200 w * h * bitsPerPackedPixel[ph->size-1] / 8); 201 202 if (packedBytes < estimatedBytes) { 203 useRle = FALSE; 204 usePalette = TRUE; 205 estimatedBytes = packedBytes; 206 } 207 } 208 } 209 210 if (!usePalette) ph->size = 0; 211 212 zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size); 213 214 for (i = 0; i < ph->size; i++) { 215 zrleOutStreamWRITE_PIXEL(os, ph->palette[i]); 216 } 217 218 if (useRle) { 219 220 PIXEL_T* ptr = data; 221 PIXEL_T* end = ptr + w * h; 222 PIXEL_T* runStart; 223 PIXEL_T pix; 224 while (ptr < end) { 225 int len; 226 runStart = ptr; 227 pix = *ptr++; 228 while (*ptr == pix && ptr < end) 229 ptr++; 230 len = ptr - runStart; 231 if (len <= 2 && usePalette) { 232 int index = zrlePaletteHelperLookup(ph, pix); 233 if (len == 2) 234 zrleOutStreamWriteU8(os, index); 235 zrleOutStreamWriteU8(os, index); 236 continue; 237 } 238 if (usePalette) { 239 int index = zrlePaletteHelperLookup(ph, pix); 240 zrleOutStreamWriteU8(os, index | 128); 241 } else { 242 zrleOutStreamWRITE_PIXEL(os, pix); 243 } 244 len -= 1; 245 while (len >= 255) { 246 zrleOutStreamWriteU8(os, 255); 247 len -= 255; 248 } 249 zrleOutStreamWriteU8(os, len); 250 } 251 252 } else { 253 254 /* no RLE */ 255 256 if (usePalette) { 257 int bppp; 258 PIXEL_T* ptr = data; 259 260 /* packed pixels */ 261 262 assert (ph->size < 17); 263 264 bppp = bitsPerPackedPixel[ph->size-1]; 265 266 for (i = 0; i < h; i++) { 267 zrle_U8 nbits = 0; 268 zrle_U8 byte = 0; 269 270 PIXEL_T* eol = ptr + w; 271 272 while (ptr < eol) { 273 PIXEL_T pix = *ptr++; 274 zrle_U8 index = zrlePaletteHelperLookup(ph, pix); 275 byte = (byte << bppp) | index; 276 nbits += bppp; 277 if (nbits >= 8) { 278 zrleOutStreamWriteU8(os, byte); 279 nbits = 0; 280 } 281 } 282 if (nbits > 0) { 283 byte <<= 8 - nbits; 284 zrleOutStreamWriteU8(os, byte); 285 } 286 } 287 } else { 288 289 /* raw */ 290 291 #if BPP!=8 292 if (zywrle_level > 0 && !(zywrle_level & 0x80)) { 293 ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf); 294 ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf, paletteHelper); 295 } 296 else 297 #endif 298 { 299 #ifdef CPIXEL 300 PIXEL_T *ptr; 301 for (ptr = data; ptr < data+w*h; ptr++) 302 zrleOutStreamWRITE_PIXEL(os, *ptr); 303 #else 304 zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8)); 305 #endif 306 } 307 } 308 } 309 } 310 311 #undef PIXEL_T 312 #undef zrleOutStreamWRITE_PIXEL 313 #undef ZRLE_ENCODE 314 #undef ZRLE_ENCODE_TILE 315 #undef ZYWRLE_ENCODE_TILE 316 #undef BPPOUT 317