mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 21:38:58 +08:00
Add BGI Image decode support
Fix DSC decompress
This commit is contained in:
@@ -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 {
|
||||
|
||||
112
src/scripts/bgi/image/img.rs
Normal file
112
src/scripts/bgi/image/img.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
1
src/scripts/bgi/image/mod.rs
Normal file
1
src/scripts/bgi/image/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod img;
|
||||
@@ -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;
|
||||
|
||||
@@ -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")]
|
||||
|
||||
Reference in New Issue
Block a user