what the fuck help

This commit is contained in:
Pyrex 2024-04-10 12:04:23 -07:00
commit ea18938dcf
15 changed files with 909 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
outputs/

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"rust-analyzer.linkedProjects": [
".\\Cargo.toml"
]
}

277
Cargo.lock generated Normal file
View File

@ -0,0 +1,277 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
[[package]]
name = "env_logger"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [
"log",
"regex",
]
[[package]]
name = "fdeflate"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
dependencies = [
"simd-adler32",
]
[[package]]
name = "flate2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "getrandom"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memchr"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
"simd-adler32",
]
[[package]]
name = "png"
version = "0.17.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
dependencies = [
"bitflags",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "proc-macro2"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quickcheck"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
dependencies = [
"env_logger",
"log",
"rand",
]
[[package]]
name = "quickcheck_macros"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "rx0"
version = "0.1.0"
dependencies = [
"png",
"quickcheck",
"quickcheck_macros",
"thiserror",
]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

14
Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "rx0"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
png = "0.17.13"
thiserror = "1.0.58"
[dev-dependencies]
quickcheck = "1.0.3"
quickcheck_macros = "1.0.0"

BIN
inputs/avatar2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 KiB

BIN
inputs/zonked.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

56
src/decode_image.rs Normal file
View File

@ -0,0 +1,56 @@
use std::io::Read;
use crate::{decode_tile, image::Image, protocol::{self, ProtocolReaderResult}};
pub fn decode_image<R: Read>(
reader: &mut protocol::ProtocolReader<R>
) -> ProtocolReaderResult<Image> {
let width = reader.read_u16()? as usize;
let height = reader.read_u16()? as usize;
let mut layer_quality = [0_u8; 4];
for i in 0..4 {
layer_quality[i] = reader.read_u8()?;
}
let mut n_layers = 0;
for i in (0..4).rev() {
if layer_quality[i] != 0 {
n_layers = i + 1;
break;
}
}
let mut layer_pixels = vec![];
for _ in 0..n_layers {
layer_pixels.push(vec![0_u8; width as usize * height as usize])
}
for y0 in (0..height).step_by(16) {
for x0 in (0..width).step_by(16) {
for layer in 0..n_layers {
let mut data = [0; 256];
decode_tile::decode_tile(&mut data, layer_quality[layer], reader)?;
for y in 0..16 {
for x in 0..16 {
let src_x = x0 + x;
let src_y = y0 + y;
if src_x < width && src_y < height {
layer_pixels[layer][src_y * width + src_x] =
data[y * 16 + x];
}
}
}
}
}
}
let mut image = Image::new(width, height);
for (layer, pixels) in layer_pixels.into_iter().enumerate() {
image.add(layer_quality[layer], pixels)
.expect("should be correct by construction");
}
Ok(image)
}

59
src/decode_tile.rs Normal file
View File

@ -0,0 +1,59 @@
use std::io::Read;
use crate::protocol::{ProtocolReader, ProtocolReaderResult};
pub fn decode_tile<R: Read>(
data: &mut [u8; 256],
quality: u8,
reader: &mut ProtocolReader<R>
) -> ProtocolReaderResult<()> {
let mut coefs = [0_i32; 256];
for _ in 0..quality {
let ix = reader.read_u8()?;
let val = reader.read_u16()? as i32;
coefs[ix as usize] = val;
}
let mut transform = |zero: usize, stride: usize| {
let mut ixs = [0; 16];
ixs[0] = zero;
for i in 1..16 { ixs[i] = ixs[i - 1] + stride; }
for bit in [8, 4, 2, 1] {
for i in 0..16 {
if i & bit == 0 {
let j = i | bit;
let ival = coefs[ixs[i]];
let jval = coefs[ixs[j]];
coefs[ixs[i]] = ival.wrapping_add(jval);
coefs[ixs[j]] = ival.wrapping_sub(jval);
}
}
}
for i in 0..16 {
coefs[ixs[i]] /= 16;
}
};
for row in 0..16 { transform(row * 16, 1); }
for col in 0..16 { transform(col, 16); }
for i in 0..256 {
data[i] = coefs[i].max(0).min(255) as u8;
}
Ok(())
}
pub fn decode_value(enc: u8) -> i32 {
let sign = enc & 0x80 != 0;
let exponent = (enc >> 4) & 0x7;
let mantissa = enc & 0xf;
let magnitude = ((((mantissa as i32) << 1) | 0b100001) << exponent) - 33;
if sign { return -magnitude * 16 }
return magnitude * 16;
}

42
src/encode_image.rs Normal file
View File

@ -0,0 +1,42 @@
use std::io::Write;
use crate::{encode_tile, image::Image, protocol::{self, ProtocolWriterResult}};
pub fn encode_image<W: Write>(
image: Image,
writer: &mut protocol::ProtocolWriter<W>
) -> ProtocolWriterResult<()> {
assert!(image.layers.len() <= 4); // TODO: Enforce in Image
writer.write_u16(image.width as u16)?;
writer.write_u16(image.height as u16)?;
for i in 0..4 {
writer.write_u8(image.layers.get(i).map(|l| l.0).unwrap_or(0))?;
}
for y0 in (0..image.height).step_by(16) {
for x0 in (0..image.width).step_by(16) {
for (quality, layer) in image.layers.iter() {
let mut data = [0; 256];
for y in 0..16 {
for x in 0..16 {
let src_x = x0 + x;
let src_y = y0 + y;
data[y * 16 + x] =
if src_x < image.width && src_y < image.height {
layer[src_y * image.width + src_x]
} else {
0
};
}
}
encode_tile::encode_tile(data, *quality, writer)?
}
}
}
Ok(())
}

151
src/encode_tile.rs Normal file
View File

@ -0,0 +1,151 @@
use std::io::Write;
use crate::protocol::{ProtocolWriter, ProtocolWriterResult};
pub fn encode_tile<W: Write>(
data: [u8; 256],
quality: u8,
writer: &mut ProtocolWriter<W>
) -> ProtocolWriterResult<()> {
let mut coefs: [i32; 256] = [0; 256];
for i in 0..256 {
coefs[i] = data[i] as i32;
}
let mut transform = |zero: usize, stride: usize| {
let mut ixs = [0; 16];
ixs[0] = zero;
for i in 1..16 {
ixs[i] = ixs[i - 1] + stride;
}
for bit in [8, 4, 2, 1] {
for i in 0..16 {
if i & bit == 0 {
let j = i | bit;
let ival = coefs[ixs[i]];
let jval = coefs[ixs[j]];
coefs[ixs[i]] = ival.wrapping_add(jval);
coefs[ixs[j]] = ival.wrapping_sub(jval);
}
}
}
};
for col in 0..16 {
transform(col, 16);
}
for row in 0..16 {
transform(row * 16, 1);
}
// this operation can be efficiently implemented as a heapsort in C
// but the code is ugly
// so just use Rust's default sort
let mut indices = [0; 256];
for i in 0..256 {
indices[i] = i;
}
indices.sort_by_key(|ix| -(coefs[*ix]).abs());
// write indices and values
// (note that the first index will almost always be zero)
for i in 0..quality {
let ix = indices[i as usize];
writer.write_u8(ix as u8)?;
writer.write_u16(coefs[ix] as u16)?;
};
Ok(())
}
pub fn encode_value(value: i32) -> u8 {
let value = value / 16;
let sign = value < 0;
let mut rescaled = value.abs() + 33;
let mut exponent = 0;
while rescaled > 64 {
exponent += 1;
rescaled >>= 1;
}
let mantissa = (rescaled >> 1) & 0xf;
return (
if sign { 128 } else { 0 } |
exponent << 4 |
mantissa
) as u8;
}
#[cfg(test)]
mod test {
use quickcheck_macros::quickcheck;
use crate::decode_tile::decode_value;
use super::encode_value;
#[quickcheck]
fn test_encode_value_2(val: u16) -> bool {
let val = (val & (0x8000 | 0x3fff)) as i16;
let canon = decode_value(encode_value(val as i32));
canon == decode_value(encode_value(canon as i32))
}
#[test]
fn test_encode_value_1() {
// ...01abcdx cases
assert_eq!(0b00001111, encode_value(0 + (0b111110 - 33)));
assert_eq!(0b00001110, encode_value(0 + (0b111100 - 33)));
assert_eq!(0b10001111, encode_value(0 - (0b111110 - 33)));
assert_eq!(0b10001110, encode_value(0 - (0b111100 - 33)));
// ...01abcdxx cases
assert_eq!(0b00011111, encode_value(0 + (0b1111101 - 33)));
assert_eq!(0b00011110, encode_value(0 + (0b1111001 - 33)));
assert_eq!(0b10011111, encode_value(0 - (0b1111101 - 33)));
assert_eq!(0b10011110, encode_value(0 - (0b1111001 - 33)));
// ...01abcdxxx cases
assert_eq!(0b00101111, encode_value(0 + (0b11111000 - 33)));
assert_eq!(0b00101110, encode_value(0 + (0b11110001 - 33)));
assert_eq!(0b10101111, encode_value(0 - (0b11111010 - 33)));
assert_eq!(0b10101110, encode_value(0 - (0b11110011 - 33)));
// ...01abcdxxxx cases
assert_eq!(0b00111111, encode_value(0 + (0b111110000 - 33)));
assert_eq!(0b00111110, encode_value(0 + (0b111100010 - 33)));
assert_eq!(0b10111111, encode_value(0 - (0b111110100 - 33)));
assert_eq!(0b10111110, encode_value(0 - (0b111100110 - 33)));
// ...01abcdxxxxx cases
assert_eq!(0b01001111, encode_value(0 + (0b1111100000 - 33)));
assert_eq!(0b01001110, encode_value(0 + (0b1111000100 - 33)));
assert_eq!(0b11001111, encode_value(0 - (0b1111101000 - 33)));
assert_eq!(0b11001110, encode_value(0 - (0b1111001100 - 33)));
// ...01abcdxxxxxx cases
assert_eq!(0b01011111, encode_value(0 + (0b11111000000 - 33)));
assert_eq!(0b01011110, encode_value(0 + (0b11110001000 - 33)));
assert_eq!(0b11011111, encode_value(0 - (0b11111010000 - 33)));
assert_eq!(0b11011110, encode_value(0 - (0b11110011000 - 33)));
// ...01abcdxxxxxxx cases
assert_eq!(0b01101111, encode_value(0 + (0b111110000000 - 33)));
assert_eq!(0b01101110, encode_value(0 + (0b111100010000 - 33)));
assert_eq!(0b11101111, encode_value(0 - (0b111110100000 - 33)));
assert_eq!(0b11101110, encode_value(0 - (0b111100110000 - 33)));
// ...01abcdxxxxxxx cases
assert_eq!(0b01111111, encode_value(0 + (0b1111100000000 - 33)));
assert_eq!(0b01111110, encode_value(0 + (0b1111000100001 - 33)));
assert_eq!(0b11111111, encode_value(0 - (0b1111101000010 - 33)));
assert_eq!(0b11111110, encode_value(0 - (0b1111001100011 - 33)));
}
}

45
src/image.rs Normal file
View File

@ -0,0 +1,45 @@
use std::io;
use png::ColorType;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ImageError {
#[error("can't make the layer fit {0}x{1}")]
WrongSize(usize, usize),
#[error("unsupported color type {0:?}")]
InvalidInputColorType(ColorType),
#[error("can't save an image with {0} layers as png")]
WrongNumberOfLayersToSave(usize),
#[error("general IO error")]
IoError(#[from] io::Error),
#[error("error in encoding PNG")]
PngEncodingError(#[from] png::EncodingError),
#[error("error in decoding PNG")]
PngDecodingError(#[from] png::DecodingError),
}
pub struct Image {
pub width: usize,
pub height: usize,
pub layers: Vec<(u8, Vec<u8>)>
}
impl Image {
pub fn new(width: usize, height: usize) -> Self {
Image {
width, height,
layers: vec![]
}
}
pub fn add(&mut self, quality: u8, pixels: Vec<u8>) -> Result<(), ImageError> {
if pixels.len() != self.width * self.height {
return Err(ImageError::WrongSize(self.width, self.height));
}
self.layers.push((quality, pixels));
Ok(())
}
}

42
src/main.rs Normal file
View File

@ -0,0 +1,42 @@
use std::{fs::File, io::{Cursor, Write}};
use protocol::{ProtocolReader, ProtocolWriter};
mod decode_image;
mod decode_tile;
mod encode_image;
mod encode_tile;
mod image;
mod png_utils;
mod protocol;
fn main() {
// run_for("zonked".to_string(), 9, 2, Some(330000));
run_for("zonked".to_string());
run_for("avatar2".to_string());
}
fn run_for(name: String) {
let image = png_utils::load_image(
format!("inputs/{}.png", name),
[5, 6, 5, 0]
).unwrap();
let mut writer = ProtocolWriter::new(vec![]);
encode_image::encode_image(
image,
&mut writer
).unwrap();
let compressed = writer.destroy();
let mut output_file = File::create(format!("outputs/{}.rx0", name)).unwrap();
output_file.write_all(&compressed).unwrap();
let mut reader = ProtocolReader::new(Cursor::new(compressed));
let decompressed_image = decode_image::decode_image(&mut reader).unwrap();
png_utils::save_image(
format!("outputs/{}_out.png", name),
decompressed_image
).unwrap();
}

83
src/png_utils.rs Normal file
View File

@ -0,0 +1,83 @@
use std::fs::File;
use png::{BitDepth, ColorType};
use crate::image::{Image, ImageError};
pub fn load_image(filename: String, quality: [u8; 4]) -> Result<Image, ImageError> {
let decoder = png::Decoder::new(File::open(filename).unwrap());
let mut reader = decoder.read_info().unwrap();
let mut buf = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut buf).unwrap();
let bytes = &buf[..info.buffer_size()];
assert_eq!(BitDepth::Eight, reader.info().bit_depth);
assert_eq!(ColorType::Rgb, reader.info().color_type);
let width = reader.info().width;
let height = reader.info().height;
match reader.info().color_type {
ColorType::Rgb => {
assert_eq!(3, reader.info().bytes_per_pixel());
let r: Vec<u8> = bytes[0..].iter().cloned().step_by(3).collect();
let g: Vec<u8> = bytes[1..].iter().cloned().step_by(3).collect();
let b: Vec<u8> = bytes[2..].iter().cloned().step_by(3).collect();
let mut image = Image::new(width as usize, height as usize);
image.add(quality[0], r)?;
image.add(quality[1], g)?;
image.add(quality[2], b)?;
return Ok(image);
}
ColorType::Rgba => {
assert_eq!(4, reader.info().bytes_per_pixel());
let r: Vec<u8> = bytes[0..].iter().cloned().step_by(4).collect();
let g: Vec<u8> = bytes[1..].iter().cloned().step_by(4).collect();
let b: Vec<u8> = bytes[2..].iter().cloned().step_by(4).collect();
let a: Vec<u8> = bytes[3..].iter().cloned().step_by(4).collect();
let mut image = Image::new(width as usize, height as usize);
image.add(quality[0], r)?;
image.add(quality[1], g)?;
image.add(quality[2], b)?;
image.add(quality[3], a)?;
return Ok(image);
}
ct => {
return Err(ImageError::InvalidInputColorType(ct))
}
}
}
pub fn save_image(filename: String, image: Image) -> Result<(), ImageError> {
let n_layers = image.layers.len();
let color_type = match n_layers {
3 => ColorType::Rgb,
4 => ColorType::Rgba,
_ => return Err(ImageError::WrongNumberOfLayersToSave(n_layers)),
};
let mut encoder = png::Encoder::new(
File::create(filename)?,
image.width as u32, image.height as u32,
);
encoder.set_color(color_type);
let mut idata: Vec<u8> = vec![0; image.width * image.height * n_layers];
for i in 0..n_layers {
for (dst, src) in
idata[i..].iter_mut().step_by(n_layers).zip(image.layers[i].1.iter())
{
*dst = *src;
}
}
let mut writer = encoder.write_header()?;
writer.write_image_data(&idata)?;
Ok(())
}

67
src/protocol.rs Normal file
View File

@ -0,0 +1,67 @@
use std::io::{self, Read, Write};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ProtocolWriterError {
#[error("error using underlying writer")]
Io(#[from] io::Error)
}
pub type ProtocolWriterResult<T> = Result<T, ProtocolWriterError>;
pub struct ProtocolWriter<W: Write> {
writer: W
}
#[derive(Error, Debug)]
pub enum ProtocolReaderError {
#[error("error using underlying reader")]
Io(#[from] io::Error),
}
pub type ProtocolReaderResult<T> = Result<T, ProtocolReaderError>;
pub struct ProtocolReader<R: Read> {
reader: R
}
impl<W: Write> ProtocolWriter<W> {
pub fn new(writer: W) -> Self {
Self { writer }
}
pub fn destroy(self) -> W {
self.writer
}
pub fn write_u8(&mut self, value: u8) -> ProtocolWriterResult<()> {
self.writer.write_all(&value.to_le_bytes())?;
Ok(())
}
pub fn write_u16(&mut self, value: u16) -> ProtocolWriterResult<()> {
self.writer.write_all(&value.to_le_bytes())?;
Ok(())
}
}
impl<R: Read> ProtocolReader<R> {
pub fn new(reader: R) -> Self {
Self { reader }
}
pub fn read_u8(&mut self) -> ProtocolReaderResult<u8> {
let mut u8_buf = [0; 1];
self.reader.read_exact(&mut u8_buf)?;
Ok(u8::from_le_bytes(u8_buf))
}
pub fn read_u16(&mut self) -> ProtocolReaderResult<u16> {
let mut u16_buf = [0; 2];
self.reader.read_exact(&mut u16_buf)?;
Ok(u16::from_le_bytes(u16_buf))
}
}

66
src/transform.rs.old Normal file
View File

@ -0,0 +1,66 @@
// Ported from:
// - https://colab.research.google.com/drive/1WjtKwUcqxWafAumFO9ET74RsckZSsw6n#scrollTo=e3r9-RBpcgwH
// Specialized for:
//
// - Input domain: 0-255
// - Tile size: 16x16
//
// Rather than dividing by 16 at the end of a decode phase,
// we divide by 16 at the end of the _encode_ phase
//
// The normal range would be something like -255 * 256 to 255 * 256
// (-65280 to 65280) but this reduces it (now it's something like -4080 to 4080)
//
// This simplifies the decoder (which can be i16) and means it can be written
// using i16s instead of i32s
//
// We could probably shrink the range more by recentering to -128-127, but does
// it even matter? Reasonable encodings like A-law and mu-law can handle both.
//
// (Take my opinions on the range with a grain of salt: I've calculated it but I
// haven't measured it)
//
struct Transform<'d> {
data: &'d mut [i32],
zero: usize,
stride: usize,
}
impl<'d> Transform<'d> {
pub fn encode(&mut self) {
self.transform();
self.divide(16);
}
pub fn decode(&mut self) {
self.transform();
}
pub fn ix(&self, i: usize) -> usize {
self.zero + t * self.stride
}
fn transform(&mut self) {
for bit in [8, 4, 2, 1] {
for i in 0..16 {
if i & bit == 0 {
let j = i | bit;
let ival = self.data[self.ix(i)];
let jval = self.data[self.ix(j)];
self.data[self.ix(i)] = ival.wrapping_add(jval);
self.data[self.ix(j)] = ival.wrapping_sub(jval);
}
}
}
}
fn divide(&mut self, divisor: i32) {
for i in 0..16 {
self.data[self.ix(i)] = self.data[self.ix(j)] / divisor;
}
}
}