diff --git a/Cargo.lock b/Cargo.lock index 63e55230..5c35ca17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.5.0" @@ -408,6 +414,7 @@ checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" name = "oxipng" version = "10.0.0" dependencies = [ + "arrayvec", "bitvec", "clap", "crossbeam-channel", diff --git a/Cargo.toml b/Cargo.toml index acdfcbfc..e998241c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ libdeflater = "1.25.0" log = "0.4.28" bitvec = "1.0.1" rustc-hash = "2.1.1" +arrayvec = "0.7.6" [dependencies.env_logger] optional = true diff --git a/src/apng.rs b/src/apng.rs index d6505eeb..ab6b691e 100644 --- a/src/apng.rs +++ b/src/apng.rs @@ -1,4 +1,4 @@ -use std::io::Write; +use arrayvec::ArrayVec; use crate::{ PngResult, @@ -50,17 +50,33 @@ impl Frame { /// Construct the data for a fcTL chunk using the given sequence number #[must_use] - pub fn fctl_data(&self, sequence_number: u32) -> Vec { - let mut byte_data = Vec::with_capacity(26); - byte_data.write_all(&sequence_number.to_be_bytes()).unwrap(); - byte_data.write_all(&self.width.to_be_bytes()).unwrap(); - byte_data.write_all(&self.height.to_be_bytes()).unwrap(); - byte_data.write_all(&self.x_offset.to_be_bytes()).unwrap(); - byte_data.write_all(&self.y_offset.to_be_bytes()).unwrap(); - byte_data.write_all(&self.delay_num.to_be_bytes()).unwrap(); - byte_data.write_all(&self.delay_den.to_be_bytes()).unwrap(); - byte_data.push(self.dispose_op); - byte_data.push(self.blend_op); + pub fn fctl_data(&self, sequence_number: u32) -> ArrayVec { + let mut byte_data = const { ArrayVec::<_, 26>::new_const() }; + byte_data + .try_extend_from_slice(&sequence_number.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&self.width.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&self.height.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&self.x_offset.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&self.y_offset.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&self.delay_num.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&self.delay_den.to_be_bytes()) + .unwrap(); + byte_data + .try_extend_from_slice(&[self.dispose_op, self.blend_op]) + .unwrap(); + byte_data } diff --git a/src/png/mod.rs b/src/png/mod.rs index f2001eac..79387010 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -1,5 +1,6 @@ -use std::{fs, io::Write, path::Path, sync::Arc}; +use std::{fs, path::Path, sync::Arc}; +use arrayvec::ArrayVec; use bitvec::bitarr; use libdeflater::{CompressionLvl, Compressor}; use log::warn; @@ -164,18 +165,22 @@ impl PngData { // PNG header let mut output = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; // IHDR - let mut ihdr_data = Vec::with_capacity(13); - ihdr_data.write_all(&self.raw.ihdr.width.to_be_bytes()).ok(); + let mut ihdr_data = const { ArrayVec::<_, 13>::new_const() }; ihdr_data - .write_all(&self.raw.ihdr.height.to_be_bytes()) - .ok(); - ihdr_data.write_all(&[self.raw.ihdr.bit_depth as u8]).ok(); + .try_extend_from_slice(&self.raw.ihdr.width.to_be_bytes()) + .unwrap(); ihdr_data - .write_all(&[self.raw.ihdr.color_type.png_header_code()]) - .ok(); - ihdr_data.write_all(&[0]).ok(); // Compression -- deflate - ihdr_data.write_all(&[0]).ok(); // Filter method -- 5-way adaptive filtering - ihdr_data.write_all(&[self.raw.ihdr.interlaced as u8]).ok(); + .try_extend_from_slice(&self.raw.ihdr.height.to_be_bytes()) + .unwrap(); + ihdr_data + .try_extend_from_slice(&[ + self.raw.ihdr.bit_depth as u8, + self.raw.ihdr.color_type.png_header_code(), + 0, // Compression -- deflate + 0, // Filter method -- 5-way adaptive filtering + self.raw.ihdr.interlaced as u8, + ]) + .unwrap(); write_png_block(b"IHDR", &ihdr_data, &mut output); // Ancillary chunks - split into those that come before IDAT and those that come after let mut aux_split = self.aux_chunks.split(|c| &c.name == b"IDAT");