blob: 620fb798133b79060256ad90c73a5ac5fc788eea [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
Peter Åstrandd69bcc42011-09-28 12:52:53 +00002 * Copyright 2004-2005 Cendio AB.
DRC33c15e32011-11-03 18:49:21 +00003 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
21//
22// Tight decoding functions.
23//
Pierre Ossmanbcc295e2014-02-12 13:16:43 +010024// This file is #included after having set the following macro:
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025// BPP - 8, 16 or 32
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000026
27#include <rdr/InStream.h>
28#include <rdr/ZlibInStream.h>
29#include <rfb/Exception.h>
30#include <assert.h>
31
32namespace rfb {
33
34// CONCAT2E concatenates its arguments, expanding them if they are macros
35
36#ifndef CONCAT2E
37#define CONCAT2(a,b) a##b
38#define CONCAT2E(a,b) CONCAT2(a,b)
39#endif
40
41#define PIXEL_T rdr::CONCAT2E(U,BPP)
42#define READ_PIXEL CONCAT2E(readOpaque,BPP)
DRC33c15e32011-11-03 18:49:21 +000043#define TIGHT_DECODE TightDecoder::CONCAT2E(tightDecode,BPP)
44#define DECOMPRESS_JPEG_RECT TightDecoder::CONCAT2E(DecompressJpegRect,BPP)
45#define FILTER_GRADIENT TightDecoder::CONCAT2E(FilterGradient,BPP)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000046
47#define TIGHT_MIN_TO_COMPRESS 12
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048
49// Main function implementing Tight decoder
50
DRC33c15e32011-11-03 18:49:21 +000051void TIGHT_DECODE (const Rect& r)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000053 bool cutZeros = false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000054#if BPP == 32
DRC33c15e32011-11-03 18:49:21 +000055 if (serverpf.is888()) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000056 cutZeros = true;
57 }
58#endif
59
60 rdr::U8 comp_ctl = is->readU8();
61
62 // Flush zlib streams if we are told by the server to do so.
63 for (int i = 0; i < 4; i++) {
64 if (comp_ctl & 1) {
65 zis[i].reset();
66 }
67 comp_ctl >>= 1;
68 }
69
70 // "Fill" compression type.
71 if (comp_ctl == rfbTightFill) {
72 PIXEL_T pix;
73 if (cutZeros) {
DRC33c15e32011-11-03 18:49:21 +000074 rdr::U8 bytebuf[3];
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000075 is->readBytes(bytebuf, 3);
DRC33c15e32011-11-03 18:49:21 +000076 serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1, NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000077 } else {
78 pix = is->READ_PIXEL();
79 }
Pierre Ossmanbcc295e2014-02-12 13:16:43 +010080 handler->fillRect(r, pix);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000081 return;
82 }
83
84 // "JPEG" compression type.
85 if (comp_ctl == rfbTightJpeg) {
DRC33c15e32011-11-03 18:49:21 +000086 DECOMPRESS_JPEG_RECT(r);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000087 return;
88 }
89
90 // Quit on unsupported compression type.
91 if (comp_ctl > rfbTightMaxSubencoding) {
92 throw Exception("TightDecoder: bad subencoding value received");
93 return;
94 }
95
96 // "Basic" compression type.
97 int palSize = 0;
98 static PIXEL_T palette[256];
99 bool useGradient = false;
100
101 if ((comp_ctl & rfbTightExplicitFilter) != 0) {
102 rdr::U8 filterId = is->readU8();
103
104 switch (filterId) {
105 case rfbTightFilterPalette:
106 palSize = is->readU8() + 1;
107 if (cutZeros) {
DRCa5004a32011-11-04 04:51:17 +0000108 rdr::U8 tightPalette[256 * 3];
109 is->readBytes(tightPalette, palSize * 3);
110 serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize, NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000111 } else {
DRCa5004a32011-11-04 04:51:17 +0000112 is->readBytes(palette, palSize * sizeof(PIXEL_T));
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000113 }
114 break;
115 case rfbTightFilterGradient:
116 useGradient = true;
117 break;
118 case rfbTightFilterCopy:
119 break;
120 default:
121 throw Exception("TightDecoder: unknown filter code received");
122 return;
123 }
124 }
125
126 int bppp = BPP;
127 if (palSize != 0) {
128 bppp = (palSize <= 2) ? 1 : 8;
129 } else if (cutZeros) {
130 bppp = 24;
131 }
132
133 // Determine if the data should be decompressed or just copied.
134 int rowSize = (r.width() * bppp + 7) / 8;
135 int dataSize = r.height() * rowSize;
136 int streamId = -1;
137 rdr::InStream *input;
138 if (dataSize < TIGHT_MIN_TO_COMPRESS) {
139 input = is;
140 } else {
Pierre Ossman7b5c0692014-03-17 14:35:51 +0100141 int length = readCompact(is);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000142 streamId = comp_ctl & 0x03;
143 zis[streamId].setUnderlying(is, length);
144 input = &zis[streamId];
145 }
146
DRCa5004a32011-11-04 04:51:17 +0000147 // Allocate netbuf and read in data
148 rdr::U8 *netbuf = new rdr::U8[dataSize];
149 if (!netbuf) {
150 throw Exception("rfb::TightDecoder::tightDecode unable to allocate buffer");
151 }
152 input->readBytes(netbuf, dataSize);
153
DRC33c15e32011-11-03 18:49:21 +0000154 PIXEL_T *buf;
155 int stride = r.width();
Pierre Ossman945cdda2014-01-28 14:13:12 +0100156 if (directDecode) buf = (PIXEL_T *)handler->getRawBufferRW(r, &stride);
DRC33c15e32011-11-03 18:49:21 +0000157 else buf = (PIXEL_T *)reader->getImageBuf(r.area());
158
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000159 if (palSize == 0) {
160 // Truecolor data
161 if (useGradient) {
162#if BPP == 32
163 if (cutZeros) {
DRCa5004a32011-11-04 04:51:17 +0000164 FilterGradient24(netbuf, buf, stride, r);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000165 } else
166#endif
DRC33c15e32011-11-03 18:49:21 +0000167 {
DRCa5004a32011-11-04 04:51:17 +0000168 FILTER_GRADIENT(netbuf, buf, stride, r);
DRC33c15e32011-11-03 18:49:21 +0000169 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170 } else {
DRC33c15e32011-11-03 18:49:21 +0000171 // Copy
172 int h = r.height();
173 PIXEL_T *ptr = buf;
DRCa5004a32011-11-04 04:51:17 +0000174 rdr::U8 *srcPtr = netbuf;
175 int w = r.width();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000176 if (cutZeros) {
DRC33c15e32011-11-03 18:49:21 +0000177 while (h > 0) {
DRCa5004a32011-11-04 04:51:17 +0000178 serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w, NULL);
179 ptr += stride;
Pierre Ossmane3cb4a22011-11-08 13:52:33 +0000180 srcPtr += w * 3;
DRC33c15e32011-11-03 18:49:21 +0000181 h--;
Pierre Ossman7c4efd72010-09-30 11:30:20 +0000182 }
183 } else {
DRC33c15e32011-11-03 18:49:21 +0000184 while (h > 0) {
DRC77b50282011-11-09 18:18:11 +0000185 memcpy(ptr, srcPtr, w * sizeof(PIXEL_T));
DRC33c15e32011-11-03 18:49:21 +0000186 ptr += stride;
DRCa5004a32011-11-04 04:51:17 +0000187 srcPtr += w * sizeof(PIXEL_T);
DRC33c15e32011-11-03 18:49:21 +0000188 h--;
189 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000190 }
191 }
192 } else {
DRC33c15e32011-11-03 18:49:21 +0000193 // Indexed color
194 int x, h = r.height(), w = r.width(), b, pad = stride - w;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000195 PIXEL_T *ptr = buf;
DRCa5004a32011-11-04 04:51:17 +0000196 rdr::U8 bits, *srcPtr = netbuf;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000197 if (palSize <= 2) {
198 // 2-color palette
DRC33c15e32011-11-03 18:49:21 +0000199 while (h > 0) {
200 for (x = 0; x < w / 8; x++) {
DRCa5004a32011-11-04 04:51:17 +0000201 bits = *srcPtr++;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000202 for (b = 7; b >= 0; b--) {
203 *ptr++ = palette[bits >> b & 1];
DRC33c15e32011-11-03 18:49:21 +0000204 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000205 }
DRC33c15e32011-11-03 18:49:21 +0000206 if (w % 8 != 0) {
DRCa5004a32011-11-04 04:51:17 +0000207 bits = *srcPtr++;
DRC33c15e32011-11-03 18:49:21 +0000208 for (b = 7; b >= 8 - w % 8; b--) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000209 *ptr++ = palette[bits >> b & 1];
210 }
211 }
DRC33c15e32011-11-03 18:49:21 +0000212 ptr += pad;
213 h--;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000214 }
215 } else {
216 // 256-color palette
DRC33c15e32011-11-03 18:49:21 +0000217 while (h > 0) {
218 PIXEL_T *endOfRow = ptr + w;
219 while (ptr < endOfRow) {
DRCa5004a32011-11-04 04:51:17 +0000220 *ptr++ = palette[*srcPtr++];
DRC33c15e32011-11-03 18:49:21 +0000221 }
222 ptr += pad;
223 h--;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000224 }
225 }
226 }
227
Pierre Ossman945cdda2014-01-28 14:13:12 +0100228 if (directDecode) handler->releaseRawBuffer(r);
Pierre Ossmanbcc295e2014-02-12 13:16:43 +0100229 else handler->imageRect(r, buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000230
DRCa5004a32011-11-04 04:51:17 +0000231 delete [] netbuf;
232
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000233 if (streamId != -1) {
234 zis[streamId].reset();
235 }
236}
237
DRC33c15e32011-11-03 18:49:21 +0000238void
239DECOMPRESS_JPEG_RECT(const Rect& r)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000240{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000241 // Read length
Pierre Ossman7b5c0692014-03-17 14:35:51 +0100242 int compressedLen = readCompact(is);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000243 if (compressedLen <= 0) {
244 throw Exception("Incorrect data received from the server.\n");
245 }
246
247 // Allocate netbuf and read in data
248 rdr::U8* netbuf = new rdr::U8[compressedLen];
249 if (!netbuf) {
DRCa5004a32011-11-04 04:51:17 +0000250 throw Exception("rfb::TightDecoder::DecompressJpegRect unable to allocate buffer");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000251 }
252 is->readBytes(netbuf, compressedLen);
253
DRC33c15e32011-11-03 18:49:21 +0000254 // We always use direct decoding with JPEG images
255 int stride;
Pierre Ossman945cdda2014-01-28 14:13:12 +0100256 rdr::U8 *buf = handler->getRawBufferRW(r, &stride);
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100257 jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf);
Pierre Ossman945cdda2014-01-28 14:13:12 +0100258 handler->releaseRawBuffer(r);
DRCe420dcb2009-04-06 07:20:34 +0000259
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000260 delete [] netbuf;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000261}
262
263#if BPP == 32
264
DRC33c15e32011-11-03 18:49:21 +0000265void
DRCa5004a32011-11-04 04:51:17 +0000266TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride,
267 const Rect& r)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000268{
269 int x, y, c;
270 static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
271 static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
272 rdr::U8 pix[3];
273 int est[3];
274
275 memset(prevRow, 0, sizeof(prevRow));
276
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000277 // Set up shortcut variables
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000278 int rectHeight = r.height();
279 int rectWidth = r.width();
280
281 for (y = 0; y < rectHeight; y++) {
282 /* First pixel in a row */
283 for (c = 0; c < 3; c++) {
284 pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
285 thisRow[c] = pix[c];
286 }
DRC33c15e32011-11-03 18:49:21 +0000287 serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1, NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000288
289 /* Remaining pixels of a row */
290 for (x = 1; x < rectWidth; x++) {
291 for (c = 0; c < 3; c++) {
DRC33c15e32011-11-03 18:49:21 +0000292 est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
293 if (est[c] > 0xff) {
294 est[c] = 0xff;
295 } else if (est[c] < 0) {
296 est[c] = 0;
297 }
298 pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
299 thisRow[x*3+c] = pix[c];
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000300 }
DRC33c15e32011-11-03 18:49:21 +0000301 serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1, NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000302 }
303
304 memcpy(prevRow, thisRow, sizeof(prevRow));
305 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000306}
307
308#endif
309
DRC33c15e32011-11-03 18:49:21 +0000310void
DRCa5004a32011-11-04 04:51:17 +0000311FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000312{
313 int x, y, c;
314 static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
315 static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000316 rdr::U8 pix[3];
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000317 int est[3];
318
319 memset(prevRow, 0, sizeof(prevRow));
320
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000321 // Set up shortcut variables
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000322 int rectHeight = r.height();
323 int rectWidth = r.width();
324
325 for (y = 0; y < rectHeight; y++) {
326 /* First pixel in a row */
DRC33c15e32011-11-03 18:49:21 +0000327 serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1, NULL);
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000328 for (c = 0; c < 3; c++)
329 pix[c] += prevRow[c];
330
331 memcpy(thisRow, pix, sizeof(pix));
332
DRC33c15e32011-11-03 18:49:21 +0000333 serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1, NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000334
335 /* Remaining pixels of a row */
336 for (x = 1; x < rectWidth; x++) {
337 for (c = 0; c < 3; c++) {
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000338 est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
339 if (est[c] > 255) {
340 est[c] = 255;
341 } else if (est[c] < 0) {
342 est[c] = 0;
343 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000344 }
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000345
DRC33c15e32011-11-03 18:49:21 +0000346 serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1, NULL);
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000347 for (c = 0; c < 3; c++)
348 pix[c] += est[c];
349
350 memcpy(&thisRow[x*3], pix, sizeof(pix));
351
DRC33c15e32011-11-03 18:49:21 +0000352 serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1, NULL);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000353 }
354
355 memcpy(prevRow, thisRow, sizeof(prevRow));
356 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000357}
358
359#undef TIGHT_MIN_TO_COMPRESS
DRC33c15e32011-11-03 18:49:21 +0000360#undef FILTER_GRADIENT
361#undef DECOMPRESS_JPEG_RECT
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000362#undef TIGHT_DECODE
363#undef READ_PIXEL
364#undef PIXEL_T
365}