zrle.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * noVNC: HTML5 VNC client
  3. * Copyright (C) 2021 The noVNC Authors
  4. * Licensed under MPL 2.0 (see LICENSE.txt)
  5. *
  6. * See README.md for usage and integration instructions.
  7. *
  8. */
  9. import Inflate from "../inflator.js";
  10. const ZRLE_TILE_WIDTH = 64;
  11. const ZRLE_TILE_HEIGHT = 64;
  12. export default class ZRLEDecoder {
  13. constructor() {
  14. this._length = 0;
  15. this._inflator = new Inflate();
  16. this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
  17. this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
  18. }
  19. decodeRect(x, y, width, height, sock, display, depth) {
  20. if (this._length === 0) {
  21. if (sock.rQwait("ZLib data length", 4)) {
  22. return false;
  23. }
  24. this._length = sock.rQshift32();
  25. }
  26. if (sock.rQwait("Zlib data", this._length)) {
  27. return false;
  28. }
  29. const data = sock.rQshiftBytes(this._length, false);
  30. this._inflator.setInput(data);
  31. for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {
  32. let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);
  33. for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {
  34. let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);
  35. const tileSize = tw * th;
  36. const subencoding = this._inflator.inflate(1)[0];
  37. if (subencoding === 0) {
  38. // raw data
  39. const data = this._readPixels(tileSize);
  40. display.blitImage(tx, ty, tw, th, data, 0, false);
  41. } else if (subencoding === 1) {
  42. // solid
  43. const background = this._readPixels(1);
  44. display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]);
  45. } else if (subencoding >= 2 && subencoding <= 16) {
  46. const data = this._decodePaletteTile(subencoding, tileSize, tw, th);
  47. display.blitImage(tx, ty, tw, th, data, 0, false);
  48. } else if (subencoding === 128) {
  49. const data = this._decodeRLETile(tileSize);
  50. display.blitImage(tx, ty, tw, th, data, 0, false);
  51. } else if (subencoding >= 130 && subencoding <= 255) {
  52. const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize);
  53. display.blitImage(tx, ty, tw, th, data, 0, false);
  54. } else {
  55. throw new Error('Unknown subencoding: ' + subencoding);
  56. }
  57. }
  58. }
  59. this._length = 0;
  60. return true;
  61. }
  62. _getBitsPerPixelInPalette(paletteSize) {
  63. if (paletteSize <= 2) {
  64. return 1;
  65. } else if (paletteSize <= 4) {
  66. return 2;
  67. } else if (paletteSize <= 16) {
  68. return 4;
  69. }
  70. }
  71. _readPixels(pixels) {
  72. let data = this._pixelBuffer;
  73. const buffer = this._inflator.inflate(3*pixels);
  74. for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) {
  75. data[i] = buffer[j];
  76. data[i + 1] = buffer[j + 1];
  77. data[i + 2] = buffer[j + 2];
  78. data[i + 3] = 255; // Add the Alpha
  79. }
  80. return data;
  81. }
  82. _decodePaletteTile(paletteSize, tileSize, tilew, tileh) {
  83. const data = this._tileBuffer;
  84. const palette = this._readPixels(paletteSize);
  85. const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize);
  86. const mask = (1 << bitsPerPixel) - 1;
  87. let offset = 0;
  88. let encoded = this._inflator.inflate(1)[0];
  89. for (let y=0; y<tileh; y++) {
  90. let shift = 8-bitsPerPixel;
  91. for (let x=0; x<tilew; x++) {
  92. if (shift<0) {
  93. shift=8-bitsPerPixel;
  94. encoded = this._inflator.inflate(1)[0];
  95. }
  96. let indexInPalette = (encoded>>shift) & mask;
  97. data[offset] = palette[indexInPalette * 4];
  98. data[offset + 1] = palette[indexInPalette * 4 + 1];
  99. data[offset + 2] = palette[indexInPalette * 4 + 2];
  100. data[offset + 3] = palette[indexInPalette * 4 + 3];
  101. offset += 4;
  102. shift-=bitsPerPixel;
  103. }
  104. if (shift<8-bitsPerPixel && y<tileh-1) {
  105. encoded = this._inflator.inflate(1)[0];
  106. }
  107. }
  108. return data;
  109. }
  110. _decodeRLETile(tileSize) {
  111. const data = this._tileBuffer;
  112. let i = 0;
  113. while (i < tileSize) {
  114. const pixel = this._readPixels(1);
  115. const length = this._readRLELength();
  116. for (let j = 0; j < length; j++) {
  117. data[i * 4] = pixel[0];
  118. data[i * 4 + 1] = pixel[1];
  119. data[i * 4 + 2] = pixel[2];
  120. data[i * 4 + 3] = pixel[3];
  121. i++;
  122. }
  123. }
  124. return data;
  125. }
  126. _decodeRLEPaletteTile(paletteSize, tileSize) {
  127. const data = this._tileBuffer;
  128. // palette
  129. const palette = this._readPixels(paletteSize);
  130. let offset = 0;
  131. while (offset < tileSize) {
  132. let indexInPalette = this._inflator.inflate(1)[0];
  133. let length = 1;
  134. if (indexInPalette >= 128) {
  135. indexInPalette -= 128;
  136. length = this._readRLELength();
  137. }
  138. if (indexInPalette > paletteSize) {
  139. throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize);
  140. }
  141. if (offset + length > tileSize) {
  142. throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset));
  143. }
  144. for (let j = 0; j < length; j++) {
  145. data[offset * 4] = palette[indexInPalette * 4];
  146. data[offset * 4 + 1] = palette[indexInPalette * 4 + 1];
  147. data[offset * 4 + 2] = palette[indexInPalette * 4 + 2];
  148. data[offset * 4 + 3] = palette[indexInPalette * 4 + 3];
  149. offset++;
  150. }
  151. }
  152. return data;
  153. }
  154. _readRLELength() {
  155. let length = 0;
  156. let current = 0;
  157. do {
  158. current = this._inflator.inflate(1)[0];
  159. length += current;
  160. } while (current === 255);
  161. return length + 1;
  162. }
  163. }