mirror of
https://github.com/Dangoware/sqp.git
synced 2025-04-19 07:12:55 -05:00
Improved DCT functions
This commit is contained in:
parent
c97eae75df
commit
41158066ec
3 changed files with 55 additions and 40 deletions
|
@ -133,13 +133,40 @@ pub fn dequantize(input: &[i16], quant_matrix: [u16; 64]) -> Vec<f32> {
|
||||||
input.iter().zip(quant_matrix).map(|(v, q)| (*v as i16 * q as i16) as f32).collect()
|
input.iter().zip(quant_matrix).map(|(v, q)| (*v as i16 * q as i16) as f32).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dct_compress(input: &[u8], width: u32, height: u32, quality: u32) -> (Vec<Vec<i16>>, usize, usize) {
|
||||||
|
let new_width = width as usize + (8 - width % 8) as usize;
|
||||||
|
let new_height = height as usize + (8 - height % 8) as usize;
|
||||||
|
let mut img_2d: Vec<Vec<u8>> = input.windows(width as usize).step_by(width as usize).map(|r| r.to_vec()).collect();
|
||||||
|
img_2d.iter_mut().for_each(|r| r.resize(new_width, 0));
|
||||||
|
img_2d.resize(new_height, vec![0u8; new_width]);
|
||||||
|
|
||||||
|
let mut dct_image = Vec::new();
|
||||||
|
for h in 0..new_height / 8 {
|
||||||
|
for w in 0..new_width / 8 {
|
||||||
|
let mut chunk = Vec::new();
|
||||||
|
for i in 0..8 {
|
||||||
|
let row = &img_2d[(h * 8) + i][w * 8..(w * 8) + 8];
|
||||||
|
chunk.extend_from_slice(&row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the DCT on the image section
|
||||||
|
let dct: Vec<f32> = dct(&chunk, 8, 8);
|
||||||
|
let quantzied_dct = quantize(&dct, quantization_matrix(quality));
|
||||||
|
|
||||||
|
dct_image.push(quantzied_dct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(dct_image, new_width, new_height)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quantization_matrix_q80() {
|
fn quantization_matrix_q80() {
|
||||||
let result = gen_quantization_matrix(80);
|
let result = quantization_matrix(80);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
|
@ -158,20 +185,20 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quantization_matrix_q100() {
|
fn quantization_matrix_q100() {
|
||||||
let result = gen_quantization_matrix(100);
|
let result = quantization_matrix(100);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
[
|
[
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0
|
1, 1, 1, 1, 1, 1, 1, 1
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,3 +31,11 @@ impl Header {
|
||||||
buf.into_inner().try_into().unwrap()
|
buf.into_inner().try_into().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ColorFormat {
|
||||||
|
/// RGBA, 8 bits per channel
|
||||||
|
Rgba32,
|
||||||
|
|
||||||
|
/// RGB, 8 bits per channel
|
||||||
|
Rgb24,
|
||||||
|
}
|
||||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -10,45 +10,25 @@ pub mod picture;
|
||||||
use picture::DangoPicture;
|
use picture::DangoPicture;
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{BufReader, BufWriter},
|
io::{BufReader, BufWriter, Write},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
use compression::dct::{dct, dequantize, idct, quantization_matrix, quantize};
|
use compression::{dct::{dct, dct_compress, dequantize, idct, quantization_matrix, quantize}, lossless};
|
||||||
|
|
||||||
use image::{ColorType, DynamicImage, GenericImage, GrayImage, Luma, Rgba};
|
use image::{ColorType, DynamicImage, GenericImage, GrayImage, Luma, Rgba};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input = image::open("scaramouche.png").unwrap().to_luma8();
|
let input = image::open("transparent.png").unwrap().to_luma8();
|
||||||
input.save("original.png").unwrap();
|
input.save("original.png").unwrap();
|
||||||
|
|
||||||
let new_width = input.width() as usize + (8 - input.width() % 8) as usize;
|
let (dct_image, new_width, new_height) = dct_compress(input.as_raw(), input.width(), input.height(), 100);
|
||||||
let new_height = input.height() as usize + (8 - input.height() % 8) as usize;
|
let compressed_dct = lossless::compress(&dct_image.iter().flatten().flat_map(|b| b.to_le_bytes()).collect::<Vec<u8>>());
|
||||||
let mut img_2d: Vec<Vec<u8>> = input.windows(input.width() as usize).step_by(input.width() as usize).map(|r| r.to_vec()).collect();
|
let mut dct_save = File::create("dct_raw.dct").unwrap();
|
||||||
img_2d.iter_mut().for_each(|r| r.resize(new_width, 0));
|
dct_save.write_all(&compressed_dct.0).unwrap();
|
||||||
img_2d.resize(new_height, vec![0u8; new_width]);
|
|
||||||
|
|
||||||
let timer = Instant::now();
|
|
||||||
let mut dct_image = Vec::new();
|
|
||||||
for h in 0..new_height / 8 {
|
|
||||||
for w in 0..new_width / 8 {
|
|
||||||
let mut chunk = Vec::new();
|
|
||||||
for i in 0..8 {
|
|
||||||
let row = &img_2d[(h * 8) + i][w * 8..(w * 8) + 8];
|
|
||||||
chunk.extend_from_slice(&row);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the DCT on the image section
|
|
||||||
let dct: Vec<f32> = dct(&chunk, 8, 8);
|
|
||||||
let quantzied_dct = quantize(&dct, quantization_matrix(80));
|
|
||||||
|
|
||||||
dct_image.push(quantzied_dct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("Encoding took {}ms", timer.elapsed().as_millis());
|
|
||||||
|
|
||||||
let mut decoded_image = GrayImage::new(new_width as u32, new_height as u32);
|
let mut decoded_image = GrayImage::new(new_width as u32, new_height as u32);
|
||||||
for (i, chunk) in dct_image.iter().enumerate() {
|
for (i, chunk) in dct_image.iter().enumerate() {
|
||||||
let dequantized_dct = dequantize(chunk, quantization_matrix(80));
|
let dequantized_dct = dequantize(chunk, quantization_matrix(100));
|
||||||
let original = idct(&dequantized_dct, 8, 8);
|
let original = idct(&dequantized_dct, 8, 8);
|
||||||
|
|
||||||
// Write rows of blocks
|
// Write rows of blocks
|
||||||
|
|
Loading…
Reference in a new issue