Add BGI Image decode support

Fix DSC decompress
This commit is contained in:
2025-06-12 21:52:01 +08:00
parent 8bed66d4f1
commit 242d501af5
13 changed files with 395 additions and 14 deletions

View File

@@ -108,6 +108,34 @@ pub trait ScriptBuilder: std::fmt::Debug {
let f = std::io::BufWriter::new(f);
self.create_file(filename, Box::new(f), encoding, file_encoding)
}
#[cfg(feature = "image")]
fn is_image(&self) -> bool {
false
}
#[cfg(feature = "image")]
fn can_create_image_file(&self) -> bool {
false
}
#[cfg(feature = "image")]
fn create_image_file<'a>(
&'a self,
_data: ImageData,
_writer: Box<dyn WriteSeek + 'a>,
) -> Result<()> {
Err(anyhow::anyhow!(
"This script type does not support creating an image file."
))
}
#[cfg(feature = "image")]
fn create_image_file_filename(&self, data: ImageData, filename: &str) -> Result<()> {
let f = std::fs::File::create(filename)?;
let f = std::io::BufWriter::new(f);
self.create_image_file(data, Box::new(f))
}
}
pub trait ArchiveContent: Read {
@@ -222,6 +250,32 @@ pub trait Script: std::fmt::Debug {
) -> Result<Box<dyn Iterator<Item = Result<Box<dyn ArchiveContent>>> + 'a>> {
Ok(Box::new(std::iter::empty()))
}
#[cfg(feature = "image")]
fn is_image(&self) -> bool {
false
}
#[cfg(feature = "image")]
fn export_image(&self) -> Result<ImageData> {
Err(anyhow::anyhow!(
"This script type does not support to export image."
))
}
#[cfg(feature = "image")]
fn import_image<'a>(&'a self, _data: ImageData, _file: Box<dyn WriteSeek + 'a>) -> Result<()> {
Err(anyhow::anyhow!(
"This script type does not support to import image."
))
}
#[cfg(feature = "image")]
fn import_image_filename(&self, data: ImageData, filename: &str) -> Result<()> {
let f = std::fs::File::create(filename)?;
let f = std::io::BufWriter::new(f);
self.import_image(data, Box::new(f))
}
}
pub trait Archive {

View File

@@ -0,0 +1,112 @@
use crate::ext::io::*;
use crate::scripts::base::*;
use crate::types::*;
use anyhow::Result;
#[derive(Debug)]
pub struct BgiImageBuilder {}
impl BgiImageBuilder {
pub const fn new() -> Self {
BgiImageBuilder {}
}
}
impl ScriptBuilder for BgiImageBuilder {
fn default_encoding(&self) -> Encoding {
Encoding::Cp932
}
fn build_script(
&self,
data: Vec<u8>,
_filename: &str,
_encoding: Encoding,
_archive_encoding: Encoding,
config: &ExtraConfig,
) -> Result<Box<dyn Script>> {
Ok(Box::new(BgiImage::new(data, config)?))
}
fn extensions(&self) -> &'static [&'static str] {
&[]
}
fn script_type(&self) -> &'static ScriptType {
&ScriptType::BGIImg
}
fn is_image(&self) -> bool {
true
}
}
#[derive(Debug)]
pub struct BgiImage {
data: MemReader,
width: u32,
height: u32,
color_type: ImageColorType,
is_scrambled: bool,
}
impl BgiImage {
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;
let bpp = reader.read_u16()?;
let color_type = match bpp {
8 => ImageColorType::Grayscale,
24 => ImageColorType::Bgr,
32 => ImageColorType::Bgra,
_ => return Err(anyhow::anyhow!("Unsupported BPP: {}", bpp)),
};
let flag = reader.read_u16()?;
let padding = reader.read_u64()?;
if padding != 0 {
return Err(anyhow::anyhow!("Invalid padding: {}", padding));
}
let is_scrambled = flag != 0;
Ok(BgiImage {
data: reader,
width,
height,
color_type,
is_scrambled,
})
}
}
impl Script for BgiImage {
fn default_output_script_type(&self) -> OutputScriptType {
OutputScriptType::Json
}
fn default_format_type(&self) -> FormatOptions {
FormatOptions::None
}
fn is_image(&self) -> bool {
true
}
fn export_image(&self) -> Result<ImageData> {
let stride = self.width as usize * ((self.color_type.bbp(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)?;
Ok(ImageData {
width: self.width,
height: self.height,
color_type: self.color_type,
depth: 8,
data,
})
}
}

View File

@@ -0,0 +1 @@
pub mod img;

View File

@@ -2,5 +2,7 @@
pub mod archive;
pub mod bp;
pub mod bsi;
#[cfg(feature = "bgi-img")]
pub mod image;
mod parser;
pub mod script;

View File

@@ -24,6 +24,8 @@ lazy_static::lazy_static! {
Box::new(bgi::archive::v1::BgiArchiveBuilder::new()),
#[cfg(feature = "bgi-arc")]
Box::new(bgi::archive::v2::BgiArchiveBuilder::new()),
#[cfg(feature = "bgi-img")]
Box::new(bgi::image::img::BgiImageBuilder::new()),
#[cfg(feature = "escude-arc")]
Box::new(escude::archive::EscudeBinArchiveBuilder::new()),
#[cfg(feature = "escude")]