mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 23:32:55 -05:00
Merge branch 'fixed_problems'
This commit is contained in:
commit
83752cbf00
4 changed files with 57 additions and 29 deletions
|
@ -10,4 +10,4 @@ A encoder/decoder for CZ# image files used in the LUCA System Engine.
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
thiserror = "1.0.59"
|
thiserror = "1.0.59"
|
||||||
image = { version = "0.25.1", default-features = false, features = ["png"] }
|
image = { version = "0.25.1", default-features = false, features = ["png"] }
|
||||||
quantizr = "1.4.2"
|
imagequant = "4.3.1"
|
||||||
|
|
|
@ -4,15 +4,28 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
use image::Rgba;
|
use imagequant::Attributes;
|
||||||
use quantizr::Image;
|
|
||||||
|
|
||||||
use crate::common::{CommonHeader, CzError};
|
use crate::common::{CommonHeader, CzError};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Rgba(pub [u8; 4]);
|
||||||
|
|
||||||
|
impl From<[u8; 4]> for Rgba {
|
||||||
|
fn from(value: [u8; 4]) -> Self {
|
||||||
|
Self([value[0], value[1], value[2], value[3]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Palette {
|
||||||
|
pub colors: Vec<Rgba>
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_palette<T: Seek + ReadBytesExt + Read>(
|
pub fn get_palette<T: Seek + ReadBytesExt + Read>(
|
||||||
input: &mut T,
|
input: &mut T,
|
||||||
num_colors: usize,
|
num_colors: usize,
|
||||||
) -> Result<Vec<Rgba<u8>>, CzError> {
|
) -> Result<Palette, CzError> {
|
||||||
let mut colormap = Vec::with_capacity(num_colors);
|
let mut colormap = Vec::with_capacity(num_colors);
|
||||||
let mut rgba_buf = [0u8; 4];
|
let mut rgba_buf = [0u8; 4];
|
||||||
|
|
||||||
|
@ -21,16 +34,16 @@ pub fn get_palette<T: Seek + ReadBytesExt + Read>(
|
||||||
colormap.push(rgba_buf.into());
|
colormap.push(rgba_buf.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(colormap)
|
Ok(Palette { colors: colormap })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take a bitmap of indicies, and map a given palette to it, returning a new
|
/// Take a bitmap of indicies, and map a given palette to it, returning a new
|
||||||
/// RGBA bitmap
|
/// RGBA bitmap
|
||||||
pub fn apply_palette(input: &[u8], palette: &[Rgba<u8>]) -> Result<Vec<u8>, CzError> {
|
pub fn apply_palette(input: &[u8], palette: &Palette) -> Result<Vec<u8>, CzError> {
|
||||||
let mut output_map = Vec::new();
|
let mut output_map = Vec::new();
|
||||||
|
|
||||||
for byte in input.iter() {
|
for byte in input.iter() {
|
||||||
let color = palette.get(*byte as usize);
|
let color = palette.colors.get(*byte as usize);
|
||||||
if let Some(color) = color {
|
if let Some(color) = color {
|
||||||
output_map.extend_from_slice(&color.0);
|
output_map.extend_from_slice(&color.0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,7 +54,7 @@ pub fn apply_palette(input: &[u8], palette: &[Rgba<u8>]) -> Result<Vec<u8>, CzEr
|
||||||
Ok(output_map)
|
Ok(output_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rgba_to_indexed(input: &[u8], palette: &[Rgba<u8>]) -> Result<Vec<u8>, CzError> {
|
pub fn rgba_to_indexed(input: &[u8], palette: &Palette) -> Result<Vec<u8>, CzError> {
|
||||||
let mut output_map = Vec::new();
|
let mut output_map = Vec::new();
|
||||||
let mut cache = HashMap::new();
|
let mut cache = HashMap::new();
|
||||||
|
|
||||||
|
@ -49,7 +62,7 @@ pub fn rgba_to_indexed(input: &[u8], palette: &[Rgba<u8>]) -> Result<Vec<u8>, Cz
|
||||||
let value = match cache.get(rgba) {
|
let value = match cache.get(rgba) {
|
||||||
Some(val) => *val,
|
Some(val) => *val,
|
||||||
None => {
|
None => {
|
||||||
let value = palette.iter().position(|e| e.0 == rgba).unwrap_or_default() as u8;
|
let value = palette.colors.iter().position(|e| e.0 == rgba).unwrap_or_default() as u8;
|
||||||
cache.insert(rgba, value);
|
cache.insert(rgba, value);
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
@ -64,28 +77,32 @@ pub fn rgba_to_indexed(input: &[u8], palette: &[Rgba<u8>]) -> Result<Vec<u8>, Cz
|
||||||
pub fn indexed_gen_palette(
|
pub fn indexed_gen_palette(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
header: &CommonHeader,
|
header: &CommonHeader,
|
||||||
) -> Result<(Vec<u8>, Vec<image::Rgba<u8>>), CzError> {
|
) -> Result<(Vec<u8>, Vec<Rgba>), CzError> {
|
||||||
let size = (header.width() as u32 * header.height() as u32) * 4;
|
let size = (header.width() as u32 * header.height() as u32) * 4;
|
||||||
|
|
||||||
let mut buf = vec![0; size as usize];
|
let mut buf: Vec<u8> = vec![0; size as usize];
|
||||||
buf[..input.len()].copy_from_slice(input);
|
buf[..input.len()].copy_from_slice(input);
|
||||||
|
let buf: Vec<imagequant::RGBA> = buf
|
||||||
|
.windows(4)
|
||||||
|
.step_by(4)
|
||||||
|
.map(|c| imagequant::RGBA::new(c[0], c[1], c[2], c[3]))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let image = Image::new(&buf, header.width() as usize, header.height() as usize).unwrap();
|
let mut quant = Attributes::new();
|
||||||
|
quant.set_speed(1).unwrap();
|
||||||
|
|
||||||
let mut opts = quantizr::Options::default();
|
let mut image = quant.new_image(
|
||||||
opts.set_max_colors(1 << header.depth()).unwrap();
|
buf,
|
||||||
|
header.width() as usize,
|
||||||
|
header.height() as usize,
|
||||||
|
0.0
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
let mut result = quantizr::QuantizeResult::quantize(&image, &opts);
|
let mut quant_result = quant.quantize(&mut image).unwrap();
|
||||||
result.set_dithering_level(0.5).unwrap();
|
|
||||||
|
|
||||||
let mut indicies = vec![0u8; header.width() as usize * header.height() as usize];
|
let (palette, indicies) = quant_result.remapped(&mut image).unwrap();
|
||||||
result.remap_image(&image, indicies.as_mut_slice()).unwrap();
|
|
||||||
|
|
||||||
let palette = result.get_palette();
|
|
||||||
|
|
||||||
let gen_palette = palette
|
let gen_palette = palette
|
||||||
.entries
|
|
||||||
.as_slice()
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| Rgba([c.r, c.g, c.b, c.a]))
|
.map(|c| Rgba([c.r, c.g, c.b, c.a]))
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -93,7 +110,7 @@ pub fn indexed_gen_palette(
|
||||||
Ok((indicies, gen_palette))
|
Ok((indicies, gen_palette))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _default_palette() -> Vec<Rgba<u8>> {
|
pub fn _default_palette() -> Vec<Rgba> {
|
||||||
let mut colormap = Vec::new();
|
let mut colormap = Vec::new();
|
||||||
|
|
||||||
for i in 0..=0xFF {
|
for i in 0..=0xFF {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
use image::Rgba;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write},
|
io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write},
|
||||||
|
@ -7,7 +6,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::{apply_palette, get_palette, indexed_gen_palette, rgba_to_indexed},
|
color::{apply_palette, get_palette, indexed_gen_palette, rgba_to_indexed, Palette},
|
||||||
common::{CommonHeader, CzError, CzVersion, ExtendedHeader},
|
common::{CommonHeader, CzError, CzVersion, ExtendedHeader},
|
||||||
formats::{cz0, cz1, cz2, cz3, cz4},
|
formats::{cz0, cz1, cz2, cz3, cz4},
|
||||||
};
|
};
|
||||||
|
@ -18,7 +17,7 @@ use crate::{
|
||||||
pub struct DynamicCz {
|
pub struct DynamicCz {
|
||||||
header_common: CommonHeader,
|
header_common: CommonHeader,
|
||||||
header_extended: Option<ExtendedHeader>,
|
header_extended: Option<ExtendedHeader>,
|
||||||
palette: Option<Vec<Rgba<u8>>>,
|
palette: Option<Palette>,
|
||||||
bitmap: Vec<u8>,
|
bitmap: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +135,7 @@ impl DynamicCz {
|
||||||
// Use the existing palette to palette the image
|
// Use the existing palette to palette the image
|
||||||
output_bitmap = rgba_to_indexed(self.bitmap(), pal)?;
|
output_bitmap = rgba_to_indexed(self.bitmap(), pal)?;
|
||||||
|
|
||||||
for rgba in pal {
|
for rgba in &pal.colors {
|
||||||
out_file.write_all(&rgba.0)?;
|
out_file.write_all(&rgba.0)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -258,13 +257,13 @@ impl DynamicCz {
|
||||||
|
|
||||||
/// Retrieve a reference to the palette if it exists, otherwise [`None`]
|
/// Retrieve a reference to the palette if it exists, otherwise [`None`]
|
||||||
/// is returned
|
/// is returned
|
||||||
pub fn palette(&self) -> &Option<Vec<Rgba<u8>>> {
|
pub fn palette(&self) -> &Option<Palette> {
|
||||||
&self.palette
|
&self.palette
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a mutable reference to the palette if it exists, otherwise
|
/// Retrieve a mutable reference to the palette if it exists, otherwise
|
||||||
/// [`None`] is returned
|
/// [`None`] is returned
|
||||||
pub fn palette_mut(&mut self) -> &mut Option<Vec<Rgba<u8>>> {
|
pub fn palette_mut(&mut self) -> &mut Option<Palette> {
|
||||||
&mut self.palette
|
&mut self.palette
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -204,6 +204,18 @@ fn main() {
|
||||||
cz.set_bitmap(repl_img.into_raw());
|
cz.set_bitmap(repl_img.into_raw());
|
||||||
cz.remove_palette();
|
cz.remove_palette();
|
||||||
|
|
||||||
|
if let Some(ver) = version {
|
||||||
|
match cz.header_mut().set_version(*ver) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(_) => {
|
||||||
|
Error::raw(
|
||||||
|
ErrorKind::ValueValidation,
|
||||||
|
format!("Invalid CZ Version {}; expected 0, 1, 2, 3, or 4\n", ver)
|
||||||
|
).exit()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
cz.save_as_cz(&final_path).unwrap();
|
cz.save_as_cz(&final_path).unwrap();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue