mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 07:12:55 -05:00
Added DynamicCz, added better test program, fixed error messages
This commit is contained in:
parent
b28a8d0b88
commit
8945b80065
12 changed files with 230 additions and 114 deletions
|
@ -8,9 +8,6 @@ A encoder/decoder for CZ# image files used in
|
|||
"""
|
||||
|
||||
[dependencies]
|
||||
image = "0.25"
|
||||
byteorder = "1.5.0"
|
||||
thiserror = "1.0.59"
|
||||
bitstream-io = "2.2.0"
|
||||
png = "0.17.13"
|
||||
rayon = "1.10.0"
|
||||
|
|
|
@ -6,19 +6,24 @@ use std::{
|
|||
};
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use image::Rgba;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CzError {
|
||||
#[error("Version in header does not match expected version")]
|
||||
#[error("Expected CZ{}, got CZ{}", 0, 1)]
|
||||
VersionMismatch(u8, u8),
|
||||
|
||||
#[error("Format of supplied file is not a CZ#")]
|
||||
InvalidFormat,
|
||||
#[error("File data is incorrect, it might be corrupt")]
|
||||
Corrupt,
|
||||
|
||||
#[error("File is not a CZ image")]
|
||||
NotCzFile,
|
||||
|
||||
#[error("Failed to read/write input/output")]
|
||||
IoError(#[from] io::Error),
|
||||
|
||||
#[error("Problem while decoding file")]
|
||||
DecodeError,
|
||||
}
|
||||
|
||||
pub trait CzHeader {
|
||||
|
@ -26,6 +31,9 @@ pub trait CzHeader {
|
|||
where
|
||||
Self: Sized;
|
||||
|
||||
/// The [CommonHeader] header from the image
|
||||
fn common(&self) -> &CommonHeader;
|
||||
|
||||
/// Turn the header into bytes equivalent to the original header from the file
|
||||
fn to_bytes(&self) -> Result<Vec<u8>, io::Error>;
|
||||
|
||||
|
@ -79,7 +87,7 @@ impl CzHeader for CommonHeader {
|
|||
bytes.read_exact(&mut magic)?;
|
||||
|
||||
if magic[0..2] != [b'C', b'Z'] {
|
||||
return Err(CzError::InvalidFormat);
|
||||
return Err(CzError::NotCzFile);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
@ -92,6 +100,10 @@ impl CzHeader for CommonHeader {
|
|||
})
|
||||
}
|
||||
|
||||
fn common(&self) -> &CommonHeader {
|
||||
&self
|
||||
}
|
||||
|
||||
fn version(&self) -> u8 {
|
||||
self.version
|
||||
}
|
||||
|
@ -139,9 +151,6 @@ pub trait CzImage {
|
|||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Save the image as a PNG
|
||||
fn save_as_png(&self, name: &str) -> Result<(), image::error::ImageError>;
|
||||
|
||||
/// Save the image as its corresponding CZ# type
|
||||
fn save_as_cz<T: Into<PathBuf>>(&self, path: T) -> Result<(), CzError>;
|
||||
|
||||
|
@ -149,7 +158,9 @@ pub trait CzImage {
|
|||
fn header(&self) -> &Self::Header;
|
||||
|
||||
/// Set the header with its metadata
|
||||
fn set_header(&mut self, header: Self::Header);
|
||||
fn set_header(&mut self, header: &Self::Header);
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8>;
|
||||
|
||||
/// Get the raw underlying bitmap for an image
|
||||
fn into_bitmap(self) -> Vec<u8>;
|
||||
|
@ -161,23 +172,23 @@ pub trait CzImage {
|
|||
pub fn parse_colormap<T: Seek + ReadBytesExt + Read>(
|
||||
input: &mut T,
|
||||
num_colors: usize,
|
||||
) -> Result<Vec<Rgba<u8>>, CzError> {
|
||||
) -> Result<Vec<[u8; 4]>, CzError> {
|
||||
let mut colormap = Vec::with_capacity(num_colors);
|
||||
let mut rgba_buf = [0u8; 4];
|
||||
|
||||
for _ in 0..num_colors {
|
||||
input.read_exact(&mut rgba_buf)?;
|
||||
colormap.push(Rgba(rgba_buf));
|
||||
colormap.push(rgba_buf);
|
||||
}
|
||||
|
||||
Ok(colormap)
|
||||
}
|
||||
|
||||
pub fn apply_palette(input: &mut Vec<u8>, palette: &[Rgba<u8>]) -> Vec<u8> {
|
||||
pub fn apply_palette(input: &mut Vec<u8>, palette: &[[u8; 4]]) -> Vec<u8> {
|
||||
let mut output_map = Vec::new();
|
||||
|
||||
for byte in input.iter() {
|
||||
let color = palette[*byte as usize].0;
|
||||
let color = palette[*byte as usize];
|
||||
output_map.extend_from_slice(&color);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use image::{
|
||||
buffer, ColorType, DynamicImage, GenericImage, GenericImageView, RgbImage, Rgba, RgbaImage,
|
||||
};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
io::{Read, Seek, Write},
|
||||
|
@ -218,7 +215,7 @@ pub fn line_diff<T: CzHeader>(header: &T, data: &[u8]) -> Vec<u8> {
|
|||
|
||||
if y % block_height as u32 != 0 {
|
||||
for x in 0..line_byte_count {
|
||||
curr_line[x] += prev_line[x]
|
||||
curr_line[x] = u8::wrapping_add(curr_line[x], prev_line[x])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
102
cz/src/dynamic.rs
Normal file
102
cz/src/dynamic.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
use std::io::{Read, Seek};
|
||||
use byteorder::ReadBytesExt;
|
||||
|
||||
use crate::{
|
||||
common::{CommonHeader, CzError, CzHeader},
|
||||
Cz0Image,
|
||||
Cz1Image,
|
||||
Cz2Image,
|
||||
Cz3Image,
|
||||
Cz4Image,
|
||||
CzImage
|
||||
};
|
||||
|
||||
pub enum DynamicCz {
|
||||
CZ0(Cz0Image),
|
||||
CZ1(Cz1Image),
|
||||
CZ2(Cz2Image),
|
||||
CZ3(Cz3Image),
|
||||
CZ4(Cz4Image),
|
||||
}
|
||||
|
||||
impl DynamicCz {
|
||||
pub fn save_as_png(&self, name: &str) -> Result<(), png::EncodingError> {
|
||||
let file = std::fs::File::create(name).unwrap();
|
||||
let ref mut w = std::io::BufWriter::new(file);
|
||||
|
||||
let mut encoder = png::Encoder::new(
|
||||
w,
|
||||
self.header().width() as u32,
|
||||
self.header().height() as u32,
|
||||
);
|
||||
encoder.set_color(png::ColorType::Rgba);
|
||||
encoder.set_depth(png::BitDepth::Eight);
|
||||
let mut writer = encoder.write_header()?;
|
||||
|
||||
writer.write_image_data(&self.bitmap())?; // Save
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CzImage for DynamicCz {
|
||||
type Header = CommonHeader;
|
||||
|
||||
fn decode<T: Seek + ReadBytesExt + Read>(input: &mut T)
|
||||
-> Result<DynamicCz, crate::common::CzError>
|
||||
{
|
||||
let common_header = CommonHeader::new(input)?;
|
||||
input.seek(std::io::SeekFrom::Start(0))?;
|
||||
|
||||
Ok(match common_header.version() {
|
||||
0 => DynamicCz::CZ0(Cz0Image::decode(input)?),
|
||||
1 => DynamicCz::CZ1(Cz1Image::decode(input)?),
|
||||
2 => DynamicCz::CZ2(Cz2Image::decode(input)?),
|
||||
3 => DynamicCz::CZ3(Cz3Image::decode(input)?),
|
||||
4 => DynamicCz::CZ4(Cz4Image::decode(input)?),
|
||||
_ => return Err(CzError::NotCzFile),
|
||||
})
|
||||
}
|
||||
|
||||
fn save_as_cz<T: Into<std::path::PathBuf>>(&self, path: T) -> Result<(), CzError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn header(&self) -> &Self::Header {
|
||||
match self {
|
||||
DynamicCz::CZ0(img) => &img.header().common(),
|
||||
DynamicCz::CZ1(img) => &img.header().common(),
|
||||
DynamicCz::CZ2(img) => &img.header().common(),
|
||||
DynamicCz::CZ3(img) => &img.header().common(),
|
||||
DynamicCz::CZ4(img) => &img.header().common(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_header(&mut self, header: &Self::Header) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8> {
|
||||
match self {
|
||||
DynamicCz::CZ0(img) => img.bitmap(),
|
||||
DynamicCz::CZ1(img) => img.bitmap(),
|
||||
DynamicCz::CZ2(img) => img.bitmap(),
|
||||
DynamicCz::CZ3(img) => img.bitmap(),
|
||||
DynamicCz::CZ4(img) => img.bitmap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_bitmap(self) -> Vec<u8> {
|
||||
match self {
|
||||
DynamicCz::CZ0(img) => img.into_bitmap(),
|
||||
DynamicCz::CZ1(img) => img.into_bitmap(),
|
||||
DynamicCz::CZ2(img) => img.into_bitmap(),
|
||||
DynamicCz::CZ3(img) => img.into_bitmap(),
|
||||
DynamicCz::CZ4(img) => img.into_bitmap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_bitmap(&mut self, bitmap: &[u8], header: &Self::Header) {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -94,6 +94,10 @@ impl CzHeader for Cz0Header {
|
|||
})
|
||||
}
|
||||
|
||||
fn common(&self) -> &CommonHeader {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn version(&self) -> u8 {
|
||||
self.common.version()
|
||||
}
|
||||
|
@ -150,17 +154,13 @@ impl CzImage for Cz0Image {
|
|||
let mut bitmap = vec![];
|
||||
bytes.read_to_end(&mut bitmap)?;
|
||||
|
||||
Ok(Self { header, bitmap })
|
||||
let bpp = (header.depth() >> 3) as usize;
|
||||
|
||||
if bitmap.len() != (header.width() as usize * header.height() as usize) * bpp {
|
||||
return Err(CzError::Corrupt)
|
||||
}
|
||||
|
||||
fn save_as_png(&self, name: &str) -> Result<(), image::error::ImageError> {
|
||||
image::save_buffer(
|
||||
name,
|
||||
&self.bitmap,
|
||||
self.header.width() as u32,
|
||||
self.header.height() as u32,
|
||||
image::ExtendedColorType::Rgba8,
|
||||
)
|
||||
Ok(Self { header, bitmap })
|
||||
}
|
||||
|
||||
fn save_as_cz<T: Into<PathBuf>>(&self, path: T) -> Result<(), CzError> {
|
||||
|
@ -177,8 +177,12 @@ impl CzImage for Cz0Image {
|
|||
&self.header
|
||||
}
|
||||
|
||||
fn set_header(&mut self, header: Self::Header) {
|
||||
self.header = header
|
||||
fn set_header(&mut self, header: &Self::Header) {
|
||||
self.header = *header
|
||||
}
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8> {
|
||||
&self.bitmap
|
||||
}
|
||||
|
||||
fn into_bitmap(self) -> Vec<u8> {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::ReadBytesExt;
|
||||
use image::{ImageFormat, Rgba};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufWriter, Read, Seek, SeekFrom, Write},
|
||||
|
@ -14,7 +13,7 @@ pub struct Cz1Image {
|
|||
header: CommonHeader,
|
||||
raw_bitmap: Option<Vec<u8>>,
|
||||
bitmap: Vec<u8>,
|
||||
palette: Vec<Rgba<u8>>,
|
||||
palette: Vec<[u8; 4]>,
|
||||
}
|
||||
|
||||
impl CzImage for Cz1Image {
|
||||
|
@ -26,7 +25,7 @@ impl CzImage for Cz1Image {
|
|||
bytes.seek(SeekFrom::Start(header.length() as u64))?;
|
||||
|
||||
if header.version() != 1 {
|
||||
return Err(CzError::VersionMismatch(header.version(), 1));
|
||||
return Err(CzError::VersionMismatch(1, header.version()));
|
||||
}
|
||||
|
||||
// The color palette, gotten for 8 and 4 BPP images
|
||||
|
@ -59,23 +58,16 @@ impl CzImage for Cz1Image {
|
|||
Ok(image)
|
||||
}
|
||||
|
||||
fn save_as_png(&self, name: &str) -> Result<(), image::error::ImageError> {
|
||||
image::save_buffer_with_format(
|
||||
name,
|
||||
&self.bitmap,
|
||||
self.header.width() as u32,
|
||||
self.header.height() as u32,
|
||||
image::ExtendedColorType::Rgba8,
|
||||
ImageFormat::Png,
|
||||
)
|
||||
}
|
||||
|
||||
fn header(&self) -> &Self::Header {
|
||||
&self.header
|
||||
}
|
||||
|
||||
fn set_header(&mut self, header: Self::Header) {
|
||||
self.header = header
|
||||
fn set_header(&mut self, header:& Self::Header) {
|
||||
self.header = *header
|
||||
}
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8> {
|
||||
&self.bitmap
|
||||
}
|
||||
|
||||
fn into_bitmap(self) -> Vec<u8> {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use image::{ImageFormat, Rgba};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufWriter, Read, Seek, SeekFrom, Write},
|
||||
|
@ -7,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::common::{apply_palette, parse_colormap, CommonHeader, CzError, CzHeader, CzImage};
|
||||
use crate::compression::{decompress, decompress_2, parse_chunk_info};
|
||||
use crate::compression::{decompress_2, parse_chunk_info};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Cz2Header {
|
||||
|
@ -25,7 +24,7 @@ impl CzHeader for Cz2Header {
|
|||
let common = CommonHeader::new(bytes)?;
|
||||
|
||||
if common.version() != 2 {
|
||||
return Err(CzError::VersionMismatch(common.version(), 2));
|
||||
return Err(CzError::VersionMismatch(2, common.version()));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
@ -36,6 +35,10 @@ impl CzHeader for Cz2Header {
|
|||
})
|
||||
}
|
||||
|
||||
fn common(&self) -> &CommonHeader {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Result<Vec<u8>, std::io::Error> {
|
||||
let mut buf = vec![];
|
||||
|
||||
|
@ -76,7 +79,7 @@ impl CzHeader for Cz2Header {
|
|||
pub struct Cz2Image {
|
||||
header: Cz2Header,
|
||||
bitmap: Vec<u8>,
|
||||
palette: Vec<Rgba<u8>>,
|
||||
palette: Vec<[u8; 4]>,
|
||||
}
|
||||
|
||||
impl CzImage for Cz2Image {
|
||||
|
@ -86,12 +89,6 @@ impl CzImage for Cz2Image {
|
|||
let header = Cz2Header::new(bytes).unwrap();
|
||||
bytes.seek(SeekFrom::Start(header.length() as u64))?;
|
||||
|
||||
if header.version() != 2 {
|
||||
return Err(CzError::VersionMismatch(header.version(), 2));
|
||||
}
|
||||
|
||||
dbg!(header);
|
||||
|
||||
// The color palette, gotten for 8 and 4 BPP images
|
||||
let mut palette = None;
|
||||
if header.depth() == 8 || header.depth() == 4 {
|
||||
|
@ -117,25 +114,16 @@ impl CzImage for Cz2Image {
|
|||
Ok(image)
|
||||
}
|
||||
|
||||
fn save_as_png(&self, name: &str) -> Result<(), image::error::ImageError> {
|
||||
let img = image::RgbaImage::from_raw(
|
||||
self.header.width() as u32,
|
||||
self.header.height() as u32,
|
||||
self.bitmap.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
img.save(name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn header(&self) -> &Self::Header {
|
||||
&self.header
|
||||
}
|
||||
|
||||
fn set_header(&mut self, header: Self::Header) {
|
||||
self.header = header
|
||||
fn set_header(&mut self, header: &Self::Header) {
|
||||
self.header = *header
|
||||
}
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8> {
|
||||
&self.bitmap
|
||||
}
|
||||
|
||||
fn into_bitmap(self) -> Vec<u8> {
|
||||
|
|
|
@ -40,7 +40,7 @@ impl CzHeader for Cz3Header {
|
|||
let common = CommonHeader::new(bytes)?;
|
||||
|
||||
if common.version() != 3 {
|
||||
return Err(CzError::VersionMismatch(common.version(), 3));
|
||||
return Err(CzError::VersionMismatch(3, common.version()));
|
||||
}
|
||||
|
||||
let mut unknown_1 = [0u8; 5];
|
||||
|
@ -73,6 +73,10 @@ impl CzHeader for Cz3Header {
|
|||
})
|
||||
}
|
||||
|
||||
fn common(&self) -> &CommonHeader {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn version(&self) -> u8 {
|
||||
self.common.version()
|
||||
}
|
||||
|
@ -124,22 +128,16 @@ impl CzImage for Cz3Image {
|
|||
Ok(Self { header, bitmap })
|
||||
}
|
||||
|
||||
fn save_as_png(&self, name: &str) -> Result<(), image::error::ImageError> {
|
||||
image::save_buffer(
|
||||
name,
|
||||
&self.bitmap,
|
||||
self.header.width() as u32,
|
||||
self.header.height() as u32,
|
||||
image::ExtendedColorType::Rgba8,
|
||||
)
|
||||
}
|
||||
|
||||
fn header(&self) -> &Self::Header {
|
||||
&self.header
|
||||
}
|
||||
|
||||
fn set_header(&mut self, header: Self::Header) {
|
||||
self.header = header
|
||||
fn set_header(&mut self, header: &Self::Header) {
|
||||
self.header = *header
|
||||
}
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8> {
|
||||
&self.bitmap
|
||||
}
|
||||
|
||||
fn into_bitmap(self) -> Vec<u8> {
|
||||
|
|
|
@ -2,12 +2,10 @@ use std::{
|
|||
io::{self, Read, Seek, SeekFrom},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use image::DynamicImage;
|
||||
use byteorder::ReadBytesExt;
|
||||
|
||||
use crate::common::{CommonHeader, CzError, CzHeader, CzImage};
|
||||
use crate::compression::{decompress, line_diff, line_diff_cz4, parse_chunk_info};
|
||||
use crate::compression::{decompress, line_diff_cz4, parse_chunk_info};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Cz4Header {
|
||||
|
@ -23,12 +21,16 @@ impl CzHeader for Cz4Header {
|
|||
let common = CommonHeader::new(bytes)?;
|
||||
|
||||
if common.version() != 4 {
|
||||
return Err(CzError::VersionMismatch(common.version(), 3));
|
||||
return Err(CzError::VersionMismatch(4, common.version()));
|
||||
}
|
||||
|
||||
Ok(Self { common })
|
||||
}
|
||||
|
||||
fn common(&self) -> &CommonHeader {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn version(&self) -> u8 {
|
||||
self.common.version()
|
||||
}
|
||||
|
@ -81,25 +83,16 @@ impl CzImage for Cz4Image {
|
|||
Ok(Self { header, bitmap })
|
||||
}
|
||||
|
||||
fn save_as_png(&self, name: &str) -> Result<(), image::error::ImageError> {
|
||||
let img = image::RgbaImage::from_raw(
|
||||
self.header.width() as u32,
|
||||
self.header.height() as u32,
|
||||
self.bitmap.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
img.save(name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn header(&self) -> &Self::Header {
|
||||
&self.header
|
||||
}
|
||||
|
||||
fn set_header(&mut self, header: Self::Header) {
|
||||
self.header = header
|
||||
fn set_header(&mut self, header: &Self::Header) {
|
||||
self.header = *header
|
||||
}
|
||||
|
||||
fn bitmap(&self) -> &Vec<u8> {
|
||||
&self.bitmap
|
||||
}
|
||||
|
||||
fn into_bitmap(self) -> Vec<u8> {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
mod binio;
|
||||
pub mod common;
|
||||
mod compression;
|
||||
|
||||
pub mod dynamic;
|
||||
pub mod common;
|
||||
pub mod formats {
|
||||
pub mod cz0;
|
||||
pub mod cz1;
|
||||
|
|
|
@ -7,3 +7,5 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
cz = { path = "../cz" }
|
||||
image = "0.25.1"
|
||||
walkdir = "2.5.0"
|
||||
|
|
|
@ -1,13 +1,43 @@
|
|||
use cz::{Cz3Image, CzImage};
|
||||
use cz::{dynamic::DynamicCz, CzImage};
|
||||
use std::fs;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
fn main() {
|
||||
let mut input = fs::File::open("../../test_files/GOOD_00009.cz3")
|
||||
.expect("Failed to open file");
|
||||
if let Err(err) = fs::DirBuilder::new().create("test/") {
|
||||
println!("{}", err);
|
||||
}
|
||||
|
||||
let timer = std::time::Instant::now();
|
||||
let img_file = Cz3Image::decode(&mut input).expect("Failed to decode image");
|
||||
println!("{:?}", timer.elapsed());
|
||||
let mut success = 0;
|
||||
let mut failure = 0;
|
||||
for entry in WalkDir::new("../../test_files") {
|
||||
let entry = entry.unwrap();
|
||||
|
||||
img_file.save_as_png("test1.png").unwrap();
|
||||
if entry.path().is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut input = match fs::File::open(entry.path()) {
|
||||
Ok(file) => file,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let img_file = match DynamicCz::decode(&mut input) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
println!(
|
||||
"{}: {}",
|
||||
entry.path().file_name().unwrap().to_string_lossy(),
|
||||
err,
|
||||
);
|
||||
failure += 1;
|
||||
continue;
|
||||
},
|
||||
};
|
||||
|
||||
success += 1;
|
||||
|
||||
img_file.save_as_png(
|
||||
&format!("test/z-{}.png", entry.path().file_stem().unwrap().to_string_lossy())
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue