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%
6.3 KB · 186 lines javascript
Raw Blame History
1/*2 * noVNC: HTML5 VNC client3 * Copyright (C) 2021 The noVNC authors4 * Licensed under MPL 2.0 (see LICENSE.txt)5 *6 * See README.md for usage and integration instructions.7 *8 */910import Inflate from "../inflator.js";1112const ZRLE_TILE_WIDTH = 64;13const ZRLE_TILE_HEIGHT = 64;1415export default class ZRLEDecoder {16    constructor() {17        this._length = 0;18        this._inflator = new Inflate();1920        this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);21        this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);22    }2324    decodeRect(x, y, width, height, sock, display, depth) {25        if (this._length === 0) {26            if (sock.rQwait("ZLib data length", 4)) {27                return false;28            }29            this._length = sock.rQshift32();30        }31        if (sock.rQwait("Zlib data", this._length)) {32            return false;33        }3435        const data = sock.rQshiftBytes(this._length, false);3637        this._inflator.setInput(data);3839        for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {40            let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);4142            for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {43                let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);4445                const tileSize = tw * th;46                const subencoding = this._inflator.inflate(1)[0];47                if (subencoding === 0) {48                    // raw data49                    const data = this._readPixels(tileSize);50                    display.blitImage(tx, ty, tw, th, data, 0, false);51                } else if (subencoding === 1) {52                    // solid53                    const background = this._readPixels(1);54                    display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]);55                } else if (subencoding >= 2 && subencoding <= 16) {56                    const data = this._decodePaletteTile(subencoding, tileSize, tw, th);57                    display.blitImage(tx, ty, tw, th, data, 0, false);58                } else if (subencoding === 128) {59                    const data = this._decodeRLETile(tileSize);60                    display.blitImage(tx, ty, tw, th, data, 0, false);61                } else if (subencoding >= 130 && subencoding <= 255) {62                    const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize);63                    display.blitImage(tx, ty, tw, th, data, 0, false);64                } else {65                    throw new Error('Unknown subencoding: ' + subencoding);66                }67            }68        }69        this._length = 0;70        return true;71    }7273    _getBitsPerPixelInPalette(paletteSize) {74        if (paletteSize <= 2) {75            return 1;76        } else if (paletteSize <= 4) {77            return 2;78        } else if (paletteSize <= 16) {79            return 4;80        }81    }8283    _readPixels(pixels) {84        let data = this._pixelBuffer;85        const buffer = this._inflator.inflate(3*pixels);86        for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) {87            data[i]     = buffer[j];88            data[i + 1] = buffer[j + 1];89            data[i + 2] = buffer[j + 2];90            data[i + 3] = 255;  // Add the Alpha91        }92        return data;93    }9495    _decodePaletteTile(paletteSize, tileSize, tilew, tileh) {96        const data = this._tileBuffer;97        const palette = this._readPixels(paletteSize);98        const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize);99        const mask = (1 << bitsPerPixel) - 1;100101        let offset = 0;102        let encoded = this._inflator.inflate(1)[0];103104        for (let y=0; y<tileh; y++) {105            let shift = 8-bitsPerPixel;106            for (let x=0; x<tilew; x++) {107                if (shift<0) {108                    shift=8-bitsPerPixel;109                    encoded = this._inflator.inflate(1)[0];110                }111                let indexInPalette = (encoded>>shift) & mask;112113                data[offset] = palette[indexInPalette * 4];114                data[offset + 1] = palette[indexInPalette * 4 + 1];115                data[offset + 2] = palette[indexInPalette * 4 + 2];116                data[offset + 3] = palette[indexInPalette * 4 + 3];117                offset += 4;118                shift-=bitsPerPixel;119            }120            if (shift<8-bitsPerPixel && y<tileh-1) {121                encoded =  this._inflator.inflate(1)[0];122            }123        }124        return data;125    }126127    _decodeRLETile(tileSize) {128        const data = this._tileBuffer;129        let i = 0;130        while (i < tileSize) {131            const pixel = this._readPixels(1);132            const length = this._readRLELength();133            for (let j = 0; j < length; j++) {134                data[i * 4] = pixel[0];135                data[i * 4 + 1] = pixel[1];136                data[i * 4 + 2] = pixel[2];137                data[i * 4 + 3] = pixel[3];138                i++;139            }140        }141        return data;142    }143144    _decodeRLEPaletteTile(paletteSize, tileSize) {145        const data = this._tileBuffer;146147        // palette148        const palette = this._readPixels(paletteSize);149150        let offset = 0;151        while (offset < tileSize) {152            let indexInPalette = this._inflator.inflate(1)[0];153            let length = 1;154            if (indexInPalette >= 128) {155                indexInPalette -= 128;156                length = this._readRLELength();157            }158            if (indexInPalette > paletteSize) {159                throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize);160            }161            if (offset + length > tileSize) {162                throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset));163            }164165            for (let j = 0; j < length; j++) {166                data[offset * 4] = palette[indexInPalette * 4];167                data[offset * 4 + 1] = palette[indexInPalette * 4 + 1];168                data[offset * 4 + 2] = palette[indexInPalette * 4 + 2];169                data[offset * 4 + 3] = palette[indexInPalette * 4 + 3];170                offset++;171            }172        }173        return data;174    }175176    _readRLELength() {177        let length = 0;178        let current = 0;179        do {180            current = this._inflator.inflate(1)[0];181            length += current;182        } while (current === 255);183        return length + 1;184    }185}186