changes to package name. added help command.

This commit is contained in:
nihil 2024-11-13 23:55:53 +01:00
parent 222b0e2c7b
commit d4d87fffe3
4 changed files with 335 additions and 285 deletions

4
Cargo.lock generated
View File

@ -82,8 +82,8 @@ dependencies = [
] ]
[[package]] [[package]]
name = "qoi-test" name = "qoi"
version = "0.1.0" version = "0.1.1"
dependencies = [ dependencies = [
"array-init", "array-init",
"colors-transform", "colors-transform",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "qoi-test" name = "qoi"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -3,12 +3,12 @@
//! This crate should not be published as better crates are available, e.g. [rapid-qoi](https://crates.io/crates/rapid-qoi). //! This crate should not be published as better crates are available, e.g. [rapid-qoi](https://crates.io/crates/rapid-qoi).
#![allow(dead_code, unused_variables)] #![allow(dead_code, unused_variables)]
pub mod qoi_img { pub mod qoi_lib {
use log::{debug, info, Level, LevelFilter, Record, SetLoggerError};
use std::fmt; use std::fmt;
use std::io::prelude::*;
use std::fs::File; use std::fs::File;
use log::{debug,info, Level, Record, SetLoggerError, LevelFilter}; use std::io::prelude::*;
use array_init; use array_init;
@ -23,20 +23,22 @@ pub mod qoi_img {
//inherit from base Error //inherit from base Error
impl std::error::Error for ImgError {} impl std::error::Error for ImgError {}
//Output for error handling //Output for error handling
impl fmt::Display for ImgError { impl fmt::Display for ImgError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
ImgError::DataError => write!(f, "invalid number of bytes (must be devisible by 4)"), ImgError::DataError => {
ImgError::PixelNumberError => write!(f, "number of pixels does not match height and width params"), write!(f, "invalid number of bytes (must be devisible by 4)")
}
ImgError::PixelNumberError => {
write!(f, "number of pixels does not match height and width params")
}
ImgError::DecodeError => write!(f, "decoder failed to construct valid image"), ImgError::DecodeError => write!(f, "decoder failed to construct valid image"),
ImgError::HeaderError => write!(f, "not a valid QOI file header") ImgError::HeaderError => write!(f, "not a valid QOI file header"),
} }
} }
} }
//boilerplate implementation of the log crate //boilerplate implementation of the log crate
struct SimpleLogger; struct SimpleLogger;
@ -49,9 +51,7 @@ pub mod qoi_img {
eprintln!("{} - {}", record.level(), record.args()); eprintln!("{} - {}", record.level(), record.args());
} }
} }
fn flush(&self) { fn flush(&self) {}
}
} }
//logging boilerplate //logging boilerplate
static LOGGER: SimpleLogger = SimpleLogger; static LOGGER: SimpleLogger = SimpleLogger;
@ -88,7 +88,6 @@ pub mod qoi_img {
log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Debug)) log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Debug))
} }
/// Custom image struct, which is used to store decoded data. Used by [encode_from_image] to encode the necessary data in bytes. Requires a Vector over [Pixel] values, `Vec<Pixel>`, /// Custom image struct, which is used to store decoded data. Used by [encode_from_image] to encode the necessary data in bytes. Requires a Vector over [Pixel] values, `Vec<Pixel>`,
/// which can be generated by [`self::new`] if given byte data. Otherwise, [self.pixels] must be given filled vector. /// which can be generated by [`self::new`] if given byte data. Otherwise, [self.pixels] must be given filled vector.
/// `height` and `width` are given as u32 (note that qoi encoding does not guarantee functionality for images containing over 4000000 pixels.) /// `height` and `width` are given as u32 (note that qoi encoding does not guarantee functionality for images containing over 4000000 pixels.)
@ -123,7 +122,13 @@ pub mod qoi_img {
impl Image { impl Image {
//Image constructor, expects an array of u8 pixels values in order, left to right, top to bottom. //Image constructor, expects an array of u8 pixels values in order, left to right, top to bottom.
pub fn new(data: Vec<u8>, height: u32, width: u32, channels: u8, colorspace: u8,) -> Result<Image, ImgError> { pub fn new(
data: Vec<u8>,
height: u32,
width: u32,
channels: u8,
colorspace: u8,
) -> Result<Image, ImgError> {
let pixels: Vec<Pixel> = match Image::pixels_from_bytes(data) { let pixels: Vec<Pixel> = match Image::pixels_from_bytes(data) {
Ok(out) => out, Ok(out) => out,
Err(error) => return Err(error), Err(error) => return Err(error),
@ -140,16 +145,21 @@ pub mod qoi_img {
} else { } else {
Err(ImgError::PixelNumberError) Err(ImgError::PixelNumberError)
} }
} }
pub fn from_pixels(pixels: Vec<Pixel>, height: u32, width: u32, channels: u8, colorspace: u8) -> Image { pub fn from_pixels(
pixels: Vec<Pixel>,
height: u32,
width: u32,
channels: u8,
colorspace: u8,
) -> Image {
let img = Image { let img = Image {
pixels, pixels,
height, height,
width, width,
channels, channels,
colorspace colorspace,
}; };
img img
} }
@ -187,22 +197,19 @@ pub mod qoi_img {
Luma, Luma,
Diff, Diff,
RGB, RGB,
RGBA RGBA,
} }
impl Pixel { impl Pixel {
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Pixel { pub fn new(r: u8, g: u8, b: u8, a: u8) -> Pixel {
Pixel { Pixel { r, g, b, a }
r,
g,
b,
a,
}
} }
fn equals(&self, other: &Pixel) -> bool { fn equals(&self, other: &Pixel) -> bool {
if (self.r == other.r) && (self.g == other.g) && (self.b == other.b) && (self.a == other.a) { if (self.r == other.r)
&& (self.g == other.g)
&& (self.b == other.b)
&& (self.a == other.a)
{
true true
} else { } else {
false false
@ -217,10 +224,12 @@ pub mod qoi_img {
} }
} }
//self = curr pixel, other = prev pixel //self = curr pixel, other = prev pixel
pub fn determine_chunk(&self, other: &Pixel, buffer: &Vec<Pixel>) -> (ChunkType, Option<(u8,u8,u8)>){ pub fn determine_chunk(
&self,
other: &Pixel,
buffer: &Vec<Pixel>,
) -> (ChunkType, Option<(u8, u8, u8)>) {
if self.equals(&other) { if self.equals(&other) {
return (ChunkType::Run, None); return (ChunkType::Run, None);
} }
@ -243,7 +252,12 @@ pub mod qoi_img {
let dg: u8 = (dg + DIFF_BIAS as i16) as u8; let dg: u8 = (dg + DIFF_BIAS as i16) as u8;
let db: u8 = (db + DIFF_BIAS as i16) as u8; let db: u8 = (db + DIFF_BIAS as i16) as u8;
return (ChunkType::Diff, Some((dr, dg, db))); return (ChunkType::Diff, Some((dr, dg, db)));
} else if (dg > -33 && dg < 32) && ((dr - dg) > -9) && ((dr - dg) < 8) && ((db - dg) > -9) && ((db - dg) < 8) { } else if (dg > -33 && dg < 32)
&& ((dr - dg) > -9)
&& ((dr - dg) < 8)
&& ((db - dg) > -9)
&& ((db - dg) < 8)
{
let dg_out: u8 = (dg + LUMA_BIAS_G as i16) as u8; let dg_out: u8 = (dg + LUMA_BIAS_G as i16) as u8;
let dr_dg: u8 = (dr - dg + LUMA_BIAS_RB as i16) as u8; let dr_dg: u8 = (dr - dg + LUMA_BIAS_RB as i16) as u8;
let db_dg: u8 = (db - dg + LUMA_BIAS_RB as i16) as u8; let db_dg: u8 = (db - dg + LUMA_BIAS_RB as i16) as u8;
@ -251,7 +265,6 @@ pub mod qoi_img {
} else { } else {
return (ChunkType::RGB, None); return (ChunkType::RGB, None);
} }
} }
pub fn diff(&self, other: &Pixel) -> (i16, i16, i16) { pub fn diff(&self, other: &Pixel) -> (i16, i16, i16) {
let mut dr: i16; let mut dr: i16;
@ -286,7 +299,6 @@ pub mod qoi_img {
} }
(dr, dg, db) (dr, dg, db)
} }
} }
@ -333,12 +345,12 @@ pub mod qoi_img {
//Definition of End of Stream bytes //Definition of End of Stream bytes
#[derive(Debug)] #[derive(Debug)]
struct End { struct End {
bytes: [u8;8] bytes: [u8; 8],
} }
impl End { impl End {
fn new() -> End { fn new() -> End {
End { End {
bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01] bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
} }
} }
} }
@ -359,39 +371,45 @@ pub mod qoi_img {
const LUMA_BIAS_G: u8 = 32; const LUMA_BIAS_G: u8 = 32;
const LUMA_BIAS_RB: u8 = 8; const LUMA_BIAS_RB: u8 = 8;
//hash function for assigning buffer indices to stored pixels //hash function for assigning buffer indices to stored pixels
fn color_hash(pixel: &Pixel) -> u8 { fn color_hash(pixel: &Pixel) -> u8 {
let store: u32 = pixel.r as u32 * 3 + pixel.g as u32 * 5 + pixel.b as u32 * 7 + pixel.a as u32 * 11; let store: u32 =
pixel.r as u32 * 3 + pixel.g as u32 * 5 + pixel.b as u32 * 7 + pixel.a as u32 * 11;
(store % 64) as u8 (store % 64) as u8
} }
pub fn encode_from_image(img: Image) -> Vec<u8> { pub fn encode_from_image(img: Image) -> Vec<u8> {
let mut prev_pixel: Pixel = Pixel {
let mut prev_pixel: Pixel = Pixel {r: 0u8, b: 0u8, g: 0u8, a: 255u8}; r: 0u8,
b: 0u8,
g: 0u8,
a: 255u8,
};
let mut prev_buffer: Vec<Pixel> = Vec::with_capacity(64); let mut prev_buffer: Vec<Pixel> = Vec::with_capacity(64);
for i in 0..64 { for i in 0..64 {
let pix: Pixel = Pixel {r:0,g:0,b:0,a:0}; let pix: Pixel = Pixel {
r: 0,
g: 0,
b: 0,
a: 0,
};
prev_buffer.push(pix); prev_buffer.push(pix);
} }
let mut encoded_bytes: Vec<u8> = Vec::new(); let mut encoded_bytes: Vec<u8> = Vec::new();
let mut run: u8 = 0; let mut run: u8 = 0;
let head = Header { let head = Header {
magic: ['q', 'o', 'i', 'f'], magic: ['q', 'o', 'i', 'f'],
width: img.width, width: img.width,
height: img.height, height: img.height,
channels: img.channels, channels: img.channels,
colorspace: img.colorspace colorspace: img.colorspace,
}; };
let head_stream = head.convert_to_bytestream(); let head_stream = head.convert_to_bytestream();
for i in head_stream { for i in head_stream {
encoded_bytes.push(i); encoded_bytes.push(i);
} }
@ -400,7 +418,8 @@ pub mod qoi_img {
for pixel in img.pixels { for pixel in img.pixels {
counter += 1; counter += 1;
let chunk: (ChunkType, Option<(u8,u8,u8)>) = pixel.determine_chunk(&prev_pixel, &prev_buffer); let chunk: (ChunkType, Option<(u8, u8, u8)>) =
pixel.determine_chunk(&prev_pixel, &prev_buffer);
if chunk == (ChunkType::Run, None) { if chunk == (ChunkType::Run, None) {
run += 1; run += 1;
prev_pixel = pixel.clone(); prev_pixel = pixel.clone();
@ -429,7 +448,7 @@ pub mod qoi_img {
(ChunkType::Index, Some((index, irr1, irr2))) => { (ChunkType::Index, Some((index, irr1, irr2))) => {
encoded_bytes.push(QOI_OP_INDEX | index); encoded_bytes.push(QOI_OP_INDEX | index);
prev_pixel = pixel; prev_pixel = pixel;
}, }
(ChunkType::Diff, Some((dr, dg, db))) => { (ChunkType::Diff, Some((dr, dg, db))) => {
let mut out: u8 = 0b0000_0000; let mut out: u8 = 0b0000_0000;
out = out | db; out = out | db;
@ -438,7 +457,7 @@ pub mod qoi_img {
encoded_bytes.push(QOI_OP_DIFF | out); encoded_bytes.push(QOI_OP_DIFF | out);
prev_pixel = pixel.clone(); prev_pixel = pixel.clone();
prev_buffer[color_hash(&pixel) as usize] = pixel; prev_buffer[color_hash(&pixel) as usize] = pixel;
}, }
(ChunkType::Luma, Some((dg, dr_dg, db_dg))) => { (ChunkType::Luma, Some((dg, dr_dg, db_dg))) => {
let mut out: [u8; 2] = [0b0000_0000; 2]; let mut out: [u8; 2] = [0b0000_0000; 2];
out[0] |= dg; out[0] |= dg;
@ -449,7 +468,7 @@ pub mod qoi_img {
encoded_bytes.push(out[1]); encoded_bytes.push(out[1]);
prev_pixel = pixel.clone(); prev_pixel = pixel.clone();
prev_buffer[color_hash(&pixel) as usize] = pixel; prev_buffer[color_hash(&pixel) as usize] = pixel;
}, }
(ChunkType::RGB, None) => { (ChunkType::RGB, None) => {
encoded_bytes.push(QOI_OP_RGB); encoded_bytes.push(QOI_OP_RGB);
encoded_bytes.push(pixel.r); encoded_bytes.push(pixel.r);
@ -457,7 +476,7 @@ pub mod qoi_img {
encoded_bytes.push(pixel.b); encoded_bytes.push(pixel.b);
prev_pixel = pixel.clone(); prev_pixel = pixel.clone();
prev_buffer[color_hash(&pixel) as usize] = pixel; prev_buffer[color_hash(&pixel) as usize] = pixel;
}, }
(ChunkType::RGBA, None) => { (ChunkType::RGBA, None) => {
if (pixel.a as i16 - prev_pixel.a as i16) == 0i16 { if (pixel.a as i16 - prev_pixel.a as i16) == 0i16 {
//this should never be reached, but it is //this should never be reached, but it is
@ -476,10 +495,11 @@ pub mod qoi_img {
prev_pixel = pixel.clone(); prev_pixel = pixel.clone();
prev_buffer[color_hash(&pixel) as usize] = pixel; prev_buffer[color_hash(&pixel) as usize] = pixel;
} }
},
_ => panic!("Critical error at encoding stage: Illegal output from difference function.")
} }
_ => panic!(
"Critical error at encoding stage: Illegal output from difference function."
),
}
} }
if run > 0 { if run > 0 {
@ -506,11 +526,16 @@ pub mod qoi_img {
} }
info!("Number of pixels processed: {}.", counter); info!("Number of pixels processed: {}.", counter);
info!("Number of bytes in encoding: {:?}.", encoded_bytes.len()-22); info!(
info!("Compression rate: {:.2}%.", (1.0-(encoded_bytes.len()-22) as f64/(counter*4)as f64)*100.0); "Number of bytes in encoding: {:?}.",
encoded_bytes.len() - 22
);
info!(
"Compression rate: {:.2}%.",
(1.0 - (encoded_bytes.len() - 22) as f64 / (counter * 4) as f64) * 100.0
);
encoded_bytes encoded_bytes
} }
pub fn write_to_file(bytes: Vec<u8>, filename: &str) -> std::io::Result<()> { pub fn write_to_file(bytes: Vec<u8>, filename: &str) -> std::io::Result<()> {
@ -528,7 +553,11 @@ pub mod qoi_img {
} }
fn read_header(bytes: &[u8]) -> Result<(u32, u32, u8, u8), ImgError> { fn read_header(bytes: &[u8]) -> Result<(u32, u32, u8, u8), ImgError> {
if bytes[0] == 'q' as u8 && bytes[1] == 'o' as u8 && bytes[2] == 'i' as u8 && bytes[3] == 'f' as u8 { if bytes[0] == 'q' as u8
&& bytes[1] == 'o' as u8
&& bytes[2] == 'i' as u8
&& bytes[3] == 'f' as u8
{
let mut width: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000; let mut width: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
let mut height: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000; let mut height: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
width |= ((bytes[4] as u32) << 24) as u32; width |= ((bytes[4] as u32) << 24) as u32;
@ -631,7 +660,12 @@ pub mod qoi_img {
let channels: u8; let channels: u8;
let colorspace: u8; let colorspace: u8;
let mut prev_pixel: Pixel = Pixel {r: 0u8, g: 0u8, b: 0u8, a: 255u8}; let mut prev_pixel: Pixel = Pixel {
r: 0u8,
g: 0u8,
b: 0u8,
a: 255u8,
};
let mut prev_buffer: [Pixel; 64] = array_init::array_init(|_| Pixel::new(0, 0, 0, 0)); let mut prev_buffer: [Pixel; 64] = array_init::array_init(|_| Pixel::new(0, 0, 0, 0));
@ -641,7 +675,7 @@ pub mod qoi_img {
height = h; height = h;
channels = ch; channels = ch;
colorspace = c; colorspace = c;
}, }
Err(err) => { Err(err) => {
return Err(err); return Err(err);
} }
@ -667,41 +701,40 @@ pub mod qoi_img {
while i < bytes.len() { while i < bytes.len() {
match read_tag(bytes[i]) { match read_tag(bytes[i]) {
Ok(tag) => { Ok(tag) => match tag {
match tag {
ChunkType::RGB => { ChunkType::RGB => {
let dec_pix: Pixel = dec_rgb(&bytes[i..i + 4], prev_pixel.a); let dec_pix: Pixel = dec_rgb(&bytes[i..i + 4], prev_pixel.a);
prev_pixel = dec_pix.clone(); prev_pixel = dec_pix.clone();
prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone(); prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone();
pixels.push(dec_pix); pixels.push(dec_pix);
i += 3; i += 3;
}, }
ChunkType::RGBA => { ChunkType::RGBA => {
let dec_pix: Pixel = dec_rgba(&bytes[i..i + 5]); let dec_pix: Pixel = dec_rgba(&bytes[i..i + 5]);
prev_pixel = dec_pix.clone(); prev_pixel = dec_pix.clone();
prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone(); prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone();
pixels.push(dec_pix); pixels.push(dec_pix);
i += 4; i += 4;
}, }
ChunkType::Diff => { ChunkType::Diff => {
let dec_pix: Pixel = dec_diff(bytes[i], &prev_pixel); let dec_pix: Pixel = dec_diff(bytes[i], &prev_pixel);
prev_pixel = dec_pix.clone(); prev_pixel = dec_pix.clone();
prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone(); prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone();
pixels.push(dec_pix); pixels.push(dec_pix);
}, }
ChunkType::Index => { ChunkType::Index => {
let dec_pix: Pixel = prev_buffer[bytes[i] as usize]; let dec_pix: Pixel = prev_buffer[bytes[i] as usize];
prev_pixel = dec_pix.clone(); prev_pixel = dec_pix.clone();
prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone(); prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone();
pixels.push(dec_pix); pixels.push(dec_pix);
}, }
ChunkType::Luma => { ChunkType::Luma => {
let dec_pix: Pixel = dec_luma(&bytes[i..i + 2], &prev_pixel); let dec_pix: Pixel = dec_luma(&bytes[i..i + 2], &prev_pixel);
prev_pixel = dec_pix.clone(); prev_pixel = dec_pix.clone();
prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone(); prev_buffer[color_hash(&dec_pix) as usize] = dec_pix.clone();
pixels.push(dec_pix); pixels.push(dec_pix);
i += 1; i += 1;
}, }
ChunkType::Run => { ChunkType::Run => {
let length: u8 = (bytes[i] & 0b00111111) + RUN_BIAS; let length: u8 = (bytes[i] & 0b00111111) + RUN_BIAS;
for j in 0..length { for j in 0..length {
@ -709,7 +742,6 @@ pub mod qoi_img {
} }
prev_buffer[color_hash(&prev_pixel) as usize] = prev_pixel.clone(); prev_buffer[color_hash(&prev_pixel) as usize] = prev_pixel.clone();
} }
}
}, },
Err(err) => return Err(err), Err(err) => return Err(err),
} }
@ -724,15 +756,14 @@ pub mod qoi_img {
let img = Image::from_pixels(pixels, height, width, channels, colorspace); let img = Image::from_pixels(pixels, height, width, channels, colorspace);
Ok(img) Ok(img)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::io;
use std::io::{Read, BufReader};
use std::fs::File; use std::fs::File;
use std::io;
use std::io::{BufReader, Read};
#[test] #[test]
fn diff_test() { fn diff_test() {
@ -761,7 +792,7 @@ mod tests {
match super::decode(bytes) { match super::decode(bytes) {
Ok(img) => out_img = img, Ok(img) => out_img = img,
Err(err) => panic!("wallah geht nicht :/ {:?}", err) Err(err) => panic!("wallah geht nicht :/ {:?}", err),
} }
write_to_file(encode_from_image(out_img), "test_dec").expect("wallahi!"); write_to_file(encode_from_image(out_img), "test_dec").expect("wallahi!");
Ok(()) Ok(())
@ -779,13 +810,12 @@ mod tests {
match super::decode(bytes) { match super::decode(bytes) {
Ok(img) => out_img = img, Ok(img) => out_img = img,
Err(err) => panic!("Ja bruder war nicht so erfolgreich ahahahahahha {:?}", err) Err(err) => panic!("Ja bruder war nicht so erfolgreich ahahahahahha {:?}", err),
} }
write_to_file(encode_from_image(out_img), "testcard_new").expect("Boowomb!"); write_to_file(encode_from_image(out_img), "testcard_new").expect("Boowomb!");
Ok(()) Ok(())
} }
#[test] #[test]
@ -798,7 +828,6 @@ mod tests {
let test_diff: u8 = 0b0110_1010; let test_diff: u8 = 0b0110_1010;
let test_index: u8 = 0b0010_1010; let test_index: u8 = 0b0010_1010;
assert_eq!(Ok(ChunkType::RGB), super::read_tag(test_rgb)); assert_eq!(Ok(ChunkType::RGB), super::read_tag(test_rgb));
assert_eq!(Ok(ChunkType::RGBA), super::read_tag(test_rgba)); assert_eq!(Ok(ChunkType::RGBA), super::read_tag(test_rgba));
assert_eq!(Ok(ChunkType::Luma), super::read_tag(test_luma)); assert_eq!(Ok(ChunkType::Luma), super::read_tag(test_luma));
@ -810,19 +839,37 @@ mod tests {
#[test] #[test]
fn sub_decoders_test() { fn sub_decoders_test() {
//init().expect("Logger initialisation failed!"); //init().expect("Logger initialisation failed!");
let pix: Pixel = Pixel { r: 255, g: 255, b: 255, a: 255 }; let pix: Pixel = Pixel {
let prev: Pixel = Pixel { r: 1, g: 1, b: 1, a: 255 }; r: 255,
g: 255,
b: 255,
a: 255,
};
let prev: Pixel = Pixel {
r: 1,
g: 1,
b: 1,
a: 255,
};
let byte: u8 = 0b01000000; let byte: u8 = 0b01000000;
assert_eq!(pix, dec_diff(byte, &prev)); assert_eq!(pix, dec_diff(byte, &prev));
let pix: Pixel = Pixel { r: 17, g: 22, b: 28, a: 100 }; let pix: Pixel = Pixel {
let prev: Pixel = Pixel { r: 10, g: 10, b: 10, a: 100 }; r: 17,
g: 22,
b: 28,
a: 100,
};
let prev: Pixel = Pixel {
r: 10,
g: 10,
b: 10,
a: 100,
};
let byte: [u8; 2] = [0b10101100, 0b00111110]; let byte: [u8; 2] = [0b10101100, 0b00111110];
assert_eq!(pix, dec_luma(&byte[0..2], &prev)); assert_eq!(pix, dec_luma(&byte[0..2], &prev));
} }
} }
} }

View File

@ -6,7 +6,7 @@ use std::time::SystemTime;
use colors_transform::{Color, Hsl, Rgb}; use colors_transform::{Color, Hsl, Rgb};
use png; use png;
use qoi_test::qoi_img::*; use qoi::qoi_lib::*;
fn encode_checkerboard() { fn encode_checkerboard() {
let mut pixels: Vec<Pixel> = Vec::with_capacity(64 * 64); let mut pixels: Vec<Pixel> = Vec::with_capacity(64 * 64);
@ -191,7 +191,7 @@ fn decode(args: &Vec<String>) -> io::Result<()> {
reader.read_to_end(&mut bytes)?; reader.read_to_end(&mut bytes)?;
match qoi_test::qoi_img::decode(bytes) { match qoi::qoi_lib::decode(bytes) {
Ok(_img) => println!("Decoding successful!"), Ok(_img) => println!("Decoding successful!"),
Err(err) => panic!("ERROR: {err:?}"), Err(err) => panic!("ERROR: {err:?}"),
} }
@ -249,6 +249,9 @@ fn main() {
"bench" => { "bench" => {
bench(&args); bench(&args);
} }
"help" => {
println!("qoi supports the following commands: \n encode [IMAGE] (encodes given png-encoded into .qoi) \n decode [IMAGE] decodes given .qoi to .png \n bench [INPUT] [OUTPUT] encodes input .png into .qoi with encoding speed measured in microseconds.")
}
_ => { _ => {
panic!("Invalid arguments!") panic!("Invalid arguments!")
} }