[4] | 1 | /************************************************************************ |
---|
| 2 | * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. |
---|
| 3 | * |
---|
| 4 | * This is free software; you can redistribute it and/or modify |
---|
| 5 | * it under the terms of the GNU General Public License as published by |
---|
| 6 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 7 | * (at your option) any later version. |
---|
| 8 | * |
---|
| 9 | * This software is distributed in the hope that it will be useful, |
---|
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 12 | * GNU General Public License for more details. |
---|
| 13 | * |
---|
| 14 | * You should have received a copy of the GNU General Public License |
---|
| 15 | * along with this software; if not, write to the Free Software |
---|
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
---|
| 17 | * USA. |
---|
| 18 | */ |
---|
| 19 | |
---|
| 20 | /* |
---|
| 21 | * tight.c - handle ``tight'' encoding. |
---|
| 22 | * |
---|
| 23 | * This file shouldn't be compiled directly. It is included multiple |
---|
| 24 | * times by rfbproto.c, each time with a different definition of the |
---|
| 25 | * macro BPP. For each value of BPP, this file defines a function |
---|
| 26 | * which handles a tight-encoded rectangle with BPP bits per pixel. |
---|
| 27 | * |
---|
| 28 | */ |
---|
| 29 | |
---|
| 30 | #define TIGHT_MIN_TO_COMPRESS 12 |
---|
| 31 | |
---|
| 32 | #define CARDBPP CONCAT2E(CARD,BPP) |
---|
| 33 | #define filterPtrBPP CONCAT2E(filterPtr,BPP) |
---|
| 34 | |
---|
| 35 | #define HandleTightBPP CONCAT2E(HandleTight,BPP) |
---|
| 36 | #define ReceiveTightBPP CONCAT2E(ReceiveTight,BPP) |
---|
| 37 | #define flushTightBPP CONCAT2E(flushTight,BPP) |
---|
| 38 | #define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP) |
---|
| 39 | #define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP) |
---|
| 40 | #define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP) |
---|
| 41 | #define FilterCopyBPP CONCAT2E(FilterCopy,BPP) |
---|
| 42 | #define FilterPaletteBPP CONCAT2E(FilterPalette,BPP) |
---|
| 43 | #define FilterGradientBPP CONCAT2E(FilterGradient,BPP) |
---|
| 44 | |
---|
| 45 | #if BPP != 8 |
---|
| 46 | #define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP) |
---|
| 47 | #endif |
---|
| 48 | |
---|
| 49 | #ifndef RGB_TO_PIXEL |
---|
| 50 | |
---|
| 51 | #define RGB_TO_PIXEL(bpp,r,g,b) \ |
---|
| 52 | (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift | \ |
---|
| 53 | ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift | \ |
---|
| 54 | ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift) |
---|
| 55 | |
---|
| 56 | #define RGB24_TO_PIXEL(bpp,r,g,b) \ |
---|
| 57 | ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \ |
---|
| 58 | << myFormat.redShift | \ |
---|
| 59 | (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \ |
---|
| 60 | << myFormat.greenShift | \ |
---|
| 61 | (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \ |
---|
| 62 | << myFormat.blueShift) |
---|
| 63 | |
---|
| 64 | #define RGB24_TO_PIXEL32(r,g,b) \ |
---|
| 65 | (((CARD32)(r) & 0xFF) << myFormat.redShift | \ |
---|
| 66 | ((CARD32)(g) & 0xFF) << myFormat.greenShift | \ |
---|
| 67 | ((CARD32)(b) & 0xFF) << myFormat.blueShift) |
---|
| 68 | |
---|
| 69 | #endif |
---|
| 70 | |
---|
| 71 | /* Type declarations */ |
---|
| 72 | |
---|
| 73 | typedef void (VNCViewer::*filterPtrBPP)(int, CARDBPP *); |
---|
| 74 | |
---|
| 75 | /* Prototypes */ |
---|
| 76 | |
---|
| 77 | // static int InitFilterCopyBPP (int rw, int rh); |
---|
| 78 | // static int InitFilterPaletteBPP (int rw, int rh); |
---|
| 79 | // static int InitFilterGradientBPP (int rw, int rh); |
---|
| 80 | // static void FilterCopyBPP (int numRows, CARDBPP *destBuffer); |
---|
| 81 | // static void FilterPaletteBPP (int numRows, CARDBPP *destBuffer); |
---|
| 82 | // static void FilterGradientBPP (int numRows, CARDBPP *destBuffer); |
---|
| 83 | |
---|
| 84 | #define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP) |
---|
| 85 | #define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP) |
---|
| 86 | #define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP) |
---|
| 87 | #define FilterCopyBPP CONCAT2E(FilterCopy,BPP) |
---|
| 88 | #define FilterPaletteBPP CONCAT2E(FilterPalette,BPP) |
---|
| 89 | #define FilterGradientBPP CONCAT2E(FilterGradient,BPP) |
---|
| 90 | |
---|
| 91 | //static Bool DecompressJpegRectBPP(int x, int y, int w, int h); |
---|
| 92 | |
---|
| 93 | /* Definitions */ |
---|
| 94 | |
---|
| 95 | Bool |
---|
| 96 | VNCViewer::HandleTightBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh) |
---|
| 97 | { |
---|
| 98 | CARDBPP fill_colour; |
---|
| 99 | CARD8 comp_ctl; |
---|
| 100 | CARD8 filter_id; |
---|
| 101 | filterPtrBPP filterFn; |
---|
| 102 | z_streamp zs; |
---|
| 103 | char *buffer2; |
---|
| 104 | int err, stream_id, compressedLen, bitsPixel; |
---|
| 105 | int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes; |
---|
| 106 | |
---|
| 107 | if (!ReadFromRFBServer((char *)&comp_ctl, 1)) |
---|
| 108 | return False; |
---|
| 109 | |
---|
| 110 | /* Flush zlib streams if we are told by the server to do so. */ |
---|
| 111 | for (stream_id = 0; stream_id < 4; stream_id++) { |
---|
| 112 | if ((comp_ctl & 1) && zlibStreamActive[stream_id]) { |
---|
| 113 | if (inflateEnd (&zlibStream[stream_id]) != Z_OK && |
---|
| 114 | zlibStream[stream_id].msg != NULL) |
---|
| 115 | aLog("inflateEnd: %s\n", zlibStream[stream_id].msg); |
---|
| 116 | zlibStreamActive[stream_id] = False; |
---|
| 117 | } |
---|
| 118 | comp_ctl >>= 1; |
---|
| 119 | } |
---|
| 120 | |
---|
| 121 | /* Handle solid rectangles. */ |
---|
| 122 | if (comp_ctl == rfbTightFill) { |
---|
| 123 | #if BPP == 32 |
---|
| 124 | if (myFormat.depth == 24 && myFormat.redMax == 0xFF && |
---|
| 125 | myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { |
---|
| 126 | if (!ReadFromRFBServer(buffer, 3)) |
---|
| 127 | return False; |
---|
| 128 | fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]); |
---|
| 129 | } else { |
---|
| 130 | if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour))) |
---|
| 131 | return False; |
---|
| 132 | } |
---|
| 133 | #else |
---|
| 134 | if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour))) |
---|
| 135 | return False; |
---|
| 136 | #endif |
---|
| 137 | |
---|
| 138 | ct->FillToScreen(fill_colour, rx, ry, rw, rh); |
---|
| 139 | |
---|
| 140 | return True; |
---|
| 141 | } |
---|
| 142 | |
---|
| 143 | #if BPP == 8 |
---|
| 144 | if (comp_ctl == rfbTightJpeg) { |
---|
| 145 | aLog("Tight encoding: JPEG is not supported in 8 bpp mode.\n"); |
---|
| 146 | return False; |
---|
| 147 | } |
---|
| 148 | #else |
---|
| 149 | if (comp_ctl == rfbTightJpeg) { |
---|
| 150 | return DecompressJpegRectBPP(ct,rx, ry, rw, rh); |
---|
| 151 | } |
---|
| 152 | #endif |
---|
| 153 | |
---|
| 154 | /* Quit on unsupported subencoding value. */ |
---|
| 155 | if (comp_ctl > rfbTightMaxSubencoding) { |
---|
| 156 | aLog("Tight encoding: bad subencoding value received.\n"); |
---|
| 157 | return False; |
---|
| 158 | } |
---|
| 159 | |
---|
| 160 | /* |
---|
| 161 | * Here primary compression mode handling begins. |
---|
| 162 | * Data was processed with optional filter + zlib compression. |
---|
| 163 | */ |
---|
| 164 | |
---|
| 165 | /* First, we should identify a filter to use. */ |
---|
| 166 | if ((comp_ctl & rfbTightExplicitFilter) != 0) { |
---|
| 167 | if (!ReadFromRFBServer((char*)&filter_id, 1)) |
---|
| 168 | return False; |
---|
| 169 | |
---|
| 170 | switch (filter_id) { |
---|
| 171 | case rfbTightFilterCopy: |
---|
| 172 | filterFn = &VNCViewer::FilterCopyBPP; |
---|
| 173 | bitsPixel = InitFilterCopyBPP(rw, rh); |
---|
| 174 | break; |
---|
| 175 | case rfbTightFilterPalette: |
---|
| 176 | filterFn = &VNCViewer::FilterPaletteBPP; |
---|
| 177 | bitsPixel = InitFilterPaletteBPP(rw, rh); |
---|
| 178 | break; |
---|
| 179 | case rfbTightFilterGradient: |
---|
| 180 | filterFn = &VNCViewer::FilterGradientBPP; |
---|
| 181 | bitsPixel = InitFilterGradientBPP(rw, rh); |
---|
| 182 | break; |
---|
| 183 | default: |
---|
| 184 | aLog("Tight encoding: unknown filter code received.\n"); |
---|
| 185 | return False; |
---|
| 186 | } |
---|
| 187 | } else { |
---|
| 188 | filterFn = &VNCViewer::FilterCopyBPP; |
---|
| 189 | bitsPixel = InitFilterCopyBPP(rw, rh); |
---|
| 190 | } |
---|
| 191 | if (bitsPixel == 0) { |
---|
| 192 | aLog("Tight encoding: error receiving palette.\n"); |
---|
| 193 | return False; |
---|
| 194 | } |
---|
| 195 | |
---|
| 196 | /* Determine if the data should be decompressed or just copied. */ |
---|
| 197 | rowSize = (rw * bitsPixel + 7) / 8; |
---|
| 198 | if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) { |
---|
| 199 | if (!ReadFromRFBServer((char*)buffer, rh * rowSize)) |
---|
| 200 | return False; |
---|
| 201 | |
---|
| 202 | buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4]; |
---|
| 203 | (this->*filterFn)(rh, (CARDBPP *)buffer2); |
---|
| 204 | ct->CopyDataToScreen(buffer2, rx, ry, rw, rh); |
---|
| 205 | |
---|
| 206 | return True; |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | /* Read the length (1..3 bytes) of compressed data following. */ |
---|
| 210 | compressedLen = (int)ReadCompactLen(); |
---|
| 211 | if (compressedLen <= 0) { |
---|
| 212 | aLog("Incorrect data received from the server.\n"); |
---|
| 213 | return False; |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | /* Now let's initialize compression stream if needed. */ |
---|
| 217 | stream_id = comp_ctl & 0x03; |
---|
| 218 | zs = &zlibStream[stream_id]; |
---|
| 219 | if (!zlibStreamActive[stream_id]) { |
---|
| 220 | zs->zalloc = Z_NULL; |
---|
| 221 | zs->zfree = Z_NULL; |
---|
| 222 | zs->opaque = Z_NULL; |
---|
| 223 | err = inflateInit(zs); |
---|
| 224 | if (err != Z_OK) { |
---|
| 225 | if (zs->msg != NULL) |
---|
| 226 | aLog("InflateInit error: %s.\n", zs->msg); |
---|
| 227 | return False; |
---|
| 228 | } |
---|
| 229 | zlibStreamActive[stream_id] = True; |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | /* Read, decode and draw actual pixel data in a loop. */ |
---|
| 233 | |
---|
| 234 | bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC; |
---|
| 235 | buffer2 = &buffer[bufferSize]; |
---|
| 236 | if (rowSize > bufferSize) { |
---|
| 237 | /* Should be impossible when BUFFER_SIZE >= 16384 */ |
---|
| 238 | aLog("Internal error: incorrect buffer size.\n"); |
---|
| 239 | return False; |
---|
| 240 | } |
---|
| 241 | |
---|
| 242 | rowsProcessed = 0; |
---|
| 243 | extraBytes = 0; |
---|
| 244 | |
---|
| 245 | while (compressedLen > 0) { |
---|
| 246 | if (compressedLen > ZLIB_BUFFER_SIZE) |
---|
| 247 | portionLen = ZLIB_BUFFER_SIZE; |
---|
| 248 | else |
---|
| 249 | portionLen = compressedLen; |
---|
| 250 | |
---|
| 251 | if (!ReadFromRFBServer((char*)zlib_buffer, portionLen)) |
---|
| 252 | return False; |
---|
| 253 | |
---|
| 254 | compressedLen -= portionLen; |
---|
| 255 | |
---|
| 256 | zs->next_in = (Bytef *)zlib_buffer; |
---|
| 257 | zs->avail_in = portionLen; |
---|
| 258 | |
---|
| 259 | do { |
---|
| 260 | zs->next_out = (Bytef *)&buffer[extraBytes]; |
---|
| 261 | zs->avail_out = bufferSize - extraBytes; |
---|
| 262 | |
---|
| 263 | err = inflate(zs, Z_SYNC_FLUSH); |
---|
| 264 | if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */ |
---|
| 265 | break; |
---|
| 266 | if (err != Z_OK && err != Z_STREAM_END) { |
---|
| 267 | if (zs->msg != NULL) { |
---|
| 268 | aLog("Inflate error: %s.\n", zs->msg); |
---|
| 269 | } else { |
---|
| 270 | aLog("Inflate error: %d.\n", err); |
---|
| 271 | } |
---|
| 272 | return False; |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | numRows = (bufferSize - zs->avail_out) / rowSize; |
---|
| 276 | |
---|
| 277 | (this->*filterFn)(numRows, (CARDBPP *)buffer2); |
---|
| 278 | |
---|
| 279 | extraBytes = bufferSize - zs->avail_out - numRows * rowSize; |
---|
| 280 | if (extraBytes > 0) |
---|
| 281 | memcpy(buffer, &buffer[numRows * rowSize], extraBytes); |
---|
| 282 | |
---|
| 283 | ct->CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows); |
---|
| 284 | rowsProcessed += numRows; |
---|
| 285 | } |
---|
| 286 | while (zs->avail_out == 0); |
---|
| 287 | } |
---|
| 288 | |
---|
| 289 | if (rowsProcessed != rh) { |
---|
| 290 | aLog("Incorrect number of scan lines after decompression.\n"); |
---|
| 291 | return False; |
---|
| 292 | } |
---|
| 293 | |
---|
| 294 | return True; |
---|
| 295 | } |
---|
| 296 | |
---|
| 297 | /*---------------------------------------------------------------------------- |
---|
| 298 | * |
---|
| 299 | * Filter stuff. |
---|
| 300 | * |
---|
| 301 | */ |
---|
| 302 | |
---|
| 303 | /* |
---|
| 304 | The following variables are defined in rfbproto.c: |
---|
| 305 | static Bool cutZeros; |
---|
| 306 | static int rectWidth, rectColors; |
---|
| 307 | static CARD8 tightPalette[256*4]; |
---|
| 308 | static CARD8 tightPrevRow[2048*3*sizeof(CARD16)]; |
---|
| 309 | */ |
---|
| 310 | |
---|
| 311 | int |
---|
| 312 | VNCViewer::InitFilterCopyBPP (int rw, int rh) |
---|
| 313 | { |
---|
| 314 | rectWidth = rw; |
---|
| 315 | |
---|
| 316 | #if BPP == 32 |
---|
| 317 | if (myFormat.depth == 24 && myFormat.redMax == 0xFF && |
---|
| 318 | myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { |
---|
| 319 | cutZeros = True; |
---|
| 320 | return 24; |
---|
| 321 | } else { |
---|
| 322 | cutZeros = False; |
---|
| 323 | } |
---|
| 324 | #endif |
---|
| 325 | |
---|
| 326 | return BPP; |
---|
| 327 | } |
---|
| 328 | |
---|
| 329 | void |
---|
| 330 | VNCViewer::FilterCopyBPP (int numRows, CARDBPP *dst) |
---|
| 331 | { |
---|
| 332 | |
---|
| 333 | #if BPP == 32 |
---|
| 334 | int x, y; |
---|
| 335 | |
---|
| 336 | if (cutZeros) { |
---|
| 337 | for (y = 0; y < numRows; y++) { |
---|
| 338 | for (x = 0; x < rectWidth; x++) { |
---|
| 339 | dst[y*rectWidth+x] = |
---|
| 340 | RGB24_TO_PIXEL32(buffer[(y*rectWidth+x)*3], |
---|
| 341 | buffer[(y*rectWidth+x)*3+1], |
---|
| 342 | buffer[(y*rectWidth+x)*3+2]); |
---|
| 343 | } |
---|
| 344 | } |
---|
| 345 | return; |
---|
| 346 | } |
---|
| 347 | #endif |
---|
| 348 | |
---|
| 349 | memcpy (dst, buffer, numRows * rectWidth * (BPP / 8)); |
---|
| 350 | } |
---|
| 351 | |
---|
| 352 | int |
---|
| 353 | VNCViewer::InitFilterGradientBPP (int rw, int rh) |
---|
| 354 | { |
---|
| 355 | int bits; |
---|
| 356 | |
---|
| 357 | bits = InitFilterCopyBPP(rw, rh); |
---|
| 358 | if (cutZeros) |
---|
| 359 | memset(tightPrevRow, 0, rw * 3); |
---|
| 360 | else |
---|
| 361 | memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16)); |
---|
| 362 | |
---|
| 363 | return bits; |
---|
| 364 | } |
---|
| 365 | |
---|
| 366 | #if BPP == 32 |
---|
| 367 | |
---|
| 368 | void |
---|
| 369 | VNCViewer::FilterGradient24 (int numRows, CARD32 *dst) |
---|
| 370 | { |
---|
| 371 | int x, y, c; |
---|
| 372 | CARD8 thisRow[2048*3]; |
---|
| 373 | CARD8 pix[3]; |
---|
| 374 | int est[3]; |
---|
| 375 | |
---|
| 376 | for (y = 0; y < numRows; y++) { |
---|
| 377 | |
---|
| 378 | /* First pixel in a row */ |
---|
| 379 | for (c = 0; c < 3; c++) { |
---|
| 380 | pix[c] = tightPrevRow[c] + buffer[y*rectWidth*3+c]; |
---|
| 381 | thisRow[c] = pix[c]; |
---|
| 382 | } |
---|
| 383 | dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); |
---|
| 384 | |
---|
| 385 | /* Remaining pixels of a row */ |
---|
| 386 | for (x = 1; x < rectWidth; x++) { |
---|
| 387 | for (c = 0; c < 3; c++) { |
---|
| 388 | est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] - |
---|
| 389 | (int)tightPrevRow[(x-1)*3+c]; |
---|
| 390 | if (est[c] > 0xFF) { |
---|
| 391 | est[c] = 0xFF; |
---|
| 392 | } else if (est[c] < 0x00) { |
---|
| 393 | est[c] = 0x00; |
---|
| 394 | } |
---|
| 395 | pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c]; |
---|
| 396 | thisRow[x*3+c] = pix[c]; |
---|
| 397 | } |
---|
| 398 | dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); |
---|
| 399 | } |
---|
| 400 | |
---|
| 401 | memcpy(tightPrevRow, thisRow, rectWidth * 3); |
---|
| 402 | } |
---|
| 403 | } |
---|
| 404 | |
---|
| 405 | #endif |
---|
| 406 | |
---|
| 407 | void |
---|
| 408 | VNCViewer::FilterGradientBPP (int numRows, CARDBPP *dst) |
---|
| 409 | { |
---|
| 410 | int x, y, c; |
---|
| 411 | CARDBPP *src = (CARDBPP *)buffer; |
---|
| 412 | CARD16 *thatRow = (CARD16 *)tightPrevRow; |
---|
| 413 | CARD16 thisRow[2048*3]; |
---|
| 414 | CARD16 pix[3]; |
---|
| 415 | CARD16 max[3]; |
---|
| 416 | int shift[3]; |
---|
| 417 | int est[3]; |
---|
| 418 | |
---|
| 419 | #if BPP == 32 |
---|
| 420 | if (cutZeros) { |
---|
| 421 | FilterGradient24(numRows, dst); |
---|
| 422 | return; |
---|
| 423 | } |
---|
| 424 | #endif |
---|
| 425 | |
---|
| 426 | max[0] = myFormat.redMax; |
---|
| 427 | max[1] = myFormat.greenMax; |
---|
| 428 | max[2] = myFormat.blueMax; |
---|
| 429 | |
---|
| 430 | shift[0] = myFormat.redShift; |
---|
| 431 | shift[1] = myFormat.greenShift; |
---|
| 432 | shift[2] = myFormat.blueShift; |
---|
| 433 | |
---|
| 434 | for (y = 0; y < numRows; y++) { |
---|
| 435 | |
---|
| 436 | /* First pixel in a row */ |
---|
| 437 | for (c = 0; c < 3; c++) { |
---|
| 438 | pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]); |
---|
| 439 | thisRow[c] = pix[c]; |
---|
| 440 | } |
---|
| 441 | dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); |
---|
| 442 | |
---|
| 443 | /* Remaining pixels of a row */ |
---|
| 444 | for (x = 1; x < rectWidth; x++) { |
---|
| 445 | for (c = 0; c < 3; c++) { |
---|
| 446 | est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c]; |
---|
| 447 | if (est[c] > (int)max[c]) { |
---|
| 448 | est[c] = (int)max[c]; |
---|
| 449 | } else if (est[c] < 0) { |
---|
| 450 | est[c] = 0; |
---|
| 451 | } |
---|
| 452 | pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]); |
---|
| 453 | thisRow[x*3+c] = pix[c]; |
---|
| 454 | } |
---|
| 455 | dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); |
---|
| 456 | } |
---|
| 457 | memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16)); |
---|
| 458 | } |
---|
| 459 | } |
---|
| 460 | |
---|
| 461 | int |
---|
| 462 | VNCViewer::InitFilterPaletteBPP (int rw, int rh) |
---|
| 463 | { |
---|
| 464 | CARD8 numColors; |
---|
| 465 | CARDBPP *palette = (CARDBPP *)tightPalette; |
---|
| 466 | |
---|
| 467 | rectWidth = rw; |
---|
| 468 | |
---|
| 469 | if (!ReadFromRFBServer((char*)&numColors, 1)) |
---|
| 470 | return 0; |
---|
| 471 | |
---|
| 472 | rectColors = (int)numColors; |
---|
| 473 | if (++rectColors < 2) |
---|
| 474 | return 0; |
---|
| 475 | |
---|
| 476 | #if BPP == 32 |
---|
| 477 | int i; |
---|
| 478 | if (myFormat.depth == 24 && myFormat.redMax == 0xFF && |
---|
| 479 | myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { |
---|
| 480 | if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3)) |
---|
| 481 | return 0; |
---|
| 482 | for (i = rectColors - 1; i >= 0; i--) { |
---|
| 483 | palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3], |
---|
| 484 | tightPalette[i*3+1], |
---|
| 485 | tightPalette[i*3+2]); |
---|
| 486 | } |
---|
| 487 | return (rectColors == 2) ? 1 : 8; |
---|
| 488 | } |
---|
| 489 | #endif |
---|
| 490 | |
---|
| 491 | if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8))) |
---|
| 492 | return 0; |
---|
| 493 | |
---|
| 494 | return (rectColors == 2) ? 1 : 8; |
---|
| 495 | } |
---|
| 496 | |
---|
| 497 | void |
---|
| 498 | VNCViewer::FilterPaletteBPP (int numRows, CARDBPP *dst) |
---|
| 499 | { |
---|
| 500 | int x, y, b, w; |
---|
| 501 | CARD8 *src = (CARD8 *)buffer; |
---|
| 502 | CARDBPP *palette = (CARDBPP *)tightPalette; |
---|
| 503 | |
---|
| 504 | if (rectColors == 2) { |
---|
| 505 | w = (rectWidth + 7) / 8; |
---|
| 506 | for (y = 0; y < numRows; y++) { |
---|
| 507 | for (x = 0; x < rectWidth / 8; x++) { |
---|
| 508 | for (b = 7; b >= 0; b--) |
---|
| 509 | dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1]; |
---|
| 510 | } |
---|
| 511 | for (b = 7; b >= 8 - rectWidth % 8; b--) { |
---|
| 512 | dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1]; |
---|
| 513 | } |
---|
| 514 | } |
---|
| 515 | } else { |
---|
| 516 | for (y = 0; y < numRows; y++) |
---|
| 517 | for (x = 0; x < rectWidth; x++) |
---|
| 518 | dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]]; |
---|
| 519 | } |
---|
| 520 | } |
---|
| 521 | |
---|
| 522 | |
---|
| 523 | #if BPP != 8 |
---|
| 524 | |
---|
| 525 | /*---------------------------------------------------------------------------- |
---|
| 526 | * |
---|
| 527 | * JPEG decompression. |
---|
| 528 | * |
---|
| 529 | */ |
---|
| 530 | |
---|
| 531 | /* |
---|
| 532 | The following variables are defined in rfbproto.c: |
---|
| 533 | static Bool jpegError; |
---|
| 534 | static struct jpeg_source_mgr jpegSrcManager; |
---|
| 535 | static JOCTET *jpegBufferPtr; |
---|
| 536 | static size_t *jpegBufferLen; |
---|
| 537 | */ |
---|
| 538 | |
---|
| 539 | Bool |
---|
| 540 | VNCViewer::DecompressJpegRectBPP(sgVNCViewer *ct, int x, int y, int w, int h) |
---|
| 541 | { |
---|
| 542 | struct jpeg_decompress_struct cinfo; |
---|
| 543 | struct jpeg_error_mgr jerr; |
---|
| 544 | int compressedLen; |
---|
| 545 | CARD8 *compressedData; |
---|
| 546 | CARDBPP *pixelPtr; |
---|
| 547 | JSAMPROW rowPointer[1]; |
---|
| 548 | int dx, dy; |
---|
| 549 | |
---|
| 550 | compressedLen = (int)ReadCompactLen(); |
---|
| 551 | if (compressedLen <= 0) { |
---|
| 552 | aLog("Incorrect data received from the server.\n"); |
---|
| 553 | return False; |
---|
| 554 | } |
---|
| 555 | |
---|
| 556 | compressedData = (CARD8*)malloc(compressedLen); |
---|
| 557 | if (compressedData == NULL) { |
---|
| 558 | aLog("Memory allocation error.\n"); |
---|
| 559 | return False; |
---|
| 560 | } |
---|
| 561 | |
---|
| 562 | if (!ReadFromRFBServer((char*)compressedData, compressedLen)) { |
---|
| 563 | free(compressedData); |
---|
| 564 | return False; |
---|
| 565 | } |
---|
| 566 | |
---|
| 567 | cinfo.err = jpeg_std_error(&jerr); |
---|
| 568 | jpeg_create_decompress(&cinfo); |
---|
| 569 | |
---|
| 570 | JpegSetSrcManager(&cinfo, compressedData, compressedLen); |
---|
| 571 | |
---|
| 572 | jpeg_read_header(&cinfo, TRUE); |
---|
| 573 | cinfo.out_color_space = JCS_RGB; |
---|
| 574 | |
---|
| 575 | jpeg_start_decompress(&cinfo); |
---|
| 576 | if (cinfo.output_width != w || cinfo.output_height != h || |
---|
| 577 | cinfo.output_components != 3) { |
---|
| 578 | aLog("Tight Encoding: Wrong JPEG data received.\n"); |
---|
| 579 | jpeg_destroy_decompress(&cinfo); |
---|
| 580 | free(compressedData); |
---|
| 581 | return False; |
---|
| 582 | } |
---|
| 583 | |
---|
| 584 | rowPointer[0] = (JSAMPROW)buffer; |
---|
| 585 | dy = 0; |
---|
| 586 | while (cinfo.output_scanline < cinfo.output_height) { |
---|
| 587 | jpeg_read_scanlines(&cinfo, rowPointer, 1); |
---|
| 588 | if (jpegError) { |
---|
| 589 | break; |
---|
| 590 | } |
---|
| 591 | pixelPtr = (CARDBPP *)&buffer[BUFFER_SIZE / 2]; |
---|
| 592 | for (dx = 0; dx < w; dx++) { |
---|
| 593 | *pixelPtr++ = |
---|
| 594 | RGB24_TO_PIXEL(BPP, buffer[dx*3], buffer[dx*3+1], buffer[dx*3+2]); |
---|
| 595 | } |
---|
| 596 | ct->CopyDataToScreen(&buffer[BUFFER_SIZE / 2], x, y + dy, w, 1); |
---|
| 597 | dy++; |
---|
| 598 | } |
---|
| 599 | |
---|
| 600 | if (!jpegError) |
---|
| 601 | jpeg_finish_decompress(&cinfo); |
---|
| 602 | |
---|
| 603 | jpeg_destroy_decompress(&cinfo); |
---|
| 604 | free(compressedData); |
---|
| 605 | |
---|
| 606 | return !jpegError; |
---|
| 607 | } |
---|
| 608 | |
---|
| 609 | #endif |
---|
| 610 | |
---|