basic framing for tight is working (decode not complete)
This commit is contained in:
parent
682f33a790
commit
de84e09854
183
include/rfb.js
183
include/rfb.js
|
@ -46,6 +46,7 @@ var that = {}, // Public API methods
|
||||||
// In preference order
|
// In preference order
|
||||||
encodings = [
|
encodings = [
|
||||||
['COPYRECT', 0x01 ],
|
['COPYRECT', 0x01 ],
|
||||||
|
['TIGHT', 0x07 ],
|
||||||
['TIGHT_PNG', -260 ],
|
['TIGHT_PNG', -260 ],
|
||||||
['HEXTILE', 0x05 ],
|
['HEXTILE', 0x05 ],
|
||||||
['RRE', 0x02 ],
|
['RRE', 0x02 ],
|
||||||
|
@ -87,7 +88,9 @@ var that = {}, // Public API methods
|
||||||
encoding : 0,
|
encoding : 0,
|
||||||
subencoding : -1,
|
subencoding : -1,
|
||||||
background : null,
|
background : null,
|
||||||
imgQ : [] // TIGHT_PNG image queue
|
imgQ : [], // TIGHT_PNG image queue
|
||||||
|
zlibs : [], // TIGHT zlib streams
|
||||||
|
palette : null
|
||||||
},
|
},
|
||||||
|
|
||||||
fb_Bpp = 4,
|
fb_Bpp = 4,
|
||||||
|
@ -296,6 +299,7 @@ init_vars = function() {
|
||||||
FBU.lines = 0; // RAW
|
FBU.lines = 0; // RAW
|
||||||
FBU.tiles = 0; // HEXTILE
|
FBU.tiles = 0; // HEXTILE
|
||||||
FBU.imgQ = []; // TIGHT_PNG image queue
|
FBU.imgQ = []; // TIGHT_PNG image queue
|
||||||
|
FBU.streams = []; // TIGHT zlib encoders
|
||||||
mouse_buttonMask = 0;
|
mouse_buttonMask = 0;
|
||||||
mouse_arr = [];
|
mouse_arr = [];
|
||||||
|
|
||||||
|
@ -303,6 +307,11 @@ init_vars = function() {
|
||||||
for (i=0; i < encodings.length; i+=1) {
|
for (i=0; i < encodings.length; i+=1) {
|
||||||
encStats[encodings[i][1]][0] = 0;
|
encStats[encodings[i][1]][0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i=0; i < 4; i++) {
|
||||||
|
FBU.zlibs[i] = new TINF();
|
||||||
|
FBU.zlibs[i].init();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Print statistics
|
// Print statistics
|
||||||
|
@ -1257,6 +1266,176 @@ encHandlers.HEXTILE = function display_hextile() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
encHandlers.TIGHT = function display_tight() {
|
||||||
|
Util.Debug(">> display_tight");
|
||||||
|
var ctl, cmode, clength, getCLength, color, img, data;
|
||||||
|
var filterId = -1, resetStreams = 0, streamId = -1;
|
||||||
|
var rQ = ws.get_rQ(), rQi = ws.get_rQi();
|
||||||
|
|
||||||
|
FBU.bytes = 1; // compression-control byte
|
||||||
|
if (ws.rQwait("TIGHT compression-control", FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
// Get 'compact length' header and data size
|
||||||
|
getCLength = function (arr) {
|
||||||
|
var header = 1, data = 0;
|
||||||
|
data += arr[0] & 0x7f;
|
||||||
|
if (arr[0] & 0x80) {
|
||||||
|
header += 1;
|
||||||
|
data += (arr[1] & 0x7f) << 7;
|
||||||
|
if (arr[1] & 0x80) {
|
||||||
|
header += 1;
|
||||||
|
data += arr[2] << 14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [header, data];
|
||||||
|
};
|
||||||
|
|
||||||
|
var decompress = function(data) {
|
||||||
|
// TODO: process resetStreams here
|
||||||
|
var uncompressed = FBU.zlibs[streamId].uncompress(data, 0);
|
||||||
|
/*if (uncompressed.status != 0)
|
||||||
|
throw("Invalid data in zlib stream");*/
|
||||||
|
return uncompressed.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handlePalette = function() {
|
||||||
|
var numColors = rQ[rQi + 2] + 1;
|
||||||
|
var paletteSize = numColors * fb_depth;
|
||||||
|
FBU.bytes += paletteSize;
|
||||||
|
|
||||||
|
if (ws.rQwait("TIGHT palette " + cmode, FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
FBU.palette = ws.rQslice(3, 3 + paletteSize);
|
||||||
|
|
||||||
|
var bpp = (numColors <= 2) ? 1 : 8;
|
||||||
|
var rowSize = Math.floor((FBU.width * bpp + 7) / 8);
|
||||||
|
if (rowSize * FBU.height < 12)
|
||||||
|
clength = [0, rowSize * FBU.height];
|
||||||
|
else
|
||||||
|
clength = getCLength(ws.rQslice(3 + paletteSize, 3 + paletteSize + 3));
|
||||||
|
FBU.bytes += clength[0] + clength[1];
|
||||||
|
if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
// Shift ctl, filter id, num colors, palette entries, and clength off
|
||||||
|
ws.rQshiftBytes(3 + paletteSize + clength[0]);
|
||||||
|
|
||||||
|
// Process data
|
||||||
|
if (clength[1] < 12)
|
||||||
|
data = ws.rQshiftBytes(clength[1]);
|
||||||
|
else
|
||||||
|
data = decompress(ws.rQshiftBytes(clength[1]));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handleCopy = function() {
|
||||||
|
var uncompressedSize = FBU.width * FBU.height * fb_depth;
|
||||||
|
if (uncompressedSize < 12)
|
||||||
|
clength = [0, uncompressedSize];
|
||||||
|
else
|
||||||
|
clength = getCLength(ws.rQslice(1, 4));
|
||||||
|
FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + zlib-data
|
||||||
|
if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
ws.rQshiftBytes(1 + clength[0]); // ctl + clength
|
||||||
|
if (clength[1] < 12)
|
||||||
|
data = ws.rQshiftBytes(clength[1]);
|
||||||
|
else
|
||||||
|
data = decompress(ws.rQshiftBytes(clength[1]));
|
||||||
|
|
||||||
|
FBU.imgQ.push({
|
||||||
|
'type': 'rgb',
|
||||||
|
'img': {'complete': true, 'data': data},
|
||||||
|
'x': FBU.x,
|
||||||
|
'y': FBU.y,
|
||||||
|
'width': FBU.width,
|
||||||
|
'height': FBU.height});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctl = ws.rQpeek8();
|
||||||
|
|
||||||
|
// Keep tight reset bits
|
||||||
|
resetStreams = ctl & 0xF;
|
||||||
|
|
||||||
|
// Figure out filter
|
||||||
|
ctl = ctl >> 4;
|
||||||
|
streamId = ctl & 0x3;
|
||||||
|
|
||||||
|
if (ctl == 0x08) cmode = "fill";
|
||||||
|
else if (ctl == 0x09) cmode = "jpeg";
|
||||||
|
else if (ctl & 0x04) cmode = "filter";
|
||||||
|
else if (ctl < 0x04) cmode = "copy";
|
||||||
|
else throw("Illegal tight compression received, ctl: " + ctl);
|
||||||
|
|
||||||
|
switch (cmode) {
|
||||||
|
// fill uses fb_depth because TPIXELs drop the padding byte
|
||||||
|
case "fill": FBU.bytes += fb_depth; break; // TPIXEL
|
||||||
|
case "jpeg": FBU.bytes += 3; break; // max clength
|
||||||
|
case "filter": FBU.bytes += 2; break; // filter id + num colors if palette
|
||||||
|
case "copy": break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
//Util.Debug(" ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
|
||||||
|
//Util.Debug(" cmode: " + cmode);
|
||||||
|
|
||||||
|
// Determine FBU.bytes
|
||||||
|
switch (cmode) {
|
||||||
|
case "fill":
|
||||||
|
ws.rQshift8(); // shift off ctl
|
||||||
|
color = ws.rQshiftBytes(fb_depth);
|
||||||
|
FBU.imgQ.push({
|
||||||
|
'type': 'fill',
|
||||||
|
'img': {'complete': true},
|
||||||
|
'x': FBU.x,
|
||||||
|
'y': FBU.y,
|
||||||
|
'width': FBU.width,
|
||||||
|
'height': FBU.height,
|
||||||
|
'color': color});
|
||||||
|
break;
|
||||||
|
case "jpeg":
|
||||||
|
clength = getCLength(ws.rQslice(1, 4));
|
||||||
|
FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + jpeg-data
|
||||||
|
if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
// We have everything, render it
|
||||||
|
//Util.Debug(" png, ws.rQlen(): " + ws.rQlen() + ", clength[0]: " + clength[0] + ", clength[1]: " + clength[1]);
|
||||||
|
ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length
|
||||||
|
img = new Image();
|
||||||
|
//img.onload = scan_tight_imgQ;
|
||||||
|
FBU.imgQ.push({
|
||||||
|
'type': 'img',
|
||||||
|
'img': img,
|
||||||
|
'x': FBU.x,
|
||||||
|
'y': FBU.y});
|
||||||
|
img.src = "data:image/" + cmode +
|
||||||
|
extract_data_uri(ws.rQshiftBytes(clength[1]));
|
||||||
|
img = null;
|
||||||
|
break;
|
||||||
|
case "filter":
|
||||||
|
filterId = rQ[rQi + 1];
|
||||||
|
if (filterId == 1) {
|
||||||
|
if (!handlePalette()) { return false; }
|
||||||
|
} else {
|
||||||
|
// Filter 0, Copy could be valid here, but servers don't send it as an explicit filter
|
||||||
|
// Filter 2, Gradient is valid but not used if jpeg is enabled
|
||||||
|
throw("Unsupported tight subencoding received, filter: " + filterId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "copy":
|
||||||
|
if (!handleCopy()) { return false; }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FBU.bytes = 0;
|
||||||
|
FBU.rects -= 1;
|
||||||
|
//Util.Debug(" ending ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
|
||||||
|
//Util.Debug("<< display_tight_png");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
encHandlers.TIGHT_PNG = function display_tight_png() {
|
encHandlers.TIGHT_PNG = function display_tight_png() {
|
||||||
//Util.Debug(">> display_tight_png");
|
//Util.Debug(">> display_tight_png");
|
||||||
var ctl, cmode, clength, getCLength, color, img;
|
var ctl, cmode, clength, getCLength, color, img;
|
||||||
|
@ -1360,6 +1539,8 @@ scan_tight_imgQ = function() {
|
||||||
data = imgQ.shift();
|
data = imgQ.shift();
|
||||||
if (data.type === 'fill') {
|
if (data.type === 'fill') {
|
||||||
display.fillRect(data.x, data.y, data.width, data.height, data.color);
|
display.fillRect(data.x, data.y, data.width, data.height, data.color);
|
||||||
|
} else if (data.type === 'rgb') {
|
||||||
|
// TODO
|
||||||
} else {
|
} else {
|
||||||
ctx.drawImage(data.img, data.x, data.y);
|
ctx.drawImage(data.img, data.x, data.y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ function get_INCLUDE_URI() {
|
||||||
extra += start + "input.js" + end;
|
extra += start + "input.js" + end;
|
||||||
extra += start + "display.js" + end;
|
extra += start + "display.js" + end;
|
||||||
extra += start + "rfb.js" + end;
|
extra += start + "rfb.js" + end;
|
||||||
|
extra += start + "jsunzip.js" + end;
|
||||||
|
|
||||||
document.write(extra);
|
document.write(extra);
|
||||||
}());
|
}());
|
||||||
|
|
Loading…
Reference in New Issue