JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1/*2 * noVNC: HTML5 VNC client3 * Copyright (C) 2019 The noVNC authors4 * Licensed under MPL 2.0 (see LICENSE.txt)5 *6 * See README.md for usage and integration instructions.7 *8 */910export default class JPEGDecoder {11 constructor() {12 // RealVNC will reuse the quantization tables13 // and Huffman tables, so we need to cache them.14 this._cachedQuantTables = [];15 this._cachedHuffmanTables = [];1617 this._segments = [];18 }1920 decodeRect(x, y, width, height, sock, display, depth) {21 // A rect of JPEG encodings is simply a JPEG file22 while (true) {23 let segment = this._readSegment(sock);24 if (segment === null) {25 return false;26 }27 this._segments.push(segment);28 // End of image?29 if (segment[1] === 0xD9) {30 break;31 }32 }3334 let huffmanTables = [];35 let quantTables = [];36 for (let segment of this._segments) {37 let type = segment[1];38 if (type === 0xC4) {39 // Huffman tables40 huffmanTables.push(segment);41 } else if (type === 0xDB) {42 // Quantization tables43 quantTables.push(segment);44 }45 }4647 const sofIndex = this._segments.findIndex(48 x => x[1] == 0xC0 || x[1] == 0xC249 );50 if (sofIndex == -1) {51 throw new Error("Illegal JPEG image without SOF");52 }5354 if (quantTables.length === 0) {55 this._segments.splice(sofIndex+1, 0,56 ...this._cachedQuantTables);57 }58 if (huffmanTables.length === 0) {59 this._segments.splice(sofIndex+1, 0,60 ...this._cachedHuffmanTables);61 }6263 let length = 0;64 for (let segment of this._segments) {65 length += segment.length;66 }6768 let data = new Uint8Array(length);69 length = 0;70 for (let segment of this._segments) {71 data.set(segment, length);72 length += segment.length;73 }7475 display.imageRect(x, y, width, height, "image/jpeg", data);7677 if (huffmanTables.length !== 0) {78 this._cachedHuffmanTables = huffmanTables;79 }80 if (quantTables.length !== 0) {81 this._cachedQuantTables = quantTables;82 }8384 this._segments = [];8586 return true;87 }8889 _readSegment(sock) {90 if (sock.rQwait("JPEG", 2)) {91 return null;92 }9394 let marker = sock.rQshift8();95 if (marker != 0xFF) {96 throw new Error("Illegal JPEG marker received (byte: " +97 marker + ")");98 }99 let type = sock.rQshift8();100 if (type >= 0xD0 && type <= 0xD9 || type == 0x01) {101 // No length after marker102 return new Uint8Array([marker, type]);103 }104105 if (sock.rQwait("JPEG", 2, 2)) {106 return null;107 }108109 let length = sock.rQshift16();110 if (length < 2) {111 throw new Error("Illegal JPEG length received (length: " +112 length + ")");113 }114115 if (sock.rQwait("JPEG", length-2, 4)) {116 return null;117 }118119 let extra = 0;120 if (type === 0xDA) {121 // start of scan122 extra += 2;123 while (true) {124 if (sock.rQwait("JPEG", length-2+extra, 4)) {125 return null;126 }127 let data = sock.rQpeekBytes(length-2+extra, false);128 if (data.at(-2) === 0xFF && data.at(-1) !== 0x00 &&129 !(data.at(-1) >= 0xD0 && data.at(-1) <= 0xD7)) {130 extra -= 2;131 break;132 }133 extra++;134 }135 }136137 let segment = new Uint8Array(2 + length + extra);138 segment[0] = marker;139 segment[1] = type;140 segment[2] = length >> 8;141 segment[3] = length;142 segment.set(sock.rQshiftBytes(length-2+extra, false), 4);143144 return segment;145 }146}147