1 /* 2 * tight.c 3 * 4 * Routines to implement Tight Encoding 5 */ 6 7 /* 8 * Copyright (C) 2005-2008 Sun Microsystems, Inc. All Rights Reserved. 9 * Copyright (C) 2004 Landmark Graphics Corporation. All Rights Reserved. 10 * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. 11 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 12 * 13 * This is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This software is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this software; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 26 * USA. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include "rfb.h" 33 #include "turbojpeg.h" 34 35 /* Note: The following constant should not be changed. */ 36 #define TIGHT_MIN_TO_COMPRESS 12 37 38 /* The parameters below may be adjusted. */ 39 #define MIN_SPLIT_RECT_SIZE 4096 40 #define MIN_SOLID_SUBRECT_SIZE 2048 41 #define MAX_SPLIT_TILE_SIZE 16 42 43 /* This variable is set on every rfbSendRectEncodingTight() call. */ 44 static Bool usePixelFormat24; 45 46 47 /* Compression level stuff. The following array contains various 48 encoder parameters for each of 10 compression levels (0..9). 49 Last three parameters correspond to JPEG quality levels (0..9). */ 50 51 typedef struct TIGHT_CONF_s { 52 int maxRectSize, maxRectWidth; 53 int monoMinRectSize; 54 int idxZlibLevel, monoZlibLevel, rawZlibLevel; 55 int idxMaxColorsDivisor; 56 } TIGHT_CONF; 57 58 static TIGHT_CONF tightConf[2] = { 59 { 65536, 2048, 6, 0, 0, 0, 4 }, 60 #if 0 61 { 2048, 128, 6, 1, 1, 1, 8 }, 62 { 6144, 256, 8, 3, 3, 2, 24 }, 63 { 10240, 1024, 12, 5, 5, 3, 32 }, 64 { 16384, 2048, 12, 6, 6, 4, 32 }, 65 { 32768, 2048, 12, 7, 7, 5, 32 }, 66 { 65536, 2048, 16, 7, 7, 6, 48 }, 67 { 65536, 2048, 16, 8, 8, 7, 64 }, 68 { 65536, 2048, 32, 9, 9, 8, 64 }, 69 #endif 70 { 65536, 2048, 32, 1, 1, 1, 96 } 71 }; 72 73 static int compressLevel; 74 static int qualityLevel; 75 static int subsampLevel; 76 77 static const int subsampLevel2tjsubsamp[4] = { 78 TJ_444, TJ_411, TJ_422, TJ_GRAYSCALE 79 }; 80 81 /* Stuff dealing with palettes. */ 82 83 typedef struct COLOR_LIST_s { 84 struct COLOR_LIST_s *next; 85 int idx; 86 CARD32 rgb; 87 } COLOR_LIST; 88 89 typedef struct PALETTE_ENTRY_s { 90 COLOR_LIST *listNode; 91 int numPixels; 92 } PALETTE_ENTRY; 93 94 typedef struct PALETTE_s { 95 PALETTE_ENTRY entry[256]; 96 COLOR_LIST *hash[256]; 97 COLOR_LIST list[256]; 98 } PALETTE; 99 100 static int paletteNumColors, paletteMaxColors; 101 static CARD32 monoBackground, monoForeground; 102 static PALETTE palette; 103 104 /* Pointers to dynamically-allocated buffers. */ 105 106 static int tightBeforeBufSize = 0; 107 static char *tightBeforeBuf = NULL; 108 109 static int tightAfterBufSize = 0; 110 static char *tightAfterBuf = NULL; 111 112 static int *prevRowBuf = NULL; 113 114 115 /* Prototypes for static functions. */ 116 117 static void FindBestSolidArea (int x, int y, int w, int h, 118 CARD32 colorValue, int *w_ptr, int *h_ptr); 119 static void ExtendSolidArea (int x, int y, int w, int h, 120 CARD32 colorValue, 121 int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr); 122 static Bool CheckSolidTile (int x, int y, int w, int h, 123 CARD32 *colorPtr, Bool needSameColor); 124 static Bool CheckSolidTile8 (int x, int y, int w, int h, 125 CARD32 *colorPtr, Bool needSameColor); 126 static Bool CheckSolidTile16 (int x, int y, int w, int h, 127 CARD32 *colorPtr, Bool needSameColor); 128 static Bool CheckSolidTile32 (int x, int y, int w, int h, 129 CARD32 *colorPtr, Bool needSameColor); 130 131 static Bool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h); 132 static Bool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h); 133 static Bool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h); 134 135 static Bool SendSolidRect (rfbClientPtr cl); 136 static Bool SendMonoRect (rfbClientPtr cl, int w, int h); 137 static Bool SendIndexedRect (rfbClientPtr cl, int w, int h); 138 static Bool SendFullColorRect (rfbClientPtr cl, int w, int h); 139 140 static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen, 141 int zlibLevel, int zlibStrategy); 142 static Bool SendCompressedData(rfbClientPtr cl, char *buf, int compressedLen); 143 144 static void FillPalette8(int count); 145 static void FillPalette16(int count); 146 static void FillPalette32(int count); 147 static void FastFillPalette16(rfbClientPtr cl, CARD16 *data, int w, int pitch, 148 int h); 149 static void FastFillPalette32(rfbClientPtr cl, CARD32 *data, int w, int pitch, 150 int h); 151 152 static void PaletteReset(void); 153 static int PaletteInsert(CARD32 rgb, int numPixels, int bpp); 154 155 static void Pack24(char *buf, rfbPixelFormat *fmt, int count); 156 157 static void EncodeIndexedRect16(CARD8 *buf, int count); 158 static void EncodeIndexedRect32(CARD8 *buf, int count); 159 160 static void EncodeMonoRect8(CARD8 *buf, int w, int h); 161 static void EncodeMonoRect16(CARD8 *buf, int w, int h); 162 static void EncodeMonoRect32(CARD8 *buf, int w, int h); 163 164 static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, 165 int quality); 166 167 /* 168 * Tight encoding implementation. 169 */ 170 171 int 172 rfbNumCodedRectsTight(cl, x, y, w, h) 173 rfbClientPtr cl; 174 int x, y, w, h; 175 { 176 int maxRectSize, maxRectWidth; 177 int subrectMaxWidth, subrectMaxHeight; 178 179 /* No matter how many rectangles we will send if LastRect markers 180 are used to terminate rectangle stream. */ 181 if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE) 182 return 0; 183 184 maxRectSize = tightConf[compressLevel].maxRectSize; 185 maxRectWidth = tightConf[compressLevel].maxRectWidth; 186 187 if (w > maxRectWidth || w * h > maxRectSize) { 188 subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; 189 subrectMaxHeight = maxRectSize / subrectMaxWidth; 190 return (((w - 1) / maxRectWidth + 1) * 191 ((h - 1) / subrectMaxHeight + 1)); 192 } else { 193 return 1; 194 } 195 } 196 197 Bool 198 rfbSendRectEncodingTight(cl, x, y, w, h) 199 rfbClientPtr cl; 200 int x, y, w, h; 201 { 202 int nMaxRows; 203 CARD32 colorValue; 204 int dx, dy, dw, dh; 205 int x_best, y_best, w_best, h_best; 206 char *fbptr; 207 208 compressLevel = cl->tightCompressLevel > 0 ? 1 : 0; 209 qualityLevel = cl->tightQualityLevel; 210 if (qualityLevel != -1) { 211 compressLevel = 1; 212 tightConf[compressLevel].idxZlibLevel = 1; 213 tightConf[compressLevel].monoZlibLevel = 1; 214 tightConf[compressLevel].rawZlibLevel = 1; 215 } else { 216 tightConf[compressLevel].idxZlibLevel = cl->tightCompressLevel; 217 tightConf[compressLevel].monoZlibLevel = cl->tightCompressLevel; 218 tightConf[compressLevel].rawZlibLevel = cl->tightCompressLevel; 219 } 220 subsampLevel = cl->tightSubsampLevel; 221 222 if ( cl->format.depth == 24 && cl->format.redMax == 0xFF && 223 cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) { 224 usePixelFormat24 = TRUE; 225 } else { 226 usePixelFormat24 = FALSE; 227 } 228 229 if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE) 230 return SendRectSimple(cl, x, y, w, h); 231 232 /* Make sure we can write at least one pixel into tightBeforeBuf. */ 233 234 if (tightBeforeBufSize < 4) { 235 tightBeforeBufSize = 4; 236 if (tightBeforeBuf == NULL) 237 tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); 238 else 239 tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, 240 tightBeforeBufSize); 241 } 242 243 /* Calculate maximum number of rows in one non-solid rectangle. */ 244 245 { 246 int maxRectSize, maxRectWidth, nMaxWidth; 247 248 maxRectSize = tightConf[compressLevel].maxRectSize; 249 maxRectWidth = tightConf[compressLevel].maxRectWidth; 250 nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; 251 nMaxRows = maxRectSize / nMaxWidth; 252 } 253 254 /* Try to find large solid-color areas and send them separately. */ 255 256 for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { 257 258 /* If a rectangle becomes too large, send its upper part now. */ 259 260 if (dy - y >= nMaxRows) { 261 if (!SendRectSimple(cl, x, y, w, nMaxRows)) 262 return 0; 263 y += nMaxRows; 264 h -= nMaxRows; 265 } 266 267 dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? 268 MAX_SPLIT_TILE_SIZE : (y + h - dy); 269 270 for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) { 271 272 dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ? 273 MAX_SPLIT_TILE_SIZE : (x + w - dx); 274 275 if (CheckSolidTile(dx, dy, dw, dh, &colorValue, FALSE)) { 276 277 if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1) { 278 CARD32 r=(colorValue>>16)&0xFF; 279 CARD32 g=(colorValue>>8)&0xFF; 280 CARD32 b=(colorValue)&0xFF; 281 double y=(0.257*(double)r)+(0.504*(double)g) 282 +(0.098*(double)b)+16.; 283 colorValue=(int)y+(((int)y)<<8)+(((int)y)<<16); 284 } 285 286 /* Get dimensions of solid-color area. */ 287 288 FindBestSolidArea(dx, dy, w - (dx - x), h - (dy - y), 289 colorValue, &w_best, &h_best); 290 291 /* Make sure a solid rectangle is large enough 292 (or the whole rectangle is of the same color). */ 293 294 if ( w_best * h_best != w * h && 295 w_best * h_best < MIN_SOLID_SUBRECT_SIZE ) 296 continue; 297 298 /* Try to extend solid rectangle to maximum size. */ 299 300 x_best = dx; y_best = dy; 301 ExtendSolidArea(x, y, w, h, colorValue, 302 &x_best, &y_best, &w_best, &h_best); 303 304 /* Send rectangles at top and left to solid-color area. */ 305 306 if ( y_best != y && 307 !SendRectSimple(cl, x, y, w, y_best-y) ) 308 return FALSE; 309 if ( x_best != x && 310 !rfbSendRectEncodingTight(cl, x, y_best, 311 x_best-x, h_best) ) 312 return FALSE; 313 314 /* Send solid-color rectangle. */ 315 316 if (!SendTightHeader(cl, x_best, y_best, w_best, h_best)) 317 return FALSE; 318 319 fbptr = (rfbScreen.pfbMemory + 320 (rfbScreen.paddedWidthInBytes * y_best) + 321 (x_best * (rfbScreen.bitsPerPixel / 8))); 322 323 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, 324 &cl->format, fbptr, tightBeforeBuf, 325 rfbScreen.paddedWidthInBytes, 1, 1); 326 327 if (!SendSolidRect(cl)) 328 return FALSE; 329 330 /* Send remaining rectangles (at right and bottom). */ 331 332 if ( x_best + w_best != x + w && 333 !rfbSendRectEncodingTight(cl, x_best+w_best, y_best, 334 w-(x_best-x)-w_best, h_best) ) 335 return FALSE; 336 if ( y_best + h_best != y + h && 337 !rfbSendRectEncodingTight(cl, x, y_best+h_best, 338 w, h-(y_best-y)-h_best) ) 339 return FALSE; 340 341 /* Return after all recursive calls are done. */ 342 343 return TRUE; 344 } 345 346 } 347 348 } 349 350 /* No suitable solid-color rectangles found. */ 351 352 return SendRectSimple(cl, x, y, w, h); 353 } 354 355 static void 356 FindBestSolidArea(x, y, w, h, colorValue, w_ptr, h_ptr) 357 int x, y, w, h; 358 CARD32 colorValue; 359 int *w_ptr, *h_ptr; 360 { 361 int dx, dy, dw, dh; 362 int w_prev; 363 int w_best = 0, h_best = 0; 364 365 w_prev = w; 366 367 for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { 368 369 dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? 370 MAX_SPLIT_TILE_SIZE : (y + h - dy); 371 dw = (w_prev > MAX_SPLIT_TILE_SIZE) ? 372 MAX_SPLIT_TILE_SIZE : w_prev; 373 374 if (!CheckSolidTile(x, dy, dw, dh, &colorValue, TRUE)) 375 break; 376 377 for (dx = x + dw; dx < x + w_prev;) { 378 dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ? 379 MAX_SPLIT_TILE_SIZE : (x + w_prev - dx); 380 if (!CheckSolidTile(dx, dy, dw, dh, &colorValue, TRUE)) 381 break; 382 dx += dw; 383 } 384 385 w_prev = dx - x; 386 if (w_prev * (dy + dh - y) > w_best * h_best) { 387 w_best = w_prev; 388 h_best = dy + dh - y; 389 } 390 } 391 392 *w_ptr = w_best; 393 *h_ptr = h_best; 394 } 395 396 static void 397 ExtendSolidArea(x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr) 398 int x, y, w, h; 399 CARD32 colorValue; 400 int *x_ptr, *y_ptr, *w_ptr, *h_ptr; 401 { 402 int cx, cy; 403 404 /* Try to extend the area upwards. */ 405 for ( cy = *y_ptr - 1; 406 cy >= y && CheckSolidTile(*x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); 407 cy-- ); 408 *h_ptr += *y_ptr - (cy + 1); 409 *y_ptr = cy + 1; 410 411 /* ... downwards. */ 412 for ( cy = *y_ptr + *h_ptr; 413 cy < y + h && 414 CheckSolidTile(*x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); 415 cy++ ); 416 *h_ptr += cy - (*y_ptr + *h_ptr); 417 418 /* ... to the left. */ 419 for ( cx = *x_ptr - 1; 420 cx >= x && CheckSolidTile(cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); 421 cx-- ); 422 *w_ptr += *x_ptr - (cx + 1); 423 *x_ptr = cx + 1; 424 425 /* ... to the right. */ 426 for ( cx = *x_ptr + *w_ptr; 427 cx < x + w && 428 CheckSolidTile(cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); 429 cx++ ); 430 *w_ptr += cx - (*x_ptr + *w_ptr); 431 } 432 433 /* 434 * Check if a rectangle is all of the same color. If needSameColor is 435 * set to non-zero, then also check that its color equals to the 436 * *colorPtr value. The result is 1 if the test is successfull, and in 437 * that case new color will be stored in *colorPtr. 438 */ 439 440 static Bool 441 CheckSolidTile(x, y, w, h, colorPtr, needSameColor) 442 int x, y, w, h; 443 CARD32 *colorPtr; 444 Bool needSameColor; 445 { 446 switch(rfbServerFormat.bitsPerPixel) { 447 case 32: 448 return CheckSolidTile32(x, y, w, h, colorPtr, needSameColor); 449 case 16: 450 return CheckSolidTile16(x, y, w, h, colorPtr, needSameColor); 451 default: 452 return CheckSolidTile8(x, y, w, h, colorPtr, needSameColor); 453 } 454 } 455 456 #define DEFINE_CHECK_SOLID_FUNCTION(bpp) \ 457 \ 458 static Bool \ 459 CheckSolidTile##bpp(x, y, w, h, colorPtr, needSameColor) \ 460 int x, y, w, h; \ 461 CARD32 *colorPtr; \ 462 Bool needSameColor; \ 463 { \ 464 CARD##bpp *fbptr; \ 465 CARD##bpp colorValue; \ 466 int dx, dy; \ 467 \ 468 fbptr = (CARD##bpp *) \ 469 &rfbScreen.pfbMemory[y * rfbScreen.paddedWidthInBytes + x * (bpp/8)]; \ 470 \ 471 colorValue = *fbptr; \ 472 if (needSameColor && (CARD32)colorValue != *colorPtr) \ 473 return FALSE; \ 474 \ 475 for (dy = 0; dy < h; dy++) { \ 476 for (dx = 0; dx < w; dx++) { \ 477 if (colorValue != fbptr[dx]) \ 478 return FALSE; \ 479 } \ 480 fbptr = (CARD##bpp *)((CARD8 *)fbptr + rfbScreen.paddedWidthInBytes); \ 481 } \ 482 \ 483 *colorPtr = (CARD32)colorValue; \ 484 return TRUE; \ 485 } 486 487 DEFINE_CHECK_SOLID_FUNCTION(8) 488 DEFINE_CHECK_SOLID_FUNCTION(16) 489 DEFINE_CHECK_SOLID_FUNCTION(32) 490 491 static Bool 492 SendRectSimple(cl, x, y, w, h) 493 rfbClientPtr cl; 494 int x, y, w, h; 495 { 496 int maxBeforeSize, maxAfterSize; 497 int maxRectSize, maxRectWidth; 498 int subrectMaxWidth, subrectMaxHeight; 499 int dx, dy; 500 int rw, rh; 501 502 maxRectSize = tightConf[compressLevel].maxRectSize; 503 maxRectWidth = tightConf[compressLevel].maxRectWidth; 504 505 maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8); 506 maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; 507 508 if (tightBeforeBufSize < maxBeforeSize) { 509 tightBeforeBufSize = maxBeforeSize; 510 if (tightBeforeBuf == NULL) 511 tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); 512 else 513 tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, 514 tightBeforeBufSize); 515 } 516 517 if (tightAfterBufSize < maxAfterSize) { 518 tightAfterBufSize = maxAfterSize; 519 if (tightAfterBuf == NULL) 520 tightAfterBuf = (char *)xalloc(tightAfterBufSize); 521 else 522 tightAfterBuf = (char *)xrealloc(tightAfterBuf, 523 tightAfterBufSize); 524 } 525 526 if (w > maxRectWidth || w * h > maxRectSize) { 527 subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; 528 subrectMaxHeight = maxRectSize / subrectMaxWidth; 529 530 for (dy = 0; dy < h; dy += subrectMaxHeight) { 531 for (dx = 0; dx < w; dx += maxRectWidth) { 532 rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx; 533 rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy; 534 if (!SendSubrect(cl, x+dx, y+dy, rw, rh)) 535 return FALSE; 536 } 537 } 538 } else { 539 if (!SendSubrect(cl, x, y, w, h)) 540 return FALSE; 541 } 542 543 return TRUE; 544 } 545 546 static Bool 547 SendSubrect(cl, x, y, w, h) 548 rfbClientPtr cl; 549 int x, y, w, h; 550 { 551 char *fbptr; 552 Bool success = FALSE; 553 554 /* Send pending data if there is more than 128 bytes. */ 555 if (ublen > 128) { 556 if (!rfbSendUpdateBuf(cl)) 557 return FALSE; 558 } 559 560 if (!SendTightHeader(cl, x, y, w, h)) 561 return FALSE; 562 563 fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y) 564 + (x * (rfbScreen.bitsPerPixel / 8))); 565 566 if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1) 567 return SendJpegRect(cl, x, y, w, h, qualityLevel); 568 569 paletteMaxColors = w * h / tightConf[compressLevel].idxMaxColorsDivisor; 570 if(qualityLevel != -1) 571 paletteMaxColors = 24; 572 if ( paletteMaxColors < 2 && 573 w * h >= tightConf[compressLevel].monoMinRectSize ) { 574 paletteMaxColors = 2; 575 } 576 577 if (cl->format.bitsPerPixel == rfbServerFormat.bitsPerPixel && 578 cl->format.redMax == rfbServerFormat.redMax && 579 cl->format.greenMax == rfbServerFormat.greenMax && 580 cl->format.blueMax == rfbServerFormat.blueMax && 581 cl->format.bitsPerPixel >= 16) { 582 583 /* This is so we can avoid translating the pixels when compressing 584 with JPEG, since it is unnecessary */ 585 switch (cl->format.bitsPerPixel) { 586 case 16: 587 FastFillPalette16(cl, (CARD16 *)fbptr, w, 588 rfbScreen.paddedWidthInBytes/2, h); 589 break; 590 default: 591 FastFillPalette32(cl, (CARD32 *)fbptr, w, 592 rfbScreen.paddedWidthInBytes/4, h); 593 } 594 595 if(paletteNumColors != 0 || qualityLevel == -1) { 596 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, 597 &cl->format, fbptr, tightBeforeBuf, 598 rfbScreen.paddedWidthInBytes, w, h); 599 } 600 } 601 else { 602 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, 603 &cl->format, fbptr, tightBeforeBuf, 604 rfbScreen.paddedWidthInBytes, w, h); 605 606 switch (cl->format.bitsPerPixel) { 607 case 8: 608 FillPalette8(w * h); 609 break; 610 case 16: 611 FillPalette16(w * h); 612 break; 613 default: 614 FillPalette32(w * h); 615 } 616 } 617 618 switch (paletteNumColors) { 619 case 0: 620 /* Truecolor image */ 621 if (qualityLevel != -1) { 622 success = SendJpegRect(cl, x, y, w, h, qualityLevel); 623 } else { 624 success = SendFullColorRect(cl, w, h); 625 } 626 break; 627 case 1: 628 /* Solid rectangle */ 629 success = SendSolidRect(cl); 630 break; 631 case 2: 632 /* Two-color rectangle */ 633 success = SendMonoRect(cl, w, h); 634 break; 635 default: 636 /* Up to 256 different colors */ 637 success = SendIndexedRect(cl, w, h); 638 } 639 return success; 640 } 641 642 static Bool 643 SendTightHeader(cl, x, y, w, h) 644 rfbClientPtr cl; 645 int x, y, w, h; 646 { 647 rfbFramebufferUpdateRectHeader rect; 648 649 if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { 650 if (!rfbSendUpdateBuf(cl)) 651 return FALSE; 652 } 653 654 rect.r.x = Swap16IfLE(x); 655 rect.r.y = Swap16IfLE(y); 656 rect.r.w = Swap16IfLE(w); 657 rect.r.h = Swap16IfLE(h); 658 rect.encoding = Swap32IfLE(rfbEncodingTight); 659 660 memcpy(&updateBuf[ublen], (char *)&rect, 661 sz_rfbFramebufferUpdateRectHeader); 662 ublen += sz_rfbFramebufferUpdateRectHeader; 663 664 cl->rfbRectanglesSent[rfbEncodingTight]++; 665 cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader; 666 667 return TRUE; 668 } 669 670 /* 671 * Subencoding implementations. 672 */ 673 674 static Bool 675 SendSolidRect(cl) 676 rfbClientPtr cl; 677 { 678 int len; 679 680 if (usePixelFormat24) { 681 Pack24(tightBeforeBuf, &cl->format, 1); 682 len = 3; 683 } else 684 len = cl->format.bitsPerPixel / 8; 685 686 if (ublen + 1 + len > UPDATE_BUF_SIZE) { 687 if (!rfbSendUpdateBuf(cl)) 688 return FALSE; 689 } 690 691 updateBuf[ublen++] = (char)(rfbTightFill << 4); 692 memcpy (&updateBuf[ublen], tightBeforeBuf, len); 693 ublen += len; 694 695 cl->rfbBytesSent[rfbEncodingTight] += len + 1; 696 697 return TRUE; 698 } 699 700 static Bool 701 SendMonoRect(cl, w, h) 702 rfbClientPtr cl; 703 int w, h; 704 { 705 int streamId = 1; 706 int paletteLen, dataLen; 707 708 if ( (ublen + TIGHT_MIN_TO_COMPRESS + 6 + 709 2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { 710 if (!rfbSendUpdateBuf(cl)) 711 return FALSE; 712 } 713 714 /* Prepare tight encoding header. */ 715 dataLen = (w + 7) / 8; 716 dataLen *= h; 717 718 if (tightConf[compressLevel].monoZlibLevel == 0) 719 updateBuf[ublen++] = (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4); 720 else 721 updateBuf[ublen++] = (streamId | rfbTightExplicitFilter) << 4; 722 updateBuf[ublen++] = rfbTightFilterPalette; 723 updateBuf[ublen++] = 1; 724 725 /* Prepare palette, convert image. */ 726 switch (cl->format.bitsPerPixel) { 727 728 case 32: 729 EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h); 730 731 ((CARD32 *)tightAfterBuf)[0] = monoBackground; 732 ((CARD32 *)tightAfterBuf)[1] = monoForeground; 733 if (usePixelFormat24) { 734 Pack24(tightAfterBuf, &cl->format, 2); 735 paletteLen = 6; 736 } else 737 paletteLen = 8; 738 739 memcpy(&updateBuf[ublen], tightAfterBuf, paletteLen); 740 ublen += paletteLen; 741 cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen; 742 break; 743 744 case 16: 745 EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h); 746 747 ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground; 748 ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground; 749 750 memcpy(&updateBuf[ublen], tightAfterBuf, 4); 751 ublen += 4; 752 cl->rfbBytesSent[rfbEncodingTight] += 7; 753 break; 754 755 default: 756 EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h); 757 758 updateBuf[ublen++] = (char)monoBackground; 759 updateBuf[ublen++] = (char)monoForeground; 760 cl->rfbBytesSent[rfbEncodingTight] += 5; 761 } 762 763 return CompressData(cl, streamId, dataLen, 764 tightConf[compressLevel].monoZlibLevel, 765 Z_DEFAULT_STRATEGY); 766 } 767 768 static Bool 769 SendIndexedRect(cl, w, h) 770 rfbClientPtr cl; 771 int w, h; 772 { 773 int streamId = 2; 774 int i, entryLen; 775 776 if ( (ublen + TIGHT_MIN_TO_COMPRESS + 6 + 777 paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { 778 if (!rfbSendUpdateBuf(cl)) 779 return FALSE; 780 } 781 782 /* Prepare tight encoding header. */ 783 if (tightConf[compressLevel].idxZlibLevel == 0) 784 updateBuf[ublen++] = (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4); 785 else 786 updateBuf[ublen++] = (streamId | rfbTightExplicitFilter) << 4; 787 updateBuf[ublen++] = rfbTightFilterPalette; 788 updateBuf[ublen++] = (char)(paletteNumColors - 1); 789 790 /* Prepare palette, convert image. */ 791 switch (cl->format.bitsPerPixel) { 792 793 case 32: 794 EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h); 795 796 for (i = 0; i < paletteNumColors; i++) { 797 ((CARD32 *)tightAfterBuf)[i] = 798 palette.entry[i].listNode->rgb; 799 } 800 if (usePixelFormat24) { 801 Pack24(tightAfterBuf, &cl->format, paletteNumColors); 802 entryLen = 3; 803 } else 804 entryLen = 4; 805 806 memcpy(&updateBuf[ublen], tightAfterBuf, paletteNumColors * entryLen); 807 ublen += paletteNumColors * entryLen; 808 cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen; 809 break; 810 811 case 16: 812 EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h); 813 814 for (i = 0; i < paletteNumColors; i++) { 815 ((CARD16 *)tightAfterBuf)[i] = 816 (CARD16)palette.entry[i].listNode->rgb; 817 } 818 819 memcpy(&updateBuf[ublen], tightAfterBuf, paletteNumColors * 2); 820 ublen += paletteNumColors * 2; 821 cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2; 822 break; 823 824 default: 825 return FALSE; /* Should never happen. */ 826 } 827 828 return CompressData(cl, streamId, w * h, 829 tightConf[compressLevel].idxZlibLevel, 830 Z_DEFAULT_STRATEGY); 831 } 832 833 static Bool 834 SendFullColorRect(cl, w, h) 835 rfbClientPtr cl; 836 int w, h; 837 { 838 int streamId = 0; 839 int len; 840 841 if (ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { 842 if (!rfbSendUpdateBuf(cl)) 843 return FALSE; 844 } 845 846 if (tightConf[compressLevel].rawZlibLevel == 0) 847 updateBuf[ublen++] = (char)(rfbTightNoZlib << 4); 848 else 849 updateBuf[ublen++] = 0x00; /* stream id = 0, no flushing, no filter */ 850 cl->rfbBytesSent[rfbEncodingTight]++; 851 852 if (usePixelFormat24) { 853 Pack24(tightBeforeBuf, &cl->format, w * h); 854 len = 3; 855 } else 856 len = cl->format.bitsPerPixel / 8; 857 858 return CompressData(cl, streamId, w * h * len, 859 tightConf[compressLevel].rawZlibLevel, 860 Z_DEFAULT_STRATEGY); 861 } 862 863 static Bool 864 CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy) 865 rfbClientPtr cl; 866 int streamId, dataLen, zlibLevel, zlibStrategy; 867 { 868 z_streamp pz; 869 int err, i; 870 871 if (dataLen < TIGHT_MIN_TO_COMPRESS) { 872 memcpy(&updateBuf[ublen], tightBeforeBuf, dataLen); 873 ublen += dataLen; 874 cl->rfbBytesSent[rfbEncodingTight] += dataLen; 875 return TRUE; 876 } 877 878 if (zlibLevel == 0) 879 return SendCompressedData (cl, tightBeforeBuf, dataLen); 880 881 pz = &cl->zsStruct[streamId]; 882 883 /* Initialize compression stream if needed. */ 884 if (!cl->zsActive[streamId]) { 885 pz->zalloc = Z_NULL; 886 pz->zfree = Z_NULL; 887 pz->opaque = Z_NULL; 888 889 err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS, 890 MAX_MEM_LEVEL, zlibStrategy); 891 if (err != Z_OK) 892 return FALSE; 893 894 cl->zsActive[streamId] = TRUE; 895 cl->zsLevel[streamId] = zlibLevel; 896 } 897 898 /* Prepare buffer pointers. */ 899 pz->next_in = (Bytef *)tightBeforeBuf; 900 pz->avail_in = dataLen; 901 pz->next_out = (Bytef *)tightAfterBuf; 902 pz->avail_out = tightAfterBufSize; 903 904 /* Change compression parameters if needed. */ 905 if (zlibLevel != cl->zsLevel[streamId]) { 906 if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) { 907 return FALSE; 908 } 909 cl->zsLevel[streamId] = zlibLevel; 910 } 911 912 /* Actual compression. */ 913 if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK || 914 pz->avail_in != 0 || pz->avail_out == 0 ) { 915 return FALSE; 916 } 917 918 return SendCompressedData(cl, tightAfterBuf, 919 tightAfterBufSize - pz->avail_out); 920 } 921 922 static Bool SendCompressedData(cl, buf, compressedLen) 923 rfbClientPtr cl; 924 char *buf; 925 int compressedLen; 926 { 927 int i, portionLen; 928 929 updateBuf[ublen++] = compressedLen & 0x7F; 930 cl->rfbBytesSent[rfbEncodingTight]++; 931 if (compressedLen > 0x7F) { 932 updateBuf[ublen-1] |= 0x80; 933 updateBuf[ublen++] = compressedLen >> 7 & 0x7F; 934 cl->rfbBytesSent[rfbEncodingTight]++; 935 if (compressedLen > 0x3FFF) { 936 updateBuf[ublen-1] |= 0x80; 937 updateBuf[ublen++] = compressedLen >> 14 & 0xFF; 938 cl->rfbBytesSent[rfbEncodingTight]++; 939 } 940 } 941 942 portionLen = UPDATE_BUF_SIZE; 943 for (i = 0; i < compressedLen; i += portionLen) { 944 if (i + portionLen > compressedLen) { 945 portionLen = compressedLen - i; 946 } 947 if (ublen + portionLen > UPDATE_BUF_SIZE) { 948 if (!rfbSendUpdateBuf(cl)) 949 return FALSE; 950 } 951 memcpy(&updateBuf[ublen], &buf[i], portionLen); 952 ublen += portionLen; 953 } 954 cl->rfbBytesSent[rfbEncodingTight] += compressedLen; 955 return TRUE; 956 } 957 958 /* 959 * Code to determine how many different colors used in rectangle. 960 */ 961 962 static void 963 FillPalette8(count) 964 int count; 965 { 966 CARD8 *data = (CARD8 *)tightBeforeBuf; 967 CARD8 c0, c1; 968 int i, n0, n1; 969 970 paletteNumColors = 0; 971 972 c0 = data[0]; 973 for (i = 1; i < count && data[i] == c0; i++); 974 if (i == count) { 975 paletteNumColors = 1; 976 return; /* Solid rectangle */ 977 } 978 979 if (paletteMaxColors < 2) 980 return; 981 982 n0 = i; 983 c1 = data[i]; 984 n1 = 0; 985 for (i++; i < count; i++) { 986 if (data[i] == c0) { 987 n0++; 988 } else if (data[i] == c1) { 989 n1++; 990 } else 991 break; 992 } 993 if (i == count) { 994 if (n0 > n1) { 995 monoBackground = (CARD32)c0; 996 monoForeground = (CARD32)c1; 997 } else { 998 monoBackground = (CARD32)c1; 999 monoForeground = (CARD32)c0; 1000 } 1001 paletteNumColors = 2; /* Two colors */ 1002 } 1003 } 1004 1005 #define DEFINE_FILL_PALETTE_FUNCTION(bpp) \ 1006 \ 1007 static void \ 1008 FillPalette##bpp(count) \ 1009 int count; \ 1010 { \ 1011 CARD##bpp *data = (CARD##bpp *)tightBeforeBuf; \ 1012 CARD##bpp c0, c1, ci; \ 1013 int i, n0, n1, ni; \ 1014 \ 1015 c0 = data[0]; \ 1016 for (i = 1; i < count && data[i] == c0; i++); \ 1017 if (i >= count) { \ 1018 paletteNumColors = 1; /* Solid rectangle */ \ 1019 return; \ 1020 } \ 1021 \ 1022 if (paletteMaxColors < 2) { \ 1023 paletteNumColors = 0; /* Full-color encoding preferred */ \ 1024 return; \ 1025 } \ 1026 \ 1027 n0 = i; \ 1028 c1 = data[i]; \ 1029 n1 = 0; \ 1030 for (i++; i < count; i++) { \ 1031 ci = data[i]; \ 1032 if (ci == c0) { \ 1033 n0++; \ 1034 } else if (ci == c1) { \ 1035 n1++; \ 1036 } else \ 1037 break; \ 1038 } \ 1039 if (i >= count) { \ 1040 if (n0 > n1) { \ 1041 monoBackground = (CARD32)c0; \ 1042 monoForeground = (CARD32)c1; \ 1043 } else { \ 1044 monoBackground = (CARD32)c1; \ 1045 monoForeground = (CARD32)c0; \ 1046 } \ 1047 paletteNumColors = 2; /* Two colors */ \ 1048 return; \ 1049 } \ 1050 \ 1051 PaletteReset(); \ 1052 PaletteInsert (c0, (CARD32)n0, bpp); \ 1053 PaletteInsert (c1, (CARD32)n1, bpp); \ 1054 \ 1055 ni = 1; \ 1056 for (i++; i < count; i++) { \ 1057 if (data[i] == ci) { \ 1058 ni++; \ 1059 } else { \ 1060 if (!PaletteInsert (ci, (CARD32)ni, bpp)) \ 1061 return; \ 1062 ci = data[i]; \ 1063 ni = 1; \ 1064 } \ 1065 } \ 1066 PaletteInsert (ci, (CARD32)ni, bpp); \ 1067 } 1068 1069 DEFINE_FILL_PALETTE_FUNCTION(16) 1070 DEFINE_FILL_PALETTE_FUNCTION(32) 1071 1072 #define DEFINE_FAST_FILL_PALETTE_FUNCTION(bpp) \ 1073 \ 1074 static void \ 1075 FastFillPalette##bpp(cl, data, w, pitch, h) \ 1076 rfbClientPtr cl; \ 1077 CARD##bpp *data; \ 1078 int w, pitch, h; \ 1079 { \ 1080 CARD##bpp c0, c1, ci, mask, c0t, c1t, cit; \ 1081 int i, j, i2, j2, n0, n1, ni; \ 1082 \ 1083 if (cl->translateFn != rfbTranslateNone) { \ 1084 mask = rfbServerFormat.redMax << rfbServerFormat.redShift; \ 1085 mask |= rfbServerFormat.greenMax << rfbServerFormat.greenShift; \ 1086 mask |= rfbServerFormat.blueMax << rfbServerFormat.blueShift; \ 1087 } else mask = ~0; \ 1088 \ 1089 c0 = data[0] & mask; \ 1090 for (j = 0; j < h; j++) { \ 1091 for (i = 0; i < w; i++) { \ 1092 if ((data[j * pitch + i] & mask) != c0) \ 1093 goto done; \ 1094 } \ 1095 } \ 1096 done: \ 1097 if (j >= h) { \ 1098 paletteNumColors = 1; /* Solid rectangle */ \ 1099 return; \ 1100 } \ 1101 if (paletteMaxColors < 2) { \ 1102 paletteNumColors = 0; /* Full-color encoding preferred */ \ 1103 return; \ 1104 } \ 1105 \ 1106 n0 = j * w + i; \ 1107 c1 = data[j * pitch + i] & mask; \ 1108 n1 = 0; \ 1109 i++; if (i >= w) {i = 0; j++;} \ 1110 for (j2 = j; j2 < h; j2++) { \ 1111 for (i2 = i; i2 < w; i2++) { \ 1112 ci = data[j2 * pitch + i2] & mask; \ 1113 if (ci == c0) { \ 1114 n0++; \ 1115 } else if (ci == c1) { \ 1116 n1++; \ 1117 } else \ 1118 goto done2; \ 1119 } \ 1120 i = 0; \ 1121 } \ 1122 done2: \ 1123 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \ 1124 &cl->format, (char *)&c0, (char *)&c0t, bpp/8, \ 1125 1, 1); \ 1126 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \ 1127 &cl->format, (char *)&c1, (char *)&c1t, bpp/8, \ 1128 1, 1); \ 1129 if (j2 >= h) { \ 1130 if (n0 > n1) { \ 1131 monoBackground = (CARD32)c0t; \ 1132 monoForeground = (CARD32)c1t; \ 1133 } else { \ 1134 monoBackground = (CARD32)c1t; \ 1135 monoForeground = (CARD32)c0t; \ 1136 } \ 1137 paletteNumColors = 2; /* Two colors */ \ 1138 return; \ 1139 } \ 1140 \ 1141 PaletteReset(); \ 1142 PaletteInsert (c0t, (CARD32)n0, bpp); \ 1143 PaletteInsert (c1t, (CARD32)n1, bpp); \ 1144 \ 1145 ni = 1; \ 1146 i2++; if (i2 >= w) {i2 = 0; j2++;} \ 1147 for (j = j2; j < h; j++) { \ 1148 for (i = i2; i < w; i++) { \ 1149 if ((data[j * pitch + i] & mask) == ci) { \ 1150 ni++; \ 1151 } else { \ 1152 (*cl->translateFn)(cl->translateLookupTable, \ 1153 &rfbServerFormat, &cl->format, \ 1154 (char *)&ci, (char *)&cit, bpp/8, \ 1155 1, 1); \ 1156 if (!PaletteInsert (cit, (CARD32)ni, bpp)) \ 1157 return; \ 1158 ci = data[j * pitch + i] & mask; \ 1159 ni = 1; \ 1160 } \ 1161 } \ 1162 i2 = 0; \ 1163 } \ 1164 \ 1165 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \ 1166 &cl->format, (char *)&ci, (char *)&cit, bpp/8, \ 1167 1, 1); \ 1168 PaletteInsert (cit, (CARD32)ni, bpp); \ 1169 } 1170 1171 DEFINE_FAST_FILL_PALETTE_FUNCTION(16) 1172 DEFINE_FAST_FILL_PALETTE_FUNCTION(32) 1173 1174 1175 /* 1176 * Functions to operate with palette structures. 1177 */ 1178 1179 #define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF)) 1180 #define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF)) 1181 1182 static void 1183 PaletteReset(void) 1184 { 1185 paletteNumColors = 0; 1186 memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *)); 1187 } 1188 1189 static int 1190 PaletteInsert(rgb, numPixels, bpp) 1191 CARD32 rgb; 1192 int numPixels; 1193 int bpp; 1194 { 1195 COLOR_LIST *pnode; 1196 COLOR_LIST *prev_pnode = NULL; 1197 int hash_key, idx, new_idx, count; 1198 1199 hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb); 1200 1201 pnode = palette.hash[hash_key]; 1202 1203 while (pnode != NULL) { 1204 if (pnode->rgb == rgb) { 1205 /* Such palette entry already exists. */ 1206 new_idx = idx = pnode->idx; 1207 count = palette.entry[idx].numPixels + numPixels; 1208 if (new_idx && palette.entry[new_idx-1].numPixels < count) { 1209 do { 1210 palette.entry[new_idx] = palette.entry[new_idx-1]; 1211 palette.entry[new_idx].listNode->idx = new_idx; 1212 new_idx--; 1213 } 1214 while (new_idx && palette.entry[new_idx-1].numPixels < count); 1215 palette.entry[new_idx].listNode = pnode; 1216 pnode->idx = new_idx; 1217 } 1218 palette.entry[new_idx].numPixels = count; 1219 return paletteNumColors; 1220 } 1221 prev_pnode = pnode; 1222 pnode = pnode->next; 1223 } 1224 1225 /* Check if palette is full. */ 1226 if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) { 1227 paletteNumColors = 0; 1228 return 0; 1229 } 1230 1231 /* Move palette entries with lesser pixel counts. */ 1232 for ( idx = paletteNumColors; 1233 idx > 0 && palette.entry[idx-1].numPixels < numPixels; 1234 idx-- ) { 1235 palette.entry[idx] = palette.entry[idx-1]; 1236 palette.entry[idx].listNode->idx = idx; 1237 } 1238 1239 /* Add new palette entry into the freed slot. */ 1240 pnode = &palette.list[paletteNumColors]; 1241 if (prev_pnode != NULL) { 1242 prev_pnode->next = pnode; 1243 } else { 1244 palette.hash[hash_key] = pnode; 1245 } 1246 pnode->next = NULL; 1247 pnode->idx = idx; 1248 pnode->rgb = rgb; 1249 palette.entry[idx].listNode = pnode; 1250 palette.entry[idx].numPixels = numPixels; 1251 1252 return (++paletteNumColors); 1253 } 1254 1255 1256 /* 1257 * Converting 32-bit color samples into 24-bit colors. 1258 * Should be called only when redMax, greenMax and blueMax are 255. 1259 * Color components assumed to be byte-aligned. 1260 */ 1261 1262 static void Pack24(buf, fmt, count) 1263 char *buf; 1264 rfbPixelFormat *fmt; 1265 int count; 1266 { 1267 CARD32 *buf32; 1268 CARD32 pix; 1269 int r_shift, g_shift, b_shift; 1270 1271 buf32 = (CARD32 *)buf; 1272 1273 if (!rfbServerFormat.bigEndian == !fmt->bigEndian) { 1274 r_shift = fmt->redShift; 1275 g_shift = fmt->greenShift; 1276 b_shift = fmt->blueShift; 1277 } else { 1278 r_shift = 24 - fmt->redShift; 1279 g_shift = 24 - fmt->greenShift; 1280 b_shift = 24 - fmt->blueShift; 1281 } 1282 1283 while (count--) { 1284 pix = *buf32++; 1285 *buf++ = (char)(pix >> r_shift); 1286 *buf++ = (char)(pix >> g_shift); 1287 *buf++ = (char)(pix >> b_shift); 1288 } 1289 } 1290 1291 1292 /* 1293 * Converting truecolor samples into palette indices. 1294 */ 1295 1296 #define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ 1297 \ 1298 static void \ 1299 EncodeIndexedRect##bpp(buf, count) \ 1300 CARD8 *buf; \ 1301 int count; \ 1302 { \ 1303 COLOR_LIST *pnode; \ 1304 CARD##bpp *src; \ 1305 CARD##bpp rgb; \ 1306 int rep = 0; \ 1307 \ 1308 src = (CARD##bpp *) buf; \ 1309 \ 1310 while (count--) { \ 1311 rgb = *src++; \ 1312 while (count && *src == rgb) { \ 1313 rep++, src++, count--; \ 1314 } \ 1315 pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \ 1316 while (pnode != NULL) { \ 1317 if ((CARD##bpp)pnode->rgb == rgb) { \ 1318 *buf++ = (CARD8)pnode->idx; \ 1319 while (rep) { \ 1320 *buf++ = (CARD8)pnode->idx; \ 1321 rep--; \ 1322 } \ 1323 break; \ 1324 } \ 1325 pnode = pnode->next; \ 1326 } \ 1327 } \ 1328 } 1329 1330 DEFINE_IDX_ENCODE_FUNCTION(16) 1331 DEFINE_IDX_ENCODE_FUNCTION(32) 1332 1333 #define DEFINE_MONO_ENCODE_FUNCTION(bpp) \ 1334 \ 1335 static void \ 1336 EncodeMonoRect##bpp(buf, w, h) \ 1337 CARD8 *buf; \ 1338 int w, h; \ 1339 { \ 1340 CARD##bpp *ptr; \ 1341 CARD##bpp bg; \ 1342 unsigned int value, mask; \ 1343 int aligned_width; \ 1344 int x, y, bg_bits; \ 1345 \ 1346 ptr = (CARD##bpp *) buf; \ 1347 bg = (CARD##bpp) monoBackground; \ 1348 aligned_width = w - w % 8; \ 1349 \ 1350 for (y = 0; y < h; y++) { \ 1351 for (x = 0; x < aligned_width; x += 8) { \ 1352 for (bg_bits = 0; bg_bits < 8; bg_bits++) { \ 1353 if (*ptr++ != bg) \ 1354 break; \ 1355 } \ 1356 if (bg_bits == 8) { \ 1357 *buf++ = 0; \ 1358 continue; \ 1359 } \ 1360 mask = 0x80 >> bg_bits; \ 1361 value = mask; \ 1362 for (bg_bits++; bg_bits < 8; bg_bits++) { \ 1363 mask >>= 1; \ 1364 if (*ptr++ != bg) { \ 1365 value |= mask; \ 1366 } \ 1367 } \ 1368 *buf++ = (CARD8)value; \ 1369 } \ 1370 \ 1371 mask = 0x80; \ 1372 value = 0; \ 1373 if (x >= w) \ 1374 continue; \ 1375 \ 1376 for (; x < w; x++) { \ 1377 if (*ptr++ != bg) { \ 1378 value |= mask; \ 1379 } \ 1380 mask >>= 1; \ 1381 } \ 1382 *buf++ = (CARD8)value; \ 1383 } \ 1384 } 1385 1386 DEFINE_MONO_ENCODE_FUNCTION(8) 1387 DEFINE_MONO_ENCODE_FUNCTION(16) 1388 DEFINE_MONO_ENCODE_FUNCTION(32) 1389 1390 /* 1391 * JPEG compression stuff. 1392 */ 1393 1394 static unsigned long jpegDstDataLen; 1395 static tjhandle j=NULL; 1396 1397 static Bool 1398 SendJpegRect(cl, x, y, w, h, quality) 1399 rfbClientPtr cl; 1400 int x, y, w, h; 1401 int quality; 1402 { 1403 int dy; 1404 unsigned char *srcbuf; 1405 int ps=rfbServerFormat.bitsPerPixel/8; 1406 int subsamp=subsampLevel2tjsubsamp[subsampLevel]; 1407 unsigned long size=0; 1408 int flags=0, pitch; 1409 unsigned char *tmpbuf=NULL; 1410 1411 if (rfbServerFormat.bitsPerPixel == 8) 1412 return SendFullColorRect(cl, w, h); 1413 1414 1415 if(ps<2) { 1416 rfbLog("Error: JPEG requires 16-bit, 24-bit, or 32-bit pixel format.\n"); 1417 return 0; 1418 } 1419 if(!j) { 1420 if((j=tjInitCompress())==NULL) { 1421 rfbLog("JPEG Error: %s\n", tjGetErrorStr()); return 0; 1422 } 1423 } 1424 1425 if (tightAfterBufSize < TJBUFSIZE(w,h)) { 1426 if (tightAfterBuf == NULL) 1427 tightAfterBuf = (char *)xalloc(TJBUFSIZE(w,h)); 1428 else 1429 tightAfterBuf = (char *)xrealloc(tightAfterBuf, 1430 TJBUFSIZE(w,h)); 1431 if(!tightAfterBuf) { 1432 rfbLog("Memory allocation failure!\n"); 1433 return 0; 1434 } 1435 tightAfterBufSize = TJBUFSIZE(w,h); 1436 } 1437 1438 if (ps == 2) { 1439 CARD16 *srcptr, pix; 1440 unsigned char *dst; 1441 int inRed, inGreen, inBlue, i, j; 1442 1443 if((tmpbuf=(unsigned char *)malloc(w*h*3))==NULL) 1444 rfbLog("Memory allocation failure!\n"); 1445 srcptr = (CARD16 *) 1446 &rfbScreen.pfbMemory[y * rfbScreen.paddedWidthInBytes + 1447 x * ps]; 1448 dst = tmpbuf; 1449 for(j=0; j<h; j++) { 1450 CARD16 *srcptr2=srcptr; 1451 unsigned char *dst2=dst; 1452 for(i=0; i<w; i++) { 1453 pix = *srcptr2++; 1454 inRed = (int) 1455 (pix >> rfbServerFormat.redShift & rfbServerFormat.redMax); 1456 inGreen = (int) 1457 (pix >> rfbServerFormat.greenShift & rfbServerFormat.greenMax); 1458 inBlue = (int) 1459 (pix >> rfbServerFormat.blueShift & rfbServerFormat.blueMax); 1460 *dst2++ = (CARD8)((inRed * 255 + rfbServerFormat.redMax / 2) / 1461 rfbServerFormat.redMax); 1462 *dst2++ = (CARD8)((inGreen * 255 + rfbServerFormat.greenMax / 2) / 1463 rfbServerFormat.greenMax); 1464 *dst2++ = (CARD8)((inBlue * 255 + rfbServerFormat.blueMax / 2) / 1465 rfbServerFormat.blueMax); 1466 } 1467 srcptr+=rfbScreen.paddedWidthInBytes/ps; 1468 dst+=w*3; 1469 } 1470 srcbuf = tmpbuf; 1471 pitch = w*3; 1472 ps = 3; 1473 } else { 1474 if(rfbServerFormat.bigEndian && ps==4) flags|=TJ_ALPHAFIRST; 1475 if(rfbServerFormat.redShift==16 && rfbServerFormat.blueShift==0) 1476 flags|=TJ_BGR; 1477 if(rfbServerFormat.bigEndian) flags^=TJ_BGR; 1478 srcbuf=(unsigned char *)&rfbScreen.pfbMemory[y * 1479 rfbScreen.paddedWidthInBytes + x * ps]; 1480 pitch=rfbScreen.paddedWidthInBytes; 1481 } 1482 1483 if(tjCompress(j, srcbuf, w, pitch, h, ps, (unsigned char *)tightAfterBuf, 1484 &size, subsamp, quality, flags)==-1) { 1485 rfbLog("JPEG Error: %s\n", tjGetErrorStr()); 1486 if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;} 1487 return 0; 1488 } 1489 jpegDstDataLen=(int)size; 1490 1491 if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;} 1492 1493 if (ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { 1494 if (!rfbSendUpdateBuf(cl)) 1495 return FALSE; 1496 } 1497 1498 updateBuf[ublen++] = (char)(rfbTightJpeg << 4); 1499 cl->rfbBytesSent[rfbEncodingTight]++; 1500 1501 return SendCompressedData(cl, tightAfterBuf, jpegDstDataLen); 1502 } 1503