diff --git a/src/commands.rs b/src/commands.rs index 4fe6f68..6456f9d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,35 +1,35 @@ use std::fs::File; use std::path::PathBuf; -use crate::decoder::Decoder; -use crate::encoder::Encoder; -use crate::frave_image::{get_quantization_matrix, FraveImage, Frv}; -use crate::variants::Variant; +use crate::compression::decoder::Decoder; +use crate::compression::encoder::Encoder; +use crate::fractal::image::{get_quantization_matrix, FractalImage, Frv}; +use crate::fractal::variants::Variant; pub fn encode(path: PathBuf, var: Variant, output: String) { let img = image::open(path).unwrap_or_else(|e| { - panic!("Failed to open: {}", e); + panic!("Failed to open: {e}"); }); - let mut enc = FraveImage::new_from_img(img.into_luma8(), var); + let mut enc = FractalImage::new_from_img(img.into_luma8(), var); enc.find_coef(); // enc.quantizate(&get_quantization_matrix()); let (coef, contexts) = enc.ans_encode(); let compressed = Frv::new(enc.height, enc.width, contexts, var, coef); - let mut f = File::create(output).unwrap(); + let mut f = File::create(output).unwrap_or_else(|e| panic!("Failed to encode frv image: {e}")); bincode::serialize_into(&mut f, &compressed).unwrap(); } pub fn decode(path: PathBuf, output: String) { let img = File::open(path).unwrap_or_else(|e| { - panic!("Failed to open: {}", e); + panic!("Failed to open: {e}"); }); let frv_img: Frv = bincode::deserialize_from(img).unwrap(); - let mut dec = FraveImage::new_from_frv(&frv_img); - dec.ans_decode(frv_img.compressed_coef, frv_img.ans_contexts); + let mut dec = FractalImage::new_from_frv(&frv_img); + dec.ans_decode(frv_img.data, frv_img.ans_contexts); // dec.unquantizate(&get_quantization_matrix()); dec.find_val(); dec.image.save(output).unwrap_or_else(|e| { - panic!("Failed to save: {}", e); + panic!("Failed to decode frv image: {e}"); }); } diff --git a/src/utils/ans.rs b/src/compression/ans.rs similarity index 86% rename from src/utils/ans.rs rename to src/compression/ans.rs index 23224ac..c668486 100644 --- a/src/utils/ans.rs +++ b/src/compression/ans.rs @@ -7,10 +7,11 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct AnsContext { - pub symbols: Vec>, + pub symbols: Vec, pub freq: Vec, } +#[must_use] pub fn cum_sum(sum: &[u32]) -> Vec { sum.iter() .scan(0_u32, |acc, x| { @@ -21,6 +22,8 @@ pub fn cum_sum(sum: &[u32]) -> Vec { .collect::>() } +// TODO: Implement Alias sampling method +#[must_use] pub fn find_nearest_or_equal(cum_freq: u32, cum_freqs: &[u32]) -> u32 { match cum_freqs.binary_search(&cum_freq) { Ok(x) => cum_freqs[x], @@ -28,6 +31,7 @@ pub fn find_nearest_or_equal(cum_freq: u32, cum_freqs: &[u32]) -> u32 { } } +#[must_use] pub fn freqs_to_enc_symbols( cum_freq: &[u32], freq: &[u32], @@ -39,12 +43,13 @@ pub fn freqs_to_enc_symbols( .map(|(&cum_freq, &freq)| { ( cum_freq, - B64RansEncSymbol::new(cum_freq, freq, (depth - 1) as u32), + B64RansEncSymbol::new(cum_freq, freq, u32::try_from(depth - 1).unwrap()), ) }) .collect::>() } +#[must_use] pub fn freqs_to_dec_symbols(cum_freq: &[u32], freq: &[u32]) -> HashMap { cum_freq .iter() diff --git a/src/decoder.rs b/src/compression/decoder.rs similarity index 73% rename from src/decoder.rs rename to src/compression/decoder.rs index 1ed5367..b69dbb3 100644 --- a/src/decoder.rs +++ b/src/compression/decoder.rs @@ -1,15 +1,12 @@ use std::collections::HashMap; -use image::GrayImage; use rans::b64_decoder::B64RansDecoderMulti; use rans::RansDecoderMulti; -use crate::coord::Coord; -use crate::frave_image::get_quantization_matrix; -use crate::frave_image::FraveImage; -use crate::utils::ans; -use crate::utils::ans::AnsContext; +use crate::compression::ans::{self, AnsContext}; +use crate::fractal::image::FractalImage; use crate::utils::bitwise; +use crate::utils::coordinate::Coord; pub trait Decoder { /// Entropy decoding step of decoder procedure. @@ -31,15 +28,15 @@ pub trait Decoder { fn fn_vl(&mut self, sum: i32, ps: usize, cn: Coord, dp: usize); } -impl Decoder for FraveImage { +impl Decoder for FractalImage { fn unquantizate(&mut self, quantization_matrix: &[i32]) { self.coef = self .coef .iter() .enumerate() .map(|(i, coefficient)| { - let layer = bitwise::get_prev_power_two(i as u32 + 1).trailing_zeros(); - (*coefficient).and_then(|s| Some(s * quantization_matrix[layer as usize])) + let layer = bitwise::get_prev_power_two(i + 1).trailing_zeros(); + (*coefficient).map(|s| s * quantization_matrix[layer as usize]) }) .collect::>>(); } @@ -47,9 +44,8 @@ impl Decoder for FraveImage { fn find_val(&mut self) { if let Some(root) = self.coef[0] { self.fn_vl(root, 1, self.center, self.depth - 1); - } - else { - println!("whoops") + } else { + println!("whoops"); } } @@ -59,11 +55,11 @@ impl Decoder for FraveImage { let rt: i32 = ((sum + dif) * 2) >> 1; if dp > 0 { self.fn_vl(lt, ps << 1, cn, dp - 1); - self.fn_vl(rt, (ps << 1) + 1, cn + self.variant[dp], dp - 1) + self.fn_vl(rt, (ps << 1) + 1, cn + self.variant[dp], dp - 1); } else { - let secondary_x = (cn.x + self.variant[0].x) as u32; - let secondary_y = (cn.y + self.variant[0].y) as u32; - self.set_pixel(cn.x as u32, cn.y as u32, lt); + let secondary_x = cn.x + self.variant[0].x; + let secondary_y = cn.y + self.variant[0].y; + self.set_pixel(cn.x, cn.y, lt); self.set_pixel(secondary_x, secondary_y, rt); } } @@ -72,7 +68,7 @@ impl Decoder for FraveImage { fn ans_decode(&mut self, compressed_coef: Vec, ans_contexts: Vec) { let mut coef = vec![]; let depth = self.depth; - let scale_bits = (depth - 1) as u32; + let scale_bits = u32::try_from(depth - 1).unwrap(); let mut decoder: B64RansDecoderMulti<3> = B64RansDecoderMulti::new(compressed_coef); let ctxs = ans_contexts; let layers = vec![ @@ -81,24 +77,23 @@ impl Decoder for FraveImage { (1 << (depth - 1))..(1 << depth), ]; for (i, layer) in layers.iter().enumerate() { - let cum_freqs = ans::cum_sum(&ctxs[2 - i].freq); + let mut cum_freqs = ans::cum_sum(&ctxs[2 - i].freq); let cum_freq_to_symbols = ans::freqs_to_dec_symbols(&cum_freqs, &ctxs[2 - i].freq); let symbol_map = cum_freqs - .iter() - .map(|e| e.to_owned()) + .clone() + .into_iter() .zip(ctxs[2 - i].symbols.clone()) - .collect::>>(); + .collect::>(); - let mut cum_freqs_sorted = cum_freqs.to_owned(); - cum_freqs_sorted.sort(); + cum_freqs.sort_unstable(); for _l in layer.clone() { let cum_freq_decoded = - ans::find_nearest_or_equal(decoder.get_at(i, scale_bits), &cum_freqs_sorted); + ans::find_nearest_or_equal(decoder.get_at(i, scale_bits), &cum_freqs); let symbol = symbol_map[&cum_freq_decoded]; decoder.advance_step_at(i, &cum_freq_to_symbols[&cum_freq_decoded], scale_bits); decoder.renorm_at(i); - coef.push(symbol); + coef.push(Some(symbol)); } } self.coef = coef; diff --git a/src/encoder.rs b/src/compression/encoder.rs similarity index 77% rename from src/encoder.rs rename to src/compression/encoder.rs index 58890fa..02a7ff9 100644 --- a/src/encoder.rs +++ b/src/compression/encoder.rs @@ -1,21 +1,20 @@ use std::collections::HashMap; use std::vec; +use itertools::Itertools; use rans::b64_encoder::B64RansEncoderMulti; use rans::RansEncoderMulti; -use crate::coord::Coord; -use crate::frave_image::FraveImage; -use crate::utils::ans; -use crate::utils::ans::AnsContext; +use crate::compression::ans::{self, AnsContext}; +use crate::fractal::image::FractalImage; use crate::utils::bitwise; -use itertools::Itertools; +use crate::utils::coordinate::Coord; fn try_apply(first: Option, second: Option, operation: fn(T, T) -> T) -> Option { match (first, second) { (Some(f), Some(s)) => Some(operation(f, s)), - (Some(f), None) => Some(operation(f,f)), - (None, Some(s)) => Some(operation(s,s)), + (Some(f), None) => Some(operation(f, f)), + (None, Some(s)) => Some(operation(s, s)), (None, None) => None, } } @@ -42,11 +41,11 @@ pub trait Encoder { /// - Haar tree pre-last layer /// - Rest of the Haar tree /// - /// Applies rANS algorithm for coefficient compression + /// Applies `rANS` algorithm for coefficient compression fn ans_encode(&self) -> (Vec, Vec); } -impl Encoder for FraveImage { +impl Encoder for FractalImage { fn find_coef(&mut self) { let lt = self.fn_cf(self.center, 2, self.depth - 2); let rt = self.fn_cf( @@ -65,11 +64,8 @@ impl Encoder for FraveImage { lt = self.fn_cf(cn, ps << 1, dp - 1); rt = self.fn_cf(cn + self.variant[dp], (ps << 1) + 1, dp - 1); } else { - lt = self.get_pixel(cn.x as u32, cn.y as u32); - rt = self.get_pixel( - (cn.x + self.variant[0].x) as u32, - (cn.y + self.variant[0].y) as u32, - ); + lt = self.get_pixel(cn.x, cn.y); + rt = self.get_pixel(cn.x + self.variant[0].x, cn.y + self.variant[0].y); } self.coef[ps] = try_apply(rt, lt, |r, l| (r - l) / 2); @@ -82,13 +78,14 @@ impl Encoder for FraveImage { .iter() .enumerate() .map(|(i, coefficient)| { - let layer = bitwise::get_prev_power_two(i as u32 + 1).trailing_zeros(); - (*coefficient).and_then(|s| Some(s / quantization_matrix[layer as usize])) + let layer = bitwise::get_prev_power_two(i + 1).trailing_zeros(); + (*coefficient).map(|s| s / quantization_matrix[layer as usize]) }) .collect::>>(); } fn ans_encode(&self) -> (Vec, Vec) { + dbg!(&self.coef); let layer1 = &self.coef[1 << (self.depth - 1)..]; let layer2 = &self.coef[1 << (self.depth - 2)..1 << (self.depth - 1)]; let layer3 = &self.coef[..1 << (self.depth - 2)]; @@ -96,10 +93,14 @@ impl Encoder for FraveImage { let mut encoder: B64RansEncoderMulti<3> = B64RansEncoderMulti::new(1 << self.depth); let mut contexts: Vec = vec![]; - for (i, layer) in [layer1, layer2, layer3].iter().enumerate() { - let counter = layer.iter().counts(); - let freq = counter.values().map(|e| *e as u32).collect::>(); - let symbols = counter.keys().map(|e| **e).collect::>>(); + for (i, layer) in [layer1, layer2, layer3].into_iter().enumerate() { + let some_layer = layer.iter().flatten(); + let counter = some_layer.clone().counts(); + let freq = counter + .values() + .map(|e| u32::try_from(*e).unwrap()) + .collect::>(); + let symbols = counter.keys().map(|e| **e).collect::>(); let cdf = ans::cum_sum(&freq); let symbol_map = ans::freqs_to_enc_symbols(&cdf, &freq, self.depth); @@ -107,12 +108,10 @@ impl Encoder for FraveImage { let cdf_map = counter .clone() .into_keys() - .map(|e| e.to_owned()) .zip(cdf.clone()) - .collect::, u32>>(); + .collect::>(); - layer - .iter() + some_layer .rev() .for_each(|s| encoder.put_at(i, &symbol_map[&cdf_map[s]])); diff --git a/src/compression/mod.rs b/src/compression/mod.rs new file mode 100644 index 0000000..af9f38a --- /dev/null +++ b/src/compression/mod.rs @@ -0,0 +1,3 @@ +pub mod ans; +pub mod decoder; +pub mod encoder; diff --git a/src/frave_image.rs b/src/fractal/image.rs similarity index 63% rename from src/frave_image.rs rename to src/fractal/image.rs index 587fb8b..a6b637c 100644 --- a/src/frave_image.rs +++ b/src/fractal/image.rs @@ -1,11 +1,41 @@ -use crate::coord::Coord; -use crate::utils::ans::AnsContext; -use crate::variants::{get_variant, Variant}; +use std::cmp; + use image::GrayImage; use serde::{Deserialize, Serialize}; -use std::cmp; -pub struct FraveImage { +use crate::compression::ans::AnsContext; +use crate::fractal::variants::Variant; +use crate::utils::coordinate::Coord; + +#[derive(Serialize, Deserialize)] +pub struct Frv { + height: u32, + width: u32, + variant: Variant, + pub ans_contexts: Vec, + #[serde(with = "serde_bytes")] + pub data: Vec, +} + +impl Frv { + pub fn new( + height: u32, + width: u32, + ans_contexts: Vec, + variant: Variant, + data: Vec, + ) -> Self { + Self { + height, + width, + variant, + ans_contexts, + data, + } + } +} + +pub struct FractalImage { pub height: u32, pub width: u32, pub depth: usize, @@ -15,40 +45,46 @@ pub struct FraveImage { pub image: GrayImage, } -impl FraveImage { +impl FractalImage { pub fn new_from_img(image: GrayImage, variant: Variant) -> Self { let width: u32 = image.width(); let height: u32 = image.height(); - let variant = get_variant(variant); + let variant = variant.get_variant(); let depth: usize = Self::calculate_depth(width, height, variant); - let center = Coord{ x: width as i32 / 2, y: height as i32/2}; //;Self::find_center(depth, variant); + let center = Coord { + x: width as i32 / 2, + y: height as i32 / 2, + }; //;Self::find_center(depth, variant); dbg!(depth, center); - FraveImage { - width, + Self { height, + width, depth, - center: center, //, + center, + variant, coef: vec![None; 1 << depth], image, - variant, } } pub fn new_from_frv(frv: &Frv) -> Self { let width = frv.width; let height = frv.height; - let variant = get_variant(frv.variant); + let variant = frv.variant.get_variant(); let depth = Self::calculate_depth(width, height, variant); - let center = Coord{ x: width as i32 /2, y: height as i32/2}; //;Self::find_center(depth, variant); - - FraveImage { - width, + let center = Coord { + x: width as i32 / 2, + y: height as i32 / 2, + }; //;Self::find_center(depth, variant); + + Self { height, + width, depth, center, - coef: vec![None; 1 << depth], variant, + coef: vec![None; 1 << depth], image: GrayImage::new(width, height), } } @@ -57,16 +93,13 @@ impl FraveImage { variant .into_iter() .scan((0, 0, 0), |accum, value| { - *accum = ( - accum.0 + 1, - value.x.abs(), - value.y.abs(), - ); + *accum = (accum.0 + 1, value.x.abs(), value.y.abs()); Some(*accum) }) .find(|&(_i, rw, rh)| img_w as i32 <= rw && img_h as i32 <= rh) .unwrap() - .0 - 1 + .0 + - 1 } fn find_center(depth: usize, variant: [Coord; 30]) -> Coord { @@ -79,60 +112,34 @@ impl FraveImage { } #[inline] - pub fn get_pixel(&self, x: u32, y: u32) -> Option { + pub fn get_pixel(&self, x: i32, y: i32) -> Option { + let (x, y) = (x as u32, y as u32); if x < self.width && y < self.height { - let [gray] = self - .image - .get_pixel(x % self.width, y % self.height) - .0; // we assume grayscale for now - Some(gray as i32) - } - else { + let [gray] = self.image.get_pixel(x % self.width, y % self.height).0; // we assume grayscale for now + Some(i32::from(gray)) + } else { None } } #[inline] - pub fn set_pixel(&mut self, x: u32, y: u32, v: i32) { - let gray: u8 = cmp::max(0, cmp::min(v, 255)) as u8; + pub fn set_pixel(&mut self, x: i32, y: i32, v: i32) { + let (x, y) = (u32::try_from(x).unwrap(), u32::try_from(y).unwrap()); + let gray = v.clamp(0, 255) as u8; if x < self.width && y < self.height { - self.image.put_pixel(x,y,image::Luma([gray])) - } - } -} - -#[derive(Serialize, Deserialize)] -pub struct Frv { - height: u32, - width: u32, - variant: Variant, - pub ans_contexts: Vec, - #[serde(with = "serde_bytes")] - pub compressed_coef: Vec, -} - -impl Frv { - pub fn new( - height: u32, - width: u32, - ans_contexts: Vec, - variant: Variant, - compressed_coef: Vec, - ) -> Self { - Frv { - height, - width, - ans_contexts, - variant, - compressed_coef, + self.image.put_pixel(x, y, image::Luma([gray])); } } } +#[must_use] pub fn get_quantization_matrix_soft() -> Vec { vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 6, 2] } +#[must_use] pub fn get_quantization_matrix() -> Vec { - vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 9, 2] + vec![ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 9, 2, + ] } diff --git a/src/fractal/mod.rs b/src/fractal/mod.rs new file mode 100644 index 0000000..d8916f8 --- /dev/null +++ b/src/fractal/mod.rs @@ -0,0 +1,3 @@ +pub mod haar_tree; +pub mod image; +pub mod variants; diff --git a/src/fractal/variants.rs b/src/fractal/variants.rs new file mode 100644 index 0000000..2264db9 --- /dev/null +++ b/src/fractal/variants.rs @@ -0,0 +1,157 @@ +use crate::utils::coordinate::Coord; +use clap::ValueEnum; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Serialize, Deserialize)] +pub enum Variant { + Boxes, + Twindragon, + TameTwindragon, + SkewedTameTwindragon, +} + +// TODO: Write generator for these numbers +impl Variant { + #[must_use] + pub const fn get_variant(&self) -> [Coord; 30] { + match self { + Self::Boxes => [ + Coord { x: 1, y: 0 }, + Coord { x: 0, y: 1 }, + Coord { x: -2, y: 0 }, + Coord { x: 0, y: -2 }, + Coord { x: 4, y: 0 }, + Coord { x: 0, y: 4 }, + Coord { x: -8, y: 0 }, + Coord { x: 0, y: -8 }, + Coord { x: 16, y: 0 }, + Coord { x: 0, y: 16 }, + Coord { x: -32, y: 0 }, + Coord { x: 0, y: -32 }, + Coord { x: 64, y: 0 }, + Coord { x: 0, y: 64 }, + Coord { x: -128, y: 0 }, + Coord { x: 0, y: -128 }, + Coord { x: 256, y: 0 }, + Coord { x: 0, y: 256 }, + Coord { x: -512, y: 0 }, + Coord { x: 0, y: -512 }, + Coord { x: 1024, y: 0 }, + Coord { x: 0, y: 1024 }, + Coord { x: -2048, y: 0 }, + Coord { x: 0, y: -2048 }, + Coord { x: 4096, y: 0 }, + Coord { x: 0, y: 4096 }, + Coord { x: -8192, y: 0 }, + Coord { x: 0, y: -8192 }, + Coord { x: 16384, y: 0 }, + Coord { x: 0, y: 16384 }, + ], + Self::Twindragon => [ + Coord { x: 1, y: 0 }, + Coord { x: -1, y: 1 }, + Coord { x: 0, y: -2 }, + Coord { x: 2, y: 2 }, + Coord { x: -4, y: 0 }, + Coord { x: 4, y: -4 }, + Coord { x: 0, y: 8 }, + Coord { x: -8, y: -8 }, + Coord { x: 16, y: 0 }, + Coord { x: -16, y: 16 }, + Coord { x: 0, y: -32 }, + Coord { x: 32, y: 32 }, + Coord { x: -64, y: 0 }, + Coord { x: 64, y: -64 }, + Coord { x: 0, y: 128 }, + Coord { x: -128, y: -128 }, + Coord { x: 256, y: 0 }, + Coord { x: -256, y: 256 }, + Coord { x: 0, y: -512 }, + Coord { x: 512, y: 512 }, + Coord { x: -1024, y: 0 }, + Coord { x: 1024, y: -1024 }, + Coord { x: 0, y: 2048 }, + Coord { x: -2048, y: -2048 }, + Coord { x: 4096, y: 0 }, + Coord { x: -4096, y: 4096 }, + Coord { x: 0, y: -8192 }, + Coord { x: 8192, y: 8192 }, + Coord { x: -16384, y: 0 }, + Coord { + x: 16384, + y: -16384, + }, + ], + Self::TameTwindragon => [ + Coord { x: 0, y: 1 }, + Coord { x: -1, y: 1 }, + Coord { x: 2, y: 0 }, + Coord { x: -3, y: -1 }, + Coord { x: 5, y: -1 }, + Coord { x: 1, y: 3 }, + Coord { x: -11, y: -1 }, + Coord { x: 9, y: -5 }, + Coord { x: 13, y: 7 }, + Coord { x: -31, y: 3 }, + Coord { x: 5, y: -17 }, + Coord { x: 57, y: 11 }, + Coord { x: -67, y: 23 }, + Coord { x: -47, y: -45 }, + Coord { x: 181, y: -1 }, + Coord { x: -87, y: 91 }, + Coord { x: -275, y: -89 }, + Coord { x: 449, y: -93 }, + Coord { x: 101, y: 271 }, + Coord { x: -999, y: -85 }, + Coord { x: 797, y: -457 }, + Coord { x: 1201, y: 627 }, + Coord { x: -2795, y: 287 }, + Coord { x: 393, y: -1541 }, + Coord { x: 5197, y: 967 }, + Coord { x: -5983, y: 2115 }, + Coord { x: -4411, y: -4049 }, + Coord { x: 16377, y: -181 }, + Coord { x: -7555, y: 8279 }, + Coord { + x: -25199, + y: -7917, + }, + ], + Self::SkewedTameTwindragon => [ + Coord { x: 1, y: 1 }, + Coord { x: -1, y: -2 }, + Coord { x: 3, y: 2 }, + Coord { x: -1, y: 2 }, + Coord { x: -5, y: -6 }, + Coord { x: 7, y: 2 }, + Coord { x: 3, y: 10 }, + Coord { x: -17, y: -14 }, + Coord { x: 11, y: -6 }, + Coord { x: 23, y: 34 }, + Coord { x: -45, y: -22 }, + Coord { x: -1, y: -46 }, + Coord { x: 91, y: 90 }, + Coord { x: -89, y: 2 }, + Coord { x: -93, y: -182 }, + Coord { x: 271, y: 178 }, + Coord { x: -85, y: 186 }, + Coord { x: -457, y: -542 }, + Coord { x: 627, y: 170 }, + Coord { x: 287, y: 914 }, + Coord { x: -1541, y: -1254 }, + Coord { x: 967, y: -574 }, + Coord { x: 2115, y: 3082 }, + Coord { x: -4049, y: -1934 }, + Coord { x: -181, y: -4230 }, + Coord { x: 8279, y: 8098 }, + Coord { x: -7917, y: 362 }, + Coord { + x: -8641, + y: -16558, + }, + Coord { x: 24475, y: 15834 }, + Coord { x: -1, y: 0 }, + ], + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 5a7d5c1..6d1154a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,4 @@ pub mod commands; -pub mod coord; -pub mod decoder; -pub mod encoder; -pub mod frave_image; +pub mod compression; +pub mod fractal; mod utils; -pub mod variants; diff --git a/src/main.rs b/src/main.rs index f7c0d54..ae411f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use frave::commands::{decode, encode}; use std::path::PathBuf; use clap::{Args, Parser, Subcommand}; -use frave::variants::Variant; +use frave::fractal::variants::Variant; #[derive(Parser)] #[command(author, version, about, long_about = None)] diff --git a/src/utils/bitwise.rs b/src/utils/bitwise.rs index 4300e20..5eb2864 100644 --- a/src/utils/bitwise.rs +++ b/src/utils/bitwise.rs @@ -1,4 +1,4 @@ -pub fn get_prev_power_two(x: u32) -> u32 { +pub const fn get_prev_power_two(x: usize) -> usize { let mut num = x; num |= num >> 1; num |= num >> 2; diff --git a/src/coord.rs b/src/utils/coordinate.rs similarity index 59% rename from src/coord.rs rename to src/utils/coordinate.rs index 3cfefb8..726e63d 100644 --- a/src/coord.rs +++ b/src/utils/coordinate.rs @@ -6,10 +6,10 @@ pub struct Coord { pub y: i32, } -impl ops::Add for Coord { - type Output = Coord; - fn add(self, rhs: Coord) -> Self::Output { - Coord { +impl ops::Add for Coord { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self { x: self.x + rhs.x, y: self.y + rhs.y, } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 4675bd4..d7fae66 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,2 @@ -pub mod ans; pub mod bitwise; +pub mod coordinate; diff --git a/src/utils/trimmer.rs b/src/utils/trimmer.rs deleted file mode 100644 index c8beb8b..0000000 --- a/src/utils/trimmer.rs +++ /dev/null @@ -1,28 +0,0 @@ -use image::GrayImage; - -pub fn mirrors(img: GrayImage, frame: u32) -> GrayImage { - let (w, h) = (img.width(), img.height()); - let mut lattice = GrayImage::new(w + frame * 2, h + frame * 2); - let mirrored_rows = (0..=(frame - 1)) - .rev() - .chain(0..=(w - 1)) - .chain(((h - frame)..=(w - 1)).rev()); - for (row, mirrored_row) in mirrored_rows.enumerate() { - for x in 0..(w + frame * 2) { - if x < frame { - lattice.put_pixel(x, row as u32, *img.get_pixel(frame - 1 - x, mirrored_row)) - } else if x >= frame && x < w + frame { - lattice.put_pixel(x, row as u32, *img.get_pixel(x - frame, mirrored_row)) - } else { - lattice.put_pixel( - x, - row as u32, - *img.get_pixel(2 * w + frame - 1 - x, mirrored_row), - ) - } - } - } - lattice -} - - diff --git a/src/variants.rs b/src/variants.rs deleted file mode 100644 index 0dae891..0000000 --- a/src/variants.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::coord::Coord; -use clap::ValueEnum; -use serde::{Deserialize, Serialize}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Serialize, Deserialize)] -pub enum Variant { - Boxes, - Twindragon, - TameTwindragon, - SkewedTameTwindragon, -} - -// TODO: Write generator for these numbers -pub fn get_variant(var: Variant) -> [Coord; 30] { - match var { - Variant::Boxes => [ - Coord { x: 1, y: 0 }, - Coord { x: 0, y: 1 }, - Coord { x: -2, y: 0 }, - Coord { x: 0, y: -2 }, - Coord { x: 4, y: 0 }, - Coord { x: 0, y: 4 }, - Coord { x: -8, y: 0 }, - Coord { x: 0, y: -8 }, - Coord { x: 16, y: 0 }, - Coord { x: 0, y: 16 }, - Coord { x: -32, y: 0 }, - Coord { x: 0, y: -32 }, - Coord { x: 64, y: 0 }, - Coord { x: 0, y: 64 }, - Coord { x: -128, y: 0 }, - Coord { x: 0, y: -128 }, - Coord { x: 256, y: 0 }, - Coord { x: 0, y: 256 }, - Coord { x: -512, y: 0 }, - Coord { x: 0, y: -512 }, - Coord { x: 1024, y: 0 }, - Coord { x: 0, y: 1024 }, - Coord { x: -2048, y: 0 }, - Coord { x: 0, y: -2048 }, - Coord { x: 4096, y: 0 }, - Coord { x: 0, y: 4096 }, - Coord { x: -8192, y: 0 }, - Coord { x: 0, y: -8192 }, - Coord { x: 16384, y: 0 }, - Coord { x: 0, y: 16384 }, - ], - Variant::Twindragon => [ - Coord { x: 1, y: 0 }, - Coord { x: -1, y: 1 }, - Coord { x: 0, y: -2 }, - Coord { x: 2, y: 2 }, - Coord { x: -4, y: 0 }, - Coord { x: 4, y: -4 }, - Coord { x: 0, y: 8 }, - Coord { x: -8, y: -8 }, - Coord { x: 16, y: 0 }, - Coord { x: -16, y: 16 }, - Coord { x: 0, y: -32 }, - Coord { x: 32, y: 32 }, - Coord { x: -64, y: 0 }, - Coord { x: 64, y: -64 }, - Coord { x: 0, y: 128 }, - Coord { x: -128, y: -128 }, - Coord { x: 256, y: 0 }, - Coord { x: -256, y: 256 }, - Coord { x: 0, y: -512 }, - Coord { x: 512, y: 512 }, - Coord { x: -1024, y: 0 }, - Coord { x: 1024, y: -1024 }, - Coord { x: 0, y: 2048 }, - Coord { x: -2048, y: -2048 }, - Coord { x: 4096, y: 0 }, - Coord { x: -4096, y: 4096 }, - Coord { x: 0, y: -8192 }, - Coord { x: 8192, y: 8192 }, - Coord { x: -16384, y: 0 }, - Coord { - x: 16384, - y: -16384, - }, - ], - Variant::TameTwindragon => [ - Coord { x: 0, y: 1 }, - Coord { x: -1, y: 1 }, - Coord { x: 2, y: 0 }, - Coord { x: -3, y: -1 }, - Coord { x: 5, y: -1 }, - Coord { x: 1, y: 3 }, - Coord { x: -11, y: -1 }, - Coord { x: 9, y: -5 }, - Coord { x: 13, y: 7 }, - Coord { x: -31, y: 3 }, - Coord { x: 5, y: -17 }, - Coord { x: 57, y: 11 }, - Coord { x: -67, y: 23 }, - Coord { x: -47, y: -45 }, - Coord { x: 181, y: -1 }, - Coord { x: -87, y: 91 }, - Coord { x: -275, y: -89 }, - Coord { x: 449, y: -93 }, - Coord { x: 101, y: 271 }, - Coord { x: -999, y: -85 }, - Coord { x: 797, y: -457 }, - Coord { x: 1201, y: 627 }, - Coord { x: -2795, y: 287 }, - Coord { x: 393, y: -1541 }, - Coord { x: 5197, y: 967 }, - Coord { x: -5983, y: 2115 }, - Coord { x: -4411, y: -4049 }, - Coord { x: 16377, y: -181 }, - Coord { x: -7555, y: 8279 }, - Coord { - x: -25199, - y: -7917, - }, - ], - Variant::SkewedTameTwindragon => [ - Coord { x: 1, y: 1 }, - Coord { x: -1, y: -2 }, - Coord { x: 3, y: 2 }, - Coord { x: -1, y: 2 }, - Coord { x: -5, y: -6 }, - Coord { x: 7, y: 2 }, - Coord { x: 3, y: 10 }, - Coord { x: -17, y: -14 }, - Coord { x: 11, y: -6 }, - Coord { x: 23, y: 34 }, - Coord { x: -45, y: -22 }, - Coord { x: -1, y: -46 }, - Coord { x: 91, y: 90 }, - Coord { x: -89, y: 2 }, - Coord { x: -93, y: -182 }, - Coord { x: 271, y: 178 }, - Coord { x: -85, y: 186 }, - Coord { x: -457, y: -542 }, - Coord { x: 627, y: 170 }, - Coord { x: 287, y: 914 }, - Coord { x: -1541, y: -1254 }, - Coord { x: 967, y: -574 }, - Coord { x: 2115, y: 3082 }, - Coord { x: -4049, y: -1934 }, - Coord { x: -181, y: -4230 }, - Coord { x: 8279, y: 8098 }, - Coord { x: -7917, y: 362 }, - Coord { - x: -8641, - y: -16558, - }, - Coord { x: 24475, y: 15834 }, - Coord { x: -1, y: 0 }, - ], - } -}