summaryrefslogtreecommitdiff
path: root/src/png.rs
diff options
context:
space:
mode:
authorDylan <boss@tehbox.org>2026-09-14 23:43:03 +1200
committerDylan <boss@tehbox.org>2026-09-14 23:43:03 +1200
commit048ebdcee5d48592b6d1b669e9db0a9ba030d859 (patch)
treebd19603b5f05ee5f3e1509d8b19c69a9fe73049a /src/png.rs
parent7c640bfeaf2a0fbc8c3550b4c19790a800a7f6a2 (diff)
downloadtehimage-rs-048ebdcee5d48592b6d1b669e9db0a9ba030d859.tar.gz
tehimage-rs-048ebdcee5d48592b6d1b669e9db0a9ba030d859.zip
feat: PNG decoding works somewhat
Uses zlib-rs
Diffstat (limited to 'src/png.rs')
-rw-r--r--src/png.rs112
1 files changed, 105 insertions, 7 deletions
diff --git a/src/png.rs b/src/png.rs
index ef1aae0..780bd9c 100644
--- a/src/png.rs
+++ b/src/png.rs
@@ -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)-> () {