SPB Git forge

spb/admin-ka

Public
41commits 1branches 0releases
172.9 MBsize
maindefault branch
20 days agolast push
JavaScript 65.5% Python 17.8% CSS 13% HTML 3.7%
4.1 KB · 147 lines javascript
Raw Blame History
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