diff options
Diffstat (limited to 'src/png.rs')
| -rw-r--r-- | src/png.rs | 112 |
1 files changed, 105 insertions, 7 deletions
@@ -1,8 +1,9 @@ -use std::collections::{self, HashMap}; +use std::{any::TypeId, collections::HashMap}; use byte_encode_derive::ByteEncode; +use zlib_rs::{InflateConfig, decompress_slice}; -use crate::{byte_encode::ByteEncode, crc::update_crc, image::{ColorType, Image, ImageBase}, reader::FileReader, zlib::{zlib_decode, ByteBuffer}}; +use crate::{byte_encode::ByteEncode, crc::update_crc, image::{RGB, ColorType, Image, ImageBase, PixelArr}, reader::FileReader, zlib::{BitBuffer, zlib_decode}}; #[derive(Default)] pub struct PNGImage @@ -13,6 +14,55 @@ pub struct PNGImage tEXt: Option<tEXt>, } +fn paeth_filter(a: u8, b: u8, c: u8) -> u8 { + let p = (a as i32 + b as i32 - c as i32) as u8; + let pa = p.abs_diff(a); + let pb = p.abs_diff(b); + let pc = p.abs_diff(c); + if pa <= pb && pa <= pc + { + a + } + else if pb <= pc + { + b + } + else + { + c + } +} +enum FilterMethod +{ + None, + Sub, + Up, + Average, + Paeth +} +impl FilterMethod +{ + fn from_byte(x: u8) -> Self { + match x { + 0 => Self::None, + 1 => Self::Sub, + 2 => Self::Up, + 3 => Self::Average, + 4 => Self::Paeth, + _ => panic!("Filter {x} is invalid!\nOnly 5 filters exist") + } + } + fn apply(&self, a: u8, b: u8, c: u8, x: u8) -> u8 { + match self { + FilterMethod::None => x, + FilterMethod::Sub => x.wrapping_add(a), + FilterMethod::Up => x.wrapping_add(b), + FilterMethod::Average => x.wrapping_add((a + b)/2), + FilterMethod::Paeth => x.wrapping_add(paeth_filter(a, b, c)), + } + } +} + trait Mergable: Sized { fn merge(a: Self, b: Self) -> Self; @@ -60,7 +110,7 @@ struct IHDR impl PNGChunk for IHDR { const CHUNK_TYPE: [char; 4] = ['I', 'H', 'D', 'R']; - fn read(reader: &mut FileReader, length: usize) -> Self { + fn read(reader: &mut FileReader, _: usize) -> Self { reader.read() } } @@ -76,7 +126,7 @@ struct IEND impl PNGChunk for IEND { const CHUNK_TYPE: [char; 4] = ['I', 'E', 'N', 'D']; - fn read(reader: &mut FileReader, length: usize) -> Self { + fn read(_: &mut FileReader, _: usize) -> Self { Self {} } } @@ -165,9 +215,17 @@ impl Mergable for IDAT } } -impl<T: ColorType> Image<T> for PNGImage +trait RGBu8: ColorType {} +impl RGBu8 for RGB<u8> {} + +impl<T: RGBu8> Image<T> for PNGImage + where T: 'static { fn read_image(reader: &mut FileReader) -> Result<ImageBase<T>, String> { + assert!( + TypeId::of::<T>() == TypeId::of::<RGB<u8>>(), + "PNG only working for rgb u8's currently sorry" + ); let magic: [u8; 8] = reader.read_array(); if magic != [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A] { @@ -240,9 +298,49 @@ impl<T: ColorType> Image<T> for PNGImage let compression_method: u8 = IDAT.data[0]; let additional_flags: u8 = IDAT.data[1]; - let decoded = zlib_decode(ByteBuffer::new(&IDAT.data[2..])); + let mut decoded = vec![0u8; 1920*(1080*3 + 1)]; // zlib_decode(BitBuffer::new(&IDAT.data[2..])); + let (decompressed, rc) = decompress_slice(&mut decoded, &IDAT.data, InflateConfig::default()); + println!("{rc:?}"); + + let mut pixels = PixelArr::<T>::new(width, height); + let mut rows: Vec<Vec<u8>> = Vec::new(); + + let mut i = 0; + for y in 0..(height as usize) + { + // println!("i: {i}"); + let filter = FilterMethod::from_byte(decoded[i]); + i += 1; + let mut row: Vec<u8> = Vec::with_capacity(width as usize * 3); + for x in 0..(width as usize * 3) + { + let a: u8 = if x < 3 { 0 } else { row[x - 3] }; + let b: u8 = if y < 1 { 0 } else { rows[y - 1][x] }; + let c: u8 = if y < 1 || x < 3 { 0 } else { rows[y - 1][x - 3] }; + let x = decoded[i]; + i += 1; + row.push(filter.apply(a, b, c, x)); + } + rows.push(row); + } + + for y in 0..(height as usize) + { + for x in 0..(width as usize) + { + let row = &rows[y]; + let r = row[x * 3]; + let g = row[x * 3 + 1]; + let b = row[x * 3 + 2]; + pixels[(x, y)] = (RGB { r, g, b}).convert(); + } + } - todo!("PNG not finished") + Ok(ImageBase + { + bpp, + pixels + }) } fn write_image(image: &crate::image::ImageBase<T>, writer: &mut crate::writer::FileWriter)-> () { |
