2
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
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.
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.
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,
21
* tight.c - handle ``tight'' encoding.
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.
30
#define TIGHT_MIN_TO_COMPRESS 12
32
#define CARDBPP CONCAT2E(CARD,BPP)
33
#define filterPtrBPP CONCAT2E(filterPtr,BPP)
35
#define HandleTightBPP CONCAT2E(HandleTight,BPP)
36
#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
37
#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
38
#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
39
#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
40
#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
41
#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
42
#define FillRectangleBPP CONCAT2E(FillRectangle,BPP)
45
#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
50
#define RGB_TO_PIXEL(bpp,r,g,b) \
51
(((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift | \
52
((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift | \
53
((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift)
55
#define RGB24_TO_PIXEL(bpp,r,g,b) \
56
((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \
57
<< myFormat.redShift | \
58
(((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \
59
<< myFormat.greenShift | \
60
(((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \
61
<< myFormat.blueShift)
63
#define RGB24_TO_PIXEL32(r,g,b) \
64
(((CARD32)(r) & 0xFF) << myFormat.redShift | \
65
((CARD32)(g) & 0xFF) << myFormat.greenShift | \
66
((CARD32)(b) & 0xFF) << myFormat.blueShift)
70
/* Type declarations */
72
typedef void (*filterPtrBPP)(int, CARDBPP *);
76
static int InitFilterCopyBPP (int rw, int rh);
77
static int InitFilterPaletteBPP (int rw, int rh);
78
static int InitFilterGradientBPP (int rw, int rh);
79
static void FilterCopyBPP (int numRows, CARDBPP *destBuffer);
80
static void FilterPaletteBPP (int numRows, CARDBPP *destBuffer);
81
static void FilterGradientBPP (int numRows, CARDBPP *destBuffer);
83
static Bool DecompressJpegRectBPP(int x, int y, int w, int h);
88
HandleTightBPP (int rx, int ry, int rw, int rh)
94
filterPtrBPP filterFn;
97
int err, stream_id, compressedLen, bitsPixel;
98
int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
101
if (!ReadFromRFBServer((char *)&comp_ctl, 1))
104
/* Flush zlib streams if we are told by the server to do so. */
105
for (stream_id = 0; stream_id < 4; stream_id++) {
106
if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
107
if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
108
zlibStream[stream_id].msg != NULL)
109
fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
110
zlibStreamActive[stream_id] = False;
115
/* Handle solid rectangles. */
116
if (comp_ctl == rfbTightFill) {
118
if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
119
myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
120
if (!ReadFromRFBServer(buffer, 3))
122
fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]);
124
if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
128
if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
133
FillRectangleBPP(fill_colour, rx, ry, rw, rh);
135
SyncScreenRegion(rx, ry, rw, rh);
140
if (comp_ctl == rfbTightJpeg) {
141
fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
145
if (comp_ctl == rfbTightJpeg) {
146
return DecompressJpegRectBPP(rx, ry, rw, rh);
150
/* Quit on unsupported subencoding value. */
151
if (comp_ctl > rfbTightMaxSubencoding) {
152
fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
157
* Here primary compression mode handling begins.
158
* Data was processed with optional filter + zlib compression.
161
/* First, we should identify a filter to use. */
162
if ((comp_ctl & rfbTightExplicitFilter) != 0) {
163
if (!ReadFromRFBServer((char*)&filter_id, 1))
167
case rfbTightFilterCopy:
168
filterFn = FilterCopyBPP;
169
bitsPixel = InitFilterCopyBPP(rw, rh);
171
case rfbTightFilterPalette:
172
filterFn = FilterPaletteBPP;
173
bitsPixel = InitFilterPaletteBPP(rw, rh);
175
case rfbTightFilterGradient:
176
filterFn = FilterGradientBPP;
177
bitsPixel = InitFilterGradientBPP(rw, rh);
180
fprintf(stderr, "Tight encoding: unknown filter code received.\n");
184
filterFn = FilterCopyBPP;
185
bitsPixel = InitFilterCopyBPP(rw, rh);
187
if (bitsPixel == 0) {
188
fprintf(stderr, "Tight encoding: error receiving palette.\n");
192
/* Determine if the data should be decompressed or just copied. */
193
rowSize = (rw * bitsPixel + 7) / 8;
194
if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
195
if (!ReadFromRFBServer((char*)buffer, rh * rowSize))
198
buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4];
199
filterFn(rh, (CARDBPP *)buffer2);
200
CopyDataToScreen(buffer2, rx, ry, rw, rh);
205
/* Read the length (1..3 bytes) of compressed data following. */
206
compressedLen = (int)ReadCompactLen();
207
if (compressedLen <= 0) {
208
fprintf(stderr, "Incorrect data received from the server.\n");
212
/* Now let's initialize compression stream if needed. */
213
stream_id = comp_ctl & 0x03;
214
zs = &zlibStream[stream_id];
215
if (!zlibStreamActive[stream_id]) {
219
err = inflateInit(zs);
222
fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
225
zlibStreamActive[stream_id] = True;
228
/* Read, decode and draw actual pixel data in a loop. */
230
bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
231
buffer2 = &buffer[bufferSize];
232
if (rowSize > bufferSize) {
233
/* Should be impossible when BUFFER_SIZE >= 16384 */
234
fprintf(stderr, "Internal error: incorrect buffer size.\n");
241
while (compressedLen > 0) {
242
if (compressedLen > ZLIB_BUFFER_SIZE)
243
portionLen = ZLIB_BUFFER_SIZE;
245
portionLen = compressedLen;
247
if (!ReadFromRFBServer((char*)zlib_buffer, portionLen))
250
compressedLen -= portionLen;
252
zs->next_in = (Bytef *)zlib_buffer;
253
zs->avail_in = portionLen;
256
zs->next_out = (Bytef *)&buffer[extraBytes];
257
zs->avail_out = bufferSize - extraBytes;
259
err = inflate(zs, Z_SYNC_FLUSH);
260
if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */
262
if (err != Z_OK && err != Z_STREAM_END) {
263
if (zs->msg != NULL) {
264
fprintf(stderr, "Inflate error: %s.\n", zs->msg);
266
fprintf(stderr, "Inflate error: %d.\n", err);
271
numRows = (bufferSize - zs->avail_out) / rowSize;
273
filterFn(numRows, (CARDBPP *)buffer2);
275
extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
277
memcpy(buffer, &buffer[numRows * rowSize], extraBytes);
279
CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows);
280
rowsProcessed += numRows;
282
while (zs->avail_out == 0);
285
if (rowsProcessed != rh) {
286
fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
293
/*----------------------------------------------------------------------------
300
The following variables are defined in rfbproto.c:
301
static Bool cutZeros;
302
static int rectWidth, rectColors;
303
static CARD8 tightPalette[256*4];
304
static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
308
InitFilterCopyBPP (int rw, int rh)
313
if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
314
myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
326
FilterCopyBPP (int numRows, CARDBPP *dst)
333
for (y = 0; y < numRows; y++) {
334
for (x = 0; x < rectWidth; x++) {
336
RGB24_TO_PIXEL32(buffer[(y*rectWidth+x)*3],
337
buffer[(y*rectWidth+x)*3+1],
338
buffer[(y*rectWidth+x)*3+2]);
345
memcpy (dst, buffer, numRows * rectWidth * (BPP / 8));
349
InitFilterGradientBPP (int rw, int rh)
353
bits = InitFilterCopyBPP(rw, rh);
355
memset(tightPrevRow, 0, rw * 3);
357
memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
365
FilterGradient24 (int numRows, CARD32 *dst)
368
CARD8 thisRow[2048*3];
372
for (y = 0; y < numRows; y++) {
374
/* First pixel in a row */
375
for (c = 0; c < 3; c++) {
376
pix[c] = tightPrevRow[c] + buffer[y*rectWidth*3+c];
379
dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
381
/* Remaining pixels of a row */
382
for (x = 1; x < rectWidth; x++) {
383
for (c = 0; c < 3; c++) {
384
est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
385
(int)tightPrevRow[(x-1)*3+c];
388
} else if (est[c] < 0x00) {
391
pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c];
392
thisRow[x*3+c] = pix[c];
394
dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
397
memcpy(tightPrevRow, thisRow, rectWidth * 3);
404
FilterGradientBPP (int numRows, CARDBPP *dst)
407
CARDBPP *src = (CARDBPP *)buffer;
408
CARD16 *thatRow = (CARD16 *)tightPrevRow;
409
CARD16 thisRow[2048*3];
417
FilterGradient24(numRows, dst);
422
max[0] = myFormat.redMax;
423
max[1] = myFormat.greenMax;
424
max[2] = myFormat.blueMax;
426
shift[0] = myFormat.redShift;
427
shift[1] = myFormat.greenShift;
428
shift[2] = myFormat.blueShift;
430
for (y = 0; y < numRows; y++) {
432
/* First pixel in a row */
433
for (c = 0; c < 3; c++) {
434
pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
437
dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
439
/* Remaining pixels of a row */
440
for (x = 1; x < rectWidth; x++) {
441
for (c = 0; c < 3; c++) {
442
est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
443
if (est[c] > (int)max[c]) {
444
est[c] = (int)max[c];
445
} else if (est[c] < 0) {
448
pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
449
thisRow[x*3+c] = pix[c];
451
dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
453
memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
458
InitFilterPaletteBPP (int rw, int rh)
462
CARDBPP *palette = (CARDBPP *)tightPalette;
466
if (!ReadFromRFBServer((char*)&numColors, 1))
469
rectColors = (int)numColors;
470
if (++rectColors < 2)
474
if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
475
myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
476
if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3))
478
for (i = rectColors - 1; i >= 0; i--) {
479
palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
481
tightPalette[i*3+2]);
483
return (rectColors == 2) ? 1 : 8;
487
if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8)))
490
return (rectColors == 2) ? 1 : 8;
494
FilterPaletteBPP (int numRows, CARDBPP *dst)
497
CARD8 *src = (CARD8 *)buffer;
498
CARDBPP *palette = (CARDBPP *)tightPalette;
500
if (rectColors == 2) {
501
w = (rectWidth + 7) / 8;
502
for (y = 0; y < numRows; y++) {
503
for (x = 0; x < rectWidth / 8; x++) {
504
for (b = 7; b >= 0; b--)
505
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
507
for (b = 7; b >= 8 - rectWidth % 8; b--) {
508
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
512
for (y = 0; y < numRows; y++)
513
for (x = 0; x < rectWidth; x++)
514
dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
520
/*----------------------------------------------------------------------------
522
* JPEG decompression.
527
The following variables are defined in rfbproto.c:
528
static Bool jpegError;
529
static struct jpeg_source_mgr jpegSrcManager;
530
static JOCTET *jpegBufferPtr;
531
static size_t *jpegBufferLen;
535
DecompressJpegRectBPP(int x, int y, int w, int h)
537
struct jpeg_decompress_struct cinfo;
538
struct jpeg_error_mgr jerr;
540
CARD8 *compressedData;
542
JSAMPROW rowPointer[1];
545
compressedLen = (int)ReadCompactLen();
546
if (compressedLen <= 0) {
547
fprintf(stderr, "Incorrect data received from the server.\n");
551
if (compressedLen > MAX_JPEG_SIZE) {
552
fprintf(stderr, "To large data announced by the server.\n");
556
compressedData = malloc(compressedLen);
557
if (compressedData == NULL) {
558
fprintf(stderr, "Memory allocation error.\n");
562
if (!ReadFromRFBServer((char*)compressedData, compressedLen)) {
563
free(compressedData);
567
cinfo.err = jpeg_std_error(&jerr);
568
jpeg_create_decompress(&cinfo);
570
JpegSetSrcManager(&cinfo, compressedData, compressedLen);
572
jpeg_read_header(&cinfo, TRUE);
573
cinfo.out_color_space = JCS_RGB;
575
jpeg_start_decompress(&cinfo);
576
if (cinfo.output_width != w || cinfo.output_height != h ||
577
cinfo.output_components != 3) {
578
fprintf(stderr, "Tight Encoding: Wrong JPEG data received.\n");
579
jpeg_destroy_decompress(&cinfo);
580
free(compressedData);
584
rowPointer[0] = (JSAMPROW)buffer;
586
while (cinfo.output_scanline < cinfo.output_height) {
587
jpeg_read_scanlines(&cinfo, rowPointer, 1);
591
pixelPtr = (CARDBPP *)&buffer[BUFFER_SIZE / 2];
592
for (dx = 0; dx < w; dx++) {
594
RGB24_TO_PIXEL(BPP, buffer[dx*3], buffer[dx*3+1], buffer[dx*3+2]);
596
CopyDataToScreen(&buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
601
jpeg_finish_decompress(&cinfo);
603
jpeg_destroy_decompress(&cinfo);
604
free(compressedData);