Skip to content

Commit 12688dc

Browse files
Test encoder by dogfooding decoded image
1 parent 643950b commit 12688dc

File tree

5 files changed

+71
-12
lines changed

5 files changed

+71
-12
lines changed

src/png/chunk.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::png::grammar::ImageHeader;
2+
use crate::png::scanline_writer::ScanlineWriter;
23
use anyhow::Result;
34
use flate2::write::ZlibEncoder;
45
use flate2::Compression;
@@ -35,11 +36,11 @@ pub trait PngChunk {
3536
}
3637

3738
#[derive(Debug)]
38-
pub struct IHDRChunk {
39-
pub image_header: ImageHeader,
39+
pub struct IHDRChunk<'a> {
40+
pub image_header: &'a ImageHeader,
4041
}
4142

42-
impl PngChunk for IHDRChunk {
43+
impl PngChunk for IHDRChunk<'_> {
4344
const NAME: [u8; 4] = *b"IHDR";
4445

4546
fn data(&self) -> Result<Vec<u8>> {
@@ -58,10 +59,10 @@ impl PngChunk for IHDRChunk {
5859
buffer.extend_from_slice(&width.to_be_bytes());
5960
buffer.extend_from_slice(&height.to_be_bytes());
6061
buffer.extend_from_slice(&bit_depth.to_be_bytes());
61-
buffer.extend_from_slice(&(color_type as u8).to_be_bytes());
62+
buffer.extend_from_slice(&(*color_type as u8).to_be_bytes());
6263
buffer.extend_from_slice(&compression_method.to_be_bytes());
6364
buffer.extend_from_slice(&filter_method.to_be_bytes());
64-
buffer.extend_from_slice(&(interlace_method as u8).to_be_bytes());
65+
buffer.extend_from_slice(&(*interlace_method as u8).to_be_bytes());
6566

6667
Ok(buffer)
6768
}
@@ -75,18 +76,23 @@ impl PngChunk for PLTEChunk {
7576
}
7677

7778
#[derive(Debug)]
78-
pub struct IDATChunk {
79-
pub data: Vec<u8>,
79+
pub struct IDATChunk<'a> {
80+
pub image_header: &'a ImageHeader,
81+
pub data: &'a [u8],
8082
}
8183

82-
impl PngChunk for IDATChunk {
84+
impl PngChunk for IDATChunk<'_> {
8385
const NAME: [u8; 4] = *b"IDAT";
8486

8587
fn data(&self) -> Result<Vec<u8>> {
88+
let scanline_writer = ScanlineWriter::new(self.image_header);
89+
let mut scanned_pixels = Vec::new();
90+
scanline_writer.write(&mut scanned_pixels, self.data)?;
91+
8692
let compressed_data = Vec::new();
8793

8894
let mut encoder = ZlibEncoder::new(compressed_data, Compression::fast());
89-
encoder.write_all(&self.data)?;
95+
encoder.write_all(&scanned_pixels)?;
9096

9197
Ok(encoder.finish()?)
9298
}

src/png/encoder.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ impl<W: Write> PngEncoder<W> {
1212
Self { writer }
1313
}
1414

15-
pub fn encode(&mut self, png: Png) -> Result<()> {
15+
pub fn encode(&mut self, png: &Png) -> Result<()> {
1616
self.writer.write_all(b"\x89PNG\r\n\x1A\n")?;
1717

1818
let Png {
@@ -27,7 +27,10 @@ impl<W: Write> PngEncoder<W> {
2727
// let palette_chunk = PLTEChunk;
2828
// palette_chunk.write(&mut self.writer)?;
2929

30-
let image_data_chunk = IDATChunk { data: pixel_buffer };
30+
let image_data_chunk = IDATChunk {
31+
image_header,
32+
data: pixel_buffer,
33+
};
3134
image_data_chunk.write(&mut self.writer)?;
3235

3336
let image_end = IENDChunk;
@@ -51,7 +54,24 @@ mod tests {
5154
let file = File::create("./tests/obama_encoded.png")?;
5255
let mut encoder = PngEncoder::new(file);
5356

54-
encoder.encode(png)?;
57+
encoder.encode(&png)?;
58+
59+
Ok(())
60+
}
61+
62+
#[test]
63+
fn test_encode_round_trip() -> Result<()> {
64+
let data = std::fs::read("./tests/obama.png")?;
65+
let png = PngDecoder::new(&data).decode()?;
66+
67+
let file = File::create("./tests/obama_encoded.png")?;
68+
let mut encoder = PngEncoder::new(file);
69+
encoder.encode(&png)?;
70+
71+
let data = std::fs::read("./tests/obama_encoded.png")?;
72+
let from_encoded_png = PngDecoder::new(&data).decode()?;
73+
74+
assert_eq!(png, from_encoded_png);
5575

5676
Ok(())
5777
}

src/png/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ mod decoder;
99
mod encoder;
1010
mod interlace;
1111
mod scanline_reader;
12+
mod scanline_writer;

src/png/scanline_writer.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use crate::png::grammar::{Filter, ImageHeader};
2+
use anyhow::Result;
3+
use std::io::Write;
4+
5+
#[derive(Debug)]
6+
pub struct ScanlineWriter<'a> {
7+
image_header: &'a ImageHeader,
8+
}
9+
10+
impl<'a> ScanlineWriter<'a> {
11+
pub const fn new(image_header: &'a ImageHeader) -> Self {
12+
Self { image_header }
13+
}
14+
15+
pub fn write<W: Write>(&self, writer: &mut W, pixel_buffer: &'a [u8]) -> Result<()> {
16+
assert_eq!(
17+
self.image_header.width as usize
18+
* self.image_header.height as usize
19+
* self.image_header.num_bytes_per_pixel(),
20+
pixel_buffer.len()
21+
);
22+
23+
for chunk in pixel_buffer.chunks_exact(
24+
self.image_header.width as usize * self.image_header.num_bytes_per_pixel(),
25+
) {
26+
writer.write_all(&[Filter::None as u8])?;
27+
writer.write_all(chunk)?;
28+
}
29+
30+
Ok(())
31+
}
32+
}

tests/obama_encoded.png

1.56 KB
Loading

0 commit comments

Comments
 (0)