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
rfbNumCodedRectsTight(cl,x,y,w,h)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
rfbSendRectEncodingTight(cl,x,y,w,h)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
FindBestSolidArea(x,y,w,h,colorValue,w_ptr,h_ptr)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
ExtendSolidArea(x,y,w,h,colorValue,x_ptr,y_ptr,w_ptr,h_ptr)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
CheckSolidTile(x,y,w,h,colorPtr,needSameColor)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
SendSubrect(cl,x,y,w,h)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
SendTightHeader(cl,x,y,w,h)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
SendSolidRect(cl)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
SendMonoRect(cl,w,h)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
SendIndexedRect(cl,w,h)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
SendFullColorRect(cl,w,h)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
CompressData(cl,streamId,dataLen,zlibLevel,zlibStrategy)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
SendCompressedData(cl,buf,compressedLen)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
FillPalette8(count)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
PaletteReset(void)1183 PaletteReset(void)
1184 {
1185 paletteNumColors = 0;
1186 memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
1187 }
1188
1189 static int
PaletteInsert(rgb,numPixels,bpp)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
Pack24(buf,fmt,count)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
SendJpegRect(cl,x,y,w,h,quality)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