Remove FIXME sections from code
One section can't be improved from what I can gather, because we have to iterate the number of bits per pixel in advance. The output section has been refactored to pull the block writing code into a separate function. Fixes #19
This commit is contained in:
parent
aec8e412a3
commit
85ea2c21e5
1 changed files with 20 additions and 63 deletions
83
src/png.rs
83
src/png.rs
|
|
@ -290,12 +290,10 @@ impl PngData {
|
||||||
}
|
}
|
||||||
/// Format the `PngData` struct into a valid PNG bytestream
|
/// Format the `PngData` struct into a valid PNG bytestream
|
||||||
pub fn output(&self) -> Vec<u8> {
|
pub fn output(&self) -> Vec<u8> {
|
||||||
// FIXME: This code can all be refactored
|
|
||||||
// PNG header
|
// PNG header
|
||||||
let mut output = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
let mut output = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
||||||
// IHDR
|
// IHDR
|
||||||
let mut ihdr_data = Vec::with_capacity(17);
|
let mut ihdr_data = Vec::with_capacity(13);
|
||||||
ihdr_data.extend_from_slice(b"IHDR");
|
|
||||||
ihdr_data.write_u32::<BigEndian>(self.ihdr_data.width).ok();
|
ihdr_data.write_u32::<BigEndian>(self.ihdr_data.width).ok();
|
||||||
ihdr_data.write_u32::<BigEndian>(self.ihdr_data.height).ok();
|
ihdr_data.write_u32::<BigEndian>(self.ihdr_data.height).ok();
|
||||||
ihdr_data.write_u8(self.ihdr_data.bit_depth.as_u8()).ok();
|
ihdr_data.write_u8(self.ihdr_data.bit_depth.as_u8()).ok();
|
||||||
|
|
@ -303,85 +301,34 @@ impl PngData {
|
||||||
ihdr_data.write_u8(0).ok(); // Compression -- deflate
|
ihdr_data.write_u8(0).ok(); // Compression -- deflate
|
||||||
ihdr_data.write_u8(0).ok(); // Filter method -- 5-way adaptive filtering
|
ihdr_data.write_u8(0).ok(); // Filter method -- 5-way adaptive filtering
|
||||||
ihdr_data.write_u8(self.ihdr_data.interlaced).ok();
|
ihdr_data.write_u8(self.ihdr_data.interlaced).ok();
|
||||||
output.reserve(ihdr_data.len() + 8);
|
write_png_block(b"IHDR", &ihdr_data, &mut output);
|
||||||
output.write_u32::<BigEndian>(ihdr_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&ihdr_data);
|
|
||||||
output.append(&mut ihdr_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
// Ancillary headers
|
// Ancillary headers
|
||||||
for (key, header) in self.aux_headers.iter().filter(|&(ref key, _)| {
|
for (key, header) in self.aux_headers.iter().filter(|&(ref key, _)| {
|
||||||
!(**key == "bKGD" || **key == "hIST" || **key == "tRNS")
|
!(**key == "bKGD" || **key == "hIST" || **key == "tRNS")
|
||||||
}) {
|
}) {
|
||||||
let mut header_data = Vec::with_capacity(header.len() + 4);
|
write_png_block(&key.as_bytes(), &header, &mut output);
|
||||||
header_data.extend(key.as_bytes());
|
|
||||||
header_data.extend_from_slice(header);
|
|
||||||
output.reserve(header_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(header_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&header_data);
|
|
||||||
output.append(&mut header_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
}
|
}
|
||||||
// Palette
|
// Palette
|
||||||
if let Some(palette) = self.palette.clone() {
|
if let Some(palette) = self.palette.clone() {
|
||||||
let mut palette_data = Vec::with_capacity(palette.len() + 4);
|
write_png_block(b"PLTE", &palette, &mut output);
|
||||||
palette_data.extend_from_slice(b"PLTE");
|
|
||||||
palette_data.extend(palette);
|
|
||||||
output.reserve(palette_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(palette_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&palette_data);
|
|
||||||
output.append(&mut palette_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
if let Some(transparency_palette) = self.transparency_palette.clone() {
|
if let Some(transparency_palette) = self.transparency_palette.clone() {
|
||||||
// Transparency pixel
|
// Transparency pixel
|
||||||
let mut palette_data = Vec::with_capacity(transparency_palette.len() + 4);
|
write_png_block(b"tRNS", &transparency_palette, &mut output);
|
||||||
palette_data.extend_from_slice(b"tRNS");
|
|
||||||
palette_data.extend(transparency_palette);
|
|
||||||
output.reserve(palette_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(palette_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&palette_data);
|
|
||||||
output.append(&mut palette_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
}
|
}
|
||||||
} else if let Some(transparency_pixel) = self.transparency_pixel.clone() {
|
} else if let Some(transparency_pixel) = self.transparency_pixel.clone() {
|
||||||
// Transparency pixel
|
// Transparency pixel
|
||||||
let mut pixel_data = Vec::with_capacity(transparency_pixel.len() + 4);
|
write_png_block(b"tRNS", &transparency_pixel, &mut output);
|
||||||
pixel_data.extend_from_slice(b"tRNS");
|
|
||||||
pixel_data.extend(transparency_pixel);
|
|
||||||
output.reserve(pixel_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(pixel_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&pixel_data);
|
|
||||||
output.append(&mut pixel_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
}
|
}
|
||||||
// Special ancillary headers that need to come after PLTE but before IDAT
|
// Special ancillary headers that need to come after PLTE but before IDAT
|
||||||
for (key, header) in self.aux_headers.iter().filter(|&(ref key, _)| {
|
for (key, header) in self.aux_headers.iter().filter(|&(ref key, _)| {
|
||||||
**key == "bKGD" || **key == "hIST" || **key == "tRNS"
|
**key == "bKGD" || **key == "hIST" || **key == "tRNS"
|
||||||
}) {
|
}) {
|
||||||
let mut header_data = Vec::with_capacity(header.len() + 4);
|
write_png_block(&key.as_bytes(), &header, &mut output);
|
||||||
header_data.extend(key.as_bytes());
|
|
||||||
header_data.extend_from_slice(header);
|
|
||||||
output.reserve(header_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(header_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&header_data);
|
|
||||||
output.append(&mut header_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
}
|
}
|
||||||
// IDAT data
|
// IDAT data
|
||||||
let mut idat_data = Vec::with_capacity(self.idat_data.len() + 4);
|
write_png_block(b"IDAT", &self.idat_data, &mut output);
|
||||||
idat_data.extend_from_slice(b"IDAT");
|
|
||||||
idat_data.extend(self.idat_data.clone());
|
|
||||||
output.reserve(idat_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(idat_data.len() as u32 - 4).ok();
|
|
||||||
let crc = crc32::checksum_ieee(&idat_data);
|
|
||||||
output.append(&mut idat_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
// Stream end
|
// Stream end
|
||||||
let iend_data = b"IEND";
|
write_png_block(b"IEND", &[], &mut output);
|
||||||
output.reserve(iend_data.len() + 8);
|
|
||||||
output.write_u32::<BigEndian>(0).ok();
|
|
||||||
let crc = crc32::checksum_ieee(iend_data);
|
|
||||||
output.extend_from_slice(iend_data);
|
|
||||||
output.write_u32::<BigEndian>(crc).ok();
|
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
@ -771,7 +718,6 @@ fn reduce_bit_depth_8_or_less(png: &PngData) -> Option<(Vec<u8>, u8)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines() {
|
||||||
// FIXME: I hate having to iterate twice...
|
|
||||||
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
||||||
let bit_vec = BitVec::from_bytes(&line.data);
|
let bit_vec = BitVec::from_bytes(&line.data);
|
||||||
for (i, bit) in bit_vec.iter().enumerate() {
|
for (i, bit) in bit_vec.iter().enumerate() {
|
||||||
|
|
@ -1190,3 +1136,14 @@ fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, String> {
|
||||||
interlaced: byte_data[12],
|
interlaced: byte_data[12],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_png_block(key: &[u8], header: &[u8], output: &mut Vec<u8>) {
|
||||||
|
let mut header_data = Vec::with_capacity(header.len() + 4);
|
||||||
|
header_data.extend_from_slice(key);
|
||||||
|
header_data.extend_from_slice(header);
|
||||||
|
output.reserve(header_data.len() + 8);
|
||||||
|
output.write_u32::<BigEndian>(header_data.len() as u32 - 4).ok();
|
||||||
|
let crc = crc32::checksum_ieee(&header_data);
|
||||||
|
output.append(&mut header_data);
|
||||||
|
output.write_u32::<BigEndian>(crc).ok();
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue