mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 21:38:58 +08:00
Add support to create BGI sysgrp image
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use crate::ext::io::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::img::*;
|
||||
use anyhow::Result;
|
||||
|
||||
fn try_parse(buf: &[u8]) -> Result<u8> {
|
||||
@@ -72,6 +73,19 @@ impl ScriptBuilder for BgiImageBuilder {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn can_create_image_file(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn create_image_file<'a>(
|
||||
&'a self,
|
||||
data: ImageData,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
options: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_image(data, writer, options.bgi_img_scramble.unwrap_or(false))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -81,10 +95,73 @@ pub struct BgiImage {
|
||||
height: u32,
|
||||
color_type: ImageColorType,
|
||||
is_scrambled: bool,
|
||||
opt_is_scrambled: Option<bool>,
|
||||
}
|
||||
|
||||
fn create_image<'a>(
|
||||
mut data: ImageData,
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
scrambled: bool,
|
||||
) -> Result<()> {
|
||||
writer.write_u16(data.width as u16)?;
|
||||
writer.write_u16(data.height as u16)?;
|
||||
if data.depth != 8 {
|
||||
return Err(anyhow::anyhow!("Unsupported image depth: {}", data.depth));
|
||||
}
|
||||
match data.color_type {
|
||||
ImageColorType::Bgr => {}
|
||||
ImageColorType::Bgra => {}
|
||||
ImageColorType::Grayscale => {}
|
||||
ImageColorType::Rgb => {
|
||||
convert_rgb_to_bgr(&mut data)?;
|
||||
}
|
||||
ImageColorType::Rgba => {
|
||||
convert_rgba_to_bgra(&mut data)?;
|
||||
}
|
||||
}
|
||||
let bpp = data.color_type.bpp(8);
|
||||
writer.write_u16(bpp)?;
|
||||
let flag = if scrambled { 1 } else { 0 };
|
||||
writer.write_u16(flag)?;
|
||||
writer.write_u64(0)?; // Padding
|
||||
let stride = data.width as usize * ((data.color_type.bpp(8) as usize + 7) / 8);
|
||||
let buf_size = stride * data.height as usize;
|
||||
if scrambled {
|
||||
let bpp = data.color_type.bpp(1) as usize;
|
||||
for i in 0..bpp {
|
||||
let mut dst = i;
|
||||
let mut incr = 0u8;
|
||||
let mut h = data.height;
|
||||
while h > 0 {
|
||||
for _ in 0..data.width {
|
||||
writer.write_u8(data.data[dst].wrapping_sub(incr))?;
|
||||
incr = data.data[dst];
|
||||
dst += bpp;
|
||||
}
|
||||
h -= 1;
|
||||
if h == 0 {
|
||||
break;
|
||||
}
|
||||
dst += stride;
|
||||
let mut pos = dst;
|
||||
for _ in 0..data.width {
|
||||
pos -= bpp;
|
||||
writer.write_u8(data.data[pos].wrapping_sub(incr))?;
|
||||
incr = data.data[pos];
|
||||
}
|
||||
h -= 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// PNG sometimes return more padding data than expected
|
||||
// We will write only the required size
|
||||
writer.write_all(&data.data[..buf_size])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl BgiImage {
|
||||
pub fn new(buf: Vec<u8>, _config: &ExtraConfig) -> Result<Self> {
|
||||
pub fn new(buf: Vec<u8>, config: &ExtraConfig) -> Result<Self> {
|
||||
let mut reader = MemReader::new(buf);
|
||||
let width = reader.read_u16()? as u32;
|
||||
let height = reader.read_u16()? as u32;
|
||||
@@ -108,6 +185,7 @@ impl BgiImage {
|
||||
height,
|
||||
color_type,
|
||||
is_scrambled,
|
||||
opt_is_scrambled: config.bgi_img_scramble,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -126,14 +204,41 @@ impl Script for BgiImage {
|
||||
}
|
||||
|
||||
fn export_image(&self) -> Result<ImageData> {
|
||||
let stride = self.width as usize * ((self.color_type.bbp(8) as usize + 7) / 8);
|
||||
let stride = self.width as usize * ((self.color_type.bpp(8) as usize + 7) / 8);
|
||||
let buf_size = stride * self.height as usize;
|
||||
if self.is_scrambled {
|
||||
return Err(anyhow::anyhow!("Scrambled images are not supported"));
|
||||
}
|
||||
let mut data = Vec::with_capacity(buf_size);
|
||||
data.resize(buf_size, 0);
|
||||
self.data.cpeek_extract_at(0x10, &mut data)?;
|
||||
if self.is_scrambled {
|
||||
let mut reader = self.data.to_ref();
|
||||
reader.pos = 0x10;
|
||||
let bpp = self.color_type.bpp(1) as usize;
|
||||
for i in 0..bpp {
|
||||
let mut dst = i;
|
||||
let mut incr = 0u8;
|
||||
let mut h = self.height;
|
||||
while h > 0 {
|
||||
for _ in 0..self.width {
|
||||
incr = incr.wrapping_add(reader.read_u8()?);
|
||||
data[dst] = incr;
|
||||
dst += bpp;
|
||||
}
|
||||
h -= 1;
|
||||
if h == 0 {
|
||||
break;
|
||||
}
|
||||
dst += stride;
|
||||
let mut pos = dst;
|
||||
for _ in 0..self.width {
|
||||
pos -= bpp;
|
||||
incr = incr.wrapping_add(reader.read_u8()?);
|
||||
data[pos] = incr;
|
||||
}
|
||||
h -= 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.data.cpeek_extract_at(0x10, &mut data)?;
|
||||
}
|
||||
Ok(ImageData {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
@@ -142,4 +247,12 @@ impl Script for BgiImage {
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
fn import_image<'a>(&'a self, data: ImageData, file: Box<dyn WriteSeek + 'a>) -> Result<()> {
|
||||
create_image(
|
||||
data,
|
||||
file,
|
||||
self.opt_is_scrambled.unwrap_or(self.is_scrambled),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user