zrle encoding
This commit is contained in:
parent
ce95686417
commit
b55a58ff38
@ -13,6 +13,8 @@ default = ["console_error_panic_hook"]
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2.83"
|
||||
js-sys = "0.3"
|
||||
flate2 = "1"
|
||||
byteorder = "1"
|
||||
# bytes="1"
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
|
@ -1,6 +1,9 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::vnc::{ImageData, MouseEventType, Vnc};
|
||||
use crate::{
|
||||
console_log, log,
|
||||
vnc::{ImageData, MouseEventType, Vnc},
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::{Clamped, JsCast};
|
||||
use web_sys::{
|
||||
@ -183,12 +186,18 @@ impl Canvas {
|
||||
Clamped(&ri.data),
|
||||
ri.width as u32,
|
||||
ri.height as u32,
|
||||
)
|
||||
.unwrap();
|
||||
// ConsoleService::log(&format!(
|
||||
// "renderring at ({}, {}), width {}, height {}",
|
||||
// cr.x, cr.y, cr.width, cr.height
|
||||
// ));
|
||||
);
|
||||
if data.is_err() {
|
||||
console_log!(
|
||||
"renderring failed at ({}, {}), width {}, height {}, len {}",
|
||||
ri.x,
|
||||
ri.y,
|
||||
ri.width,
|
||||
ri.height,
|
||||
ri.data.len(),
|
||||
);
|
||||
}
|
||||
let data = data.unwrap();
|
||||
let _ = self.ctx.put_image_data(&data, ri.x as f64, ri.y as f64);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ mod des;
|
||||
mod vnc_impl;
|
||||
mod x11cursor;
|
||||
mod x11keyboard;
|
||||
mod zlib;
|
||||
|
||||
pub enum MouseEventType {
|
||||
Down,
|
||||
@ -92,10 +93,10 @@ pub struct StreamReader {
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl StreamReader {
|
||||
pub fn new(bufs: Vec<Vec<u8>>) -> Self {
|
||||
pub fn new(bufs: Vec<Vec<u8>>, len: usize) -> Self {
|
||||
Self {
|
||||
inner: bufs,
|
||||
remain: 0,
|
||||
remain: len,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use super::{des, x11cursor::MouseUtils, x11keyboard, MouseEventType};
|
||||
use super::{des, x11cursor::MouseUtils, x11keyboard, zlib, MouseEventType};
|
||||
use crate::{console_log, log};
|
||||
|
||||
const VNC_RFB33: &[u8; 12] = b"RFB 003.003\n";
|
||||
@ -25,6 +25,7 @@ pub enum SecurityType {
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub enum VncEncoding {
|
||||
Raw = 0,
|
||||
CopyRect = 1,
|
||||
@ -71,6 +72,7 @@ pub struct Vnc {
|
||||
padding_rect: Option<VncRect>,
|
||||
outbuf: Vec<u8>,
|
||||
outs: Vec<VncOutput>,
|
||||
zlib_decoder: zlib::Decoder,
|
||||
}
|
||||
|
||||
impl Vnc {
|
||||
@ -78,18 +80,18 @@ impl Vnc {
|
||||
Self {
|
||||
state: VncState::Init,
|
||||
supported_encodings: vec![
|
||||
VncEncoding::Raw,
|
||||
// VncEncoding::Raw,
|
||||
VncEncoding::CopyRect,
|
||||
// VncEncoding::RRE,
|
||||
// VncEncoding::Hextile,
|
||||
// VncEncoding::TRLE,
|
||||
// VncEncoding::ZRLE,
|
||||
VncEncoding::ZRLE,
|
||||
// VncEncoding::CursorPseudo,
|
||||
// VncEncoding::DesktopSizePseudo,
|
||||
],
|
||||
security_type: SecurityType::Invalid,
|
||||
challenge: [0; 16],
|
||||
reader: StreamReader::new(Vec::with_capacity(10)),
|
||||
reader: StreamReader::new(Vec::with_capacity(10), 0),
|
||||
mouse: MouseUtils::new(),
|
||||
require: 12, // the handleshake message length
|
||||
width: 0,
|
||||
@ -101,24 +103,21 @@ impl Vnc {
|
||||
padding_rect: None,
|
||||
outbuf: Vec::with_capacity(128),
|
||||
outs: Vec::with_capacity(10),
|
||||
zlib_decoder: zlib::Decoder::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_input(&mut self, input: Vec<u8>) {
|
||||
// ConsoleService::info(&format!(
|
||||
// console_log!(
|
||||
// "VNC input {}, left {}, require {}",
|
||||
// input.len(),
|
||||
// self.reader.remain(),
|
||||
// self.require
|
||||
// ));
|
||||
// );
|
||||
self.reader.append(input);
|
||||
while self.reader.remain() >= self.require {
|
||||
self.handle_input();
|
||||
// ConsoleService::info(&format!(
|
||||
// "left {}, require {}",
|
||||
// self.reader.remain(),
|
||||
// self.require
|
||||
// ));
|
||||
// console_log!("left {}, require {}", self.reader.remain(), self.require);
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,7 +470,12 @@ impl Vnc {
|
||||
self.read_exact(&mut pfb, 16);
|
||||
// This pixel format will be used unless the client requests a different format using the SetPixelFormat message
|
||||
self.pf = (&pfb).into();
|
||||
console_log!("VNC: {}x{}", self.width, self.height);
|
||||
console_log!(
|
||||
"VNC: {}x{}\nPixel Format {:#?}",
|
||||
self.width,
|
||||
self.height,
|
||||
self.pf
|
||||
);
|
||||
self.name = self.read_string_l32();
|
||||
self.state = VncState::Connected;
|
||||
self.require = 1; // any message from sever will be handled
|
||||
@ -506,7 +510,7 @@ impl Vnc {
|
||||
fn handle_framebuffer_update(&mut self) {
|
||||
let _padding = self.read_u8();
|
||||
self.num_rect_left = self.read_u16();
|
||||
// console_log!("VNC: {} rects", self.num_rects_left);
|
||||
// console_log!("VNC: {} rects", self.num_rect_left);
|
||||
self.require = 12; // the length of the first rectangle hdr
|
||||
self.msg_handling = ServerMessage::FramebufferUpdate;
|
||||
}
|
||||
@ -546,32 +550,25 @@ impl Vnc {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match self.padding_rect.as_ref().unwrap().encoding_type {
|
||||
16 => {
|
||||
if self.require == 4 {
|
||||
self.require = self.read_u32() as usize;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
// we now have an entire rectangle
|
||||
let rect = self.padding_rect.take().unwrap();
|
||||
let mut image_data: Vec<u8> = Vec::with_capacity(self.require);
|
||||
self.read_exact_vec(&mut image_data, self.require);
|
||||
match rect.encoding_type {
|
||||
0 => {
|
||||
// for _ in 0..rect.height {
|
||||
// for _ in 0..rect.width {
|
||||
// let mut pixel = [0u8; 4];
|
||||
// self.read_exact(&mut pixel, 4);
|
||||
// let b = pixel[0];
|
||||
// let g = pixel[1];
|
||||
// let r = pixel[2];
|
||||
// let a = pixel[3];
|
||||
// image_data.extend_from_slice(&[r, g, b, a]);
|
||||
// }
|
||||
// }
|
||||
self.read_exact_vec(&mut image_data, self.require);
|
||||
// raw
|
||||
let mut y = 0;
|
||||
let mut x = 0;
|
||||
|
||||
// for y in 0..rect.height {
|
||||
// for x in 0..rect.width {
|
||||
// let idx = (y as usize * rect.width as usize + x as usize) * 4;
|
||||
// image_data.swap(idx, idx + 2)
|
||||
// }
|
||||
// }
|
||||
while y < rect.height {
|
||||
while x < rect.width {
|
||||
let idx = (y as usize * rect.width as usize + x as usize) * 4;
|
||||
@ -581,21 +578,41 @@ impl Vnc {
|
||||
x = 0;
|
||||
y += 1;
|
||||
}
|
||||
self.outs.push(VncOutput::RenderImage(ImageData {
|
||||
type_: rect.encoding_type,
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
data: image_data,
|
||||
}));
|
||||
}
|
||||
1 => {
|
||||
// copy rectangle
|
||||
self.read_exact_vec(&mut image_data, 4);
|
||||
self.outs.push(VncOutput::RenderImage(ImageData {
|
||||
type_: rect.encoding_type,
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
data: image_data,
|
||||
}));
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
16 => {
|
||||
// ZRLE
|
||||
match self.zlib_decoder.decode(&self.pf, &rect, &image_data) {
|
||||
Ok(images) => {
|
||||
for i in images {
|
||||
self.outs.push(VncOutput::RenderImage(i));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
self.outs.push(VncOutput::Err(format!("{:?}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("Unknow encoding {}", rect.encoding_type),
|
||||
}
|
||||
self.outs.push(VncOutput::RenderImage(ImageData {
|
||||
type_: rect.encoding_type,
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
data: image_data,
|
||||
}));
|
||||
self.num_rect_left -= 1;
|
||||
if 0 == self.num_rect_left {
|
||||
self.msg_handling = ServerMessage::None;
|
||||
@ -713,8 +730,15 @@ impl Vnc {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn handle_zrle_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) {
|
||||
unimplemented!()
|
||||
fn handle_zrle_encoding(&mut self, x: u16, y: u16, width: u16, height: u16) {
|
||||
self.require = 4;
|
||||
self.padding_rect = Some(VncRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
encoding_type: 16,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_cursor_pseudo_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) {
|
||||
@ -739,24 +763,24 @@ impl Vnc {
|
||||
// 1 CARD8 blue-shift
|
||||
// 1 CARD8 padding
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct PixelFormat {
|
||||
pub struct PixelFormat {
|
||||
// the number of bits used for each pixel value on the wire
|
||||
// 8, 16, 32(usually) only
|
||||
bits_per_pixel: u8,
|
||||
depth: u8,
|
||||
pub bits_per_pixel: u8,
|
||||
pub depth: u8,
|
||||
// true if multi-byte pixels are interpreted as big endian
|
||||
big_endian_flag: u8,
|
||||
pub big_endian_flag: u8,
|
||||
// true then the last six items specify how to extract the red, green and blue intensities from the pixel value
|
||||
true_color_flag: u8,
|
||||
pub true_color_flag: u8,
|
||||
// the next three always in big-endian order
|
||||
// no matter how the `big_endian_flag` is set
|
||||
red_max: u16,
|
||||
green_max: u16,
|
||||
blue_max: u16,
|
||||
pub red_max: u16,
|
||||
pub green_max: u16,
|
||||
pub blue_max: u16,
|
||||
// the number of shifts needed to get the red value in a pixel to the least significant bit
|
||||
red_shift: u8,
|
||||
green_shift: u8,
|
||||
blue_shift: u8,
|
||||
pub red_shift: u8,
|
||||
pub green_shift: u8,
|
||||
pub blue_shift: u8,
|
||||
padding_1: u8,
|
||||
padding_2: u8,
|
||||
padding_3: u8,
|
||||
@ -818,10 +842,11 @@ impl From<&[u8; 16]> for PixelFormat {
|
||||
}
|
||||
}
|
||||
|
||||
struct VncRect {
|
||||
x: u16,
|
||||
y: u16,
|
||||
width: u16,
|
||||
height: u16,
|
||||
encoding_type: u32,
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct VncRect {
|
||||
pub x: u16,
|
||||
pub y: u16,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub encoding_type: u32,
|
||||
}
|
||||
|
343
webvnc/src/vnc/zlib.rs
Normal file
343
webvnc/src/vnc/zlib.rs
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright (c) 2016 whitequark <whitequark@whitequark.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
use super::vnc_impl::*;
|
||||
use super::ImageData;
|
||||
use byteorder::ReadBytesExt;
|
||||
use std::io::{Read, Result};
|
||||
|
||||
struct ZlibReader<'a> {
|
||||
decompressor: flate2::Decompress,
|
||||
input: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> ZlibReader<'a> {
|
||||
fn new(decompressor: flate2::Decompress, input: &'a [u8]) -> ZlibReader<'a> {
|
||||
ZlibReader {
|
||||
decompressor,
|
||||
input,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Result<flate2::Decompress> {
|
||||
if self.input.is_empty() {
|
||||
Ok(self.decompressor)
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"leftover ZRLE byte data",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Read for ZlibReader<'a> {
|
||||
fn read(&mut self, output: &mut [u8]) -> std::io::Result<usize> {
|
||||
let in_before = self.decompressor.total_in();
|
||||
let out_before = self.decompressor.total_out();
|
||||
let result =
|
||||
self.decompressor
|
||||
.decompress(self.input, output, flate2::FlushDecompress::None);
|
||||
let consumed = (self.decompressor.total_in() - in_before) as usize;
|
||||
let produced = (self.decompressor.total_out() - out_before) as usize;
|
||||
|
||||
self.input = &self.input[consumed..];
|
||||
match result {
|
||||
Ok(flate2::Status::Ok) => Ok(produced),
|
||||
Ok(flate2::Status::BufError) => Ok(0),
|
||||
Err(error) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, error)),
|
||||
Ok(flate2::Status::StreamEnd) => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"ZRLE stream end",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BitReader<T: Read> {
|
||||
reader: T,
|
||||
buffer: u8,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl<T: Read> BitReader<T> {
|
||||
fn new(reader: T) -> BitReader<T> {
|
||||
BitReader {
|
||||
reader,
|
||||
buffer: 0,
|
||||
position: 8,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Result<T> {
|
||||
if self.position == 8 {
|
||||
Ok(self.reader)
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"leftover ZRLE bit data",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_bits(&mut self, count: usize) -> std::io::Result<u8> {
|
||||
assert!(count > 0 && count <= 8);
|
||||
|
||||
if self.position == 8 {
|
||||
self.buffer = self.reader.read_u8()?;
|
||||
self.position = 0;
|
||||
}
|
||||
|
||||
if self.position + count <= 8 {
|
||||
let shift = 8 - (count + self.position);
|
||||
let mask = (1 << count) - 1;
|
||||
let result = (self.buffer >> shift) & mask;
|
||||
self.position += count;
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"unaligned ZRLE bit read",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_bit(&mut self) -> std::io::Result<bool> {
|
||||
Ok(self.read_bits(1)? != 0)
|
||||
}
|
||||
|
||||
fn align(&mut self) {
|
||||
self.position = 8;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> Read for BitReader<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
if self.position == 8 {
|
||||
self.reader.read(buf)
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"unaligned ZRLE byte read",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Decoder {
|
||||
decompressor: Option<flate2::Decompress>,
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
pub fn new() -> Decoder {
|
||||
Decoder {
|
||||
decompressor: Some(flate2::Decompress::new(/*zlib_header*/ true)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(
|
||||
&mut self,
|
||||
format: &PixelFormat,
|
||||
rect: &VncRect,
|
||||
input: &[u8],
|
||||
) -> Result<Vec<ImageData>> {
|
||||
fn read_run_length(reader: &mut dyn Read) -> Result<usize> {
|
||||
let mut run_length_part;
|
||||
let mut run_length = 1;
|
||||
loop {
|
||||
run_length_part = reader.read_u8()?;
|
||||
run_length += run_length_part as usize;
|
||||
if 255 != run_length_part {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(run_length)
|
||||
}
|
||||
|
||||
fn copy_true_color(
|
||||
reader: &mut dyn Read,
|
||||
pixels: &mut Vec<u8>,
|
||||
pad: bool,
|
||||
compressed_bpp: usize,
|
||||
bpp: usize,
|
||||
) -> Result<()> {
|
||||
let mut buf = [255; 4];
|
||||
reader.read_exact(&mut buf[pad as usize..pad as usize + compressed_bpp])?;
|
||||
buf.swap(0, 2);
|
||||
pixels.extend_from_slice(&buf[..bpp]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_indexed(palette: &[u8], pixels: &mut Vec<u8>, bpp: usize, index: u8) {
|
||||
let start = index as usize * bpp;
|
||||
pixels.extend_from_slice(&palette[start..start + bpp])
|
||||
}
|
||||
|
||||
let mut ret = Vec::new();
|
||||
|
||||
let bpp = format.bits_per_pixel as usize / 8;
|
||||
let pixel_mask = (format.red_max as u32) << format.red_shift
|
||||
| (format.green_max as u32) << format.green_shift
|
||||
| (format.blue_max as u32) << format.blue_shift;
|
||||
|
||||
let (compressed_bpp, pad_pixel) =
|
||||
if format.bits_per_pixel == 32 && format.true_color_flag > 0 && format.depth <= 24 {
|
||||
if pixel_mask & 0x000000ff == 0 {
|
||||
(3, format.big_endian_flag > 0)
|
||||
} else if pixel_mask & 0xff000000 == 0 {
|
||||
(3, format.big_endian_flag == 0)
|
||||
} else {
|
||||
(4, false)
|
||||
}
|
||||
} else {
|
||||
(bpp, false)
|
||||
};
|
||||
|
||||
let mut palette = Vec::with_capacity(128 * bpp);
|
||||
let mut reader = BitReader::new(ZlibReader::new(self.decompressor.take().unwrap(), input));
|
||||
|
||||
let mut y = 0;
|
||||
while y < rect.height {
|
||||
let height = if y + 64 > rect.height {
|
||||
rect.height - y
|
||||
} else {
|
||||
64
|
||||
};
|
||||
let mut x = 0;
|
||||
while x < rect.width {
|
||||
let width = if x + 64 > rect.width {
|
||||
rect.width - x
|
||||
} else {
|
||||
64
|
||||
};
|
||||
let pixel_count = height as usize * width as usize;
|
||||
|
||||
let is_rle = reader.read_bit()?;
|
||||
let palette_size = reader.read_bits(7)?;
|
||||
palette.truncate(0);
|
||||
for _ in 0..palette_size {
|
||||
copy_true_color(&mut reader, &mut palette, pad_pixel, compressed_bpp, bpp)?
|
||||
}
|
||||
|
||||
let mut pixels = Vec::with_capacity(pixel_count * bpp);
|
||||
match (is_rle, palette_size) {
|
||||
(false, 0) => {
|
||||
// True Color pixels
|
||||
for _ in 0..pixel_count {
|
||||
copy_true_color(
|
||||
&mut reader,
|
||||
&mut pixels,
|
||||
pad_pixel,
|
||||
compressed_bpp,
|
||||
bpp,
|
||||
)?
|
||||
}
|
||||
}
|
||||
(false, 1) => {
|
||||
// Color fill
|
||||
for _ in 0..pixel_count {
|
||||
copy_indexed(&palette, &mut pixels, bpp, 0)
|
||||
}
|
||||
}
|
||||
(false, 2) | (false, 3..=4) | (false, 5..=16) => {
|
||||
// Indexed pixels
|
||||
let bits_per_index = match palette_size {
|
||||
2 => 1,
|
||||
3..=4 => 2,
|
||||
5..=16 => 4,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
for _ in 0..height {
|
||||
for _ in 0..width {
|
||||
let index = reader.read_bits(bits_per_index)?;
|
||||
copy_indexed(&palette, &mut pixels, bpp, index)
|
||||
}
|
||||
reader.align();
|
||||
}
|
||||
}
|
||||
(true, 0) => {
|
||||
// True Color RLE
|
||||
let mut count = 0;
|
||||
let mut pixel = Vec::new();
|
||||
while count < pixel_count {
|
||||
pixel.truncate(0);
|
||||
copy_true_color(
|
||||
&mut reader,
|
||||
&mut pixel,
|
||||
pad_pixel,
|
||||
compressed_bpp,
|
||||
bpp,
|
||||
)?;
|
||||
let run_length = read_run_length(&mut reader)?;
|
||||
for _ in 0..run_length {
|
||||
pixels.extend(&pixel)
|
||||
}
|
||||
count += run_length;
|
||||
}
|
||||
}
|
||||
(true, 2..=127) => {
|
||||
// Indexed RLE
|
||||
let mut count = 0;
|
||||
while count < pixel_count {
|
||||
let longer_than_one = reader.read_bit()?;
|
||||
let index = reader.read_bits(7)?;
|
||||
let run_length = if longer_than_one {
|
||||
read_run_length(&mut reader)?
|
||||
} else {
|
||||
1
|
||||
};
|
||||
for _ in 0..run_length {
|
||||
copy_indexed(&palette, &mut pixels, bpp, index);
|
||||
}
|
||||
count += run_length;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"ZRLE subencoding",
|
||||
))
|
||||
}
|
||||
}
|
||||
ret.push(ImageData {
|
||||
data: pixels,
|
||||
height,
|
||||
width,
|
||||
x: rect.x + x,
|
||||
y: rect.y + y,
|
||||
type_: 0,
|
||||
});
|
||||
x += width;
|
||||
}
|
||||
y += height;
|
||||
}
|
||||
|
||||
self.decompressor = Some(reader.into_inner()?.into_inner()?);
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user