mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 13:28:47 +08:00
add import support for emote psb files
fix create file bug in main
This commit is contained in:
@@ -4,6 +4,7 @@ use crate::ext::psb::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::encoding::*;
|
||||
use crate::utils::files::*;
|
||||
use crate::utils::img::*;
|
||||
use anyhow::Result;
|
||||
use base64::Engine;
|
||||
@@ -78,6 +79,21 @@ impl ScriptBuilder for PsbBuilder {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn can_create_file(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn create_file<'a>(
|
||||
&'a self,
|
||||
filename: &'a str,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
file_encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_file(filename, writer, encoding, file_encoding)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -123,6 +139,7 @@ impl Psb {
|
||||
pb.to_string_lossy().to_string()
|
||||
};
|
||||
let path = folder_path.join(&res.path);
|
||||
make_sure_dir_exists(&path)?;
|
||||
let img = ImageData {
|
||||
width: tlg.width as u32,
|
||||
height: tlg.height as u32,
|
||||
@@ -137,6 +154,7 @@ impl Psb {
|
||||
encode_img(img, outtype, &path.to_string_lossy(), &self.config)?;
|
||||
} else {
|
||||
let path = folder_path.join(&res.path);
|
||||
make_sure_dir_exists(&path)?;
|
||||
std::fs::write(&path, data)?;
|
||||
}
|
||||
Ok(res)
|
||||
@@ -172,11 +190,30 @@ impl TlgInfo {
|
||||
}
|
||||
Self { metadata }
|
||||
}
|
||||
|
||||
fn to_tlg_tags(&self, encoding: Encoding) -> Result<HashMap<Vec<u8>, Vec<u8>>> {
|
||||
let mut tags = HashMap::new();
|
||||
for (k, v) in &self.metadata {
|
||||
let k = if k.starts_with("base64:") {
|
||||
base64::engine::general_purpose::STANDARD.decode(&k[7..])?
|
||||
} else {
|
||||
encode_string(encoding, k, false)?
|
||||
};
|
||||
let v = if v.starts_with("base64:") {
|
||||
base64::engine::general_purpose::STANDARD.decode(&v[7..])?
|
||||
} else {
|
||||
encode_string(encoding, v, false)?
|
||||
};
|
||||
tags.insert(k, v);
|
||||
}
|
||||
Ok(tags)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Resource {
|
||||
path: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
tlg: Option<TlgInfo>,
|
||||
}
|
||||
|
||||
@@ -206,17 +243,15 @@ impl Script for Psb {
|
||||
pb.set_extension("");
|
||||
pb
|
||||
};
|
||||
if self.psb.resources().len() > 0 || self.psb.extra().len() > 0 {
|
||||
std::fs::create_dir_all(&folder_path)?;
|
||||
}
|
||||
for (i, data) in self.psb.resources().iter().enumerate() {
|
||||
let i = i as u64;
|
||||
let res_name = self
|
||||
.psb
|
||||
.root()
|
||||
.find_resource_key(i)
|
||||
.map(|s| s.to_string())
|
||||
.find_resource_key(i, vec![])
|
||||
.map(|s| s.join("/"))
|
||||
.unwrap_or(format!("res_{}", i));
|
||||
let res_name = sanitize_path(&res_name);
|
||||
let res = self.output_resource(&folder_path, res_name, data)?;
|
||||
resources.push(res);
|
||||
}
|
||||
@@ -225,9 +260,10 @@ impl Script for Psb {
|
||||
let res_name = self
|
||||
.psb
|
||||
.root()
|
||||
.find_resource_key(i)
|
||||
.map(|s| format!("extra_{}", s))
|
||||
.find_resource_key(i, vec![])
|
||||
.map(|s| format!("extra_{}", s.join("/")))
|
||||
.unwrap_or(format!("extra_res_{}", i));
|
||||
let res_name = sanitize_path(&res_name);
|
||||
let res = self.output_resource(&folder_path, res_name, data)?;
|
||||
extra_resources.push(res);
|
||||
}
|
||||
@@ -239,4 +275,91 @@ impl Script for Psb {
|
||||
file.write_all(&s)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn custom_import<'a>(
|
||||
&'a self,
|
||||
custom_filename: &'a str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
create_file(custom_filename, file, encoding, output_encoding)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_resource(
|
||||
folder_path: &std::path::PathBuf,
|
||||
res: &Resource,
|
||||
encoding: Encoding,
|
||||
) -> Result<Vec<u8>> {
|
||||
if let Some(tlg) = &res.tlg {
|
||||
let path = folder_path.join(&res.path);
|
||||
let imgfmt = ImageOutputType::try_from(path.as_path())?;
|
||||
let mut img = decode_img(imgfmt, &path.to_string_lossy())?;
|
||||
if img.depth != 8 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Only 8-bit images are supported for TLG conversion"
|
||||
));
|
||||
}
|
||||
let color_type = match img.color_type {
|
||||
ImageColorType::Bgr => TlgColorType::Bgr24,
|
||||
ImageColorType::Bgra => TlgColorType::Bgra32,
|
||||
ImageColorType::Grayscale => TlgColorType::Grayscale8,
|
||||
ImageColorType::Rgb => {
|
||||
convert_rgb_to_bgr(&mut img)?;
|
||||
TlgColorType::Bgr24
|
||||
}
|
||||
ImageColorType::Rgba => {
|
||||
convert_rgba_to_bgra(&mut img)?;
|
||||
TlgColorType::Bgra32
|
||||
}
|
||||
};
|
||||
let tlg = Tlg {
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
version: 5,
|
||||
color: color_type,
|
||||
data: img.data,
|
||||
tags: tlg.to_tlg_tags(encoding)?,
|
||||
};
|
||||
let mut writer = MemWriter::new();
|
||||
save_tlg(&tlg, &mut writer)?;
|
||||
Ok(writer.into_inner())
|
||||
} else {
|
||||
let path = folder_path.join(&res.path);
|
||||
Ok(std::fs::read(&path)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_file<'a>(
|
||||
custom_filename: &'a str,
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
let input = read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &input, true)?;
|
||||
let data = json::parse(&s)?;
|
||||
let resources: Vec<Resource> = serde_json::from_str(&data["resources"].dump())?;
|
||||
let extra_resources: Vec<Resource> = serde_json::from_str(&data["extra_resources"].dump())?;
|
||||
let mut psb = VirtualPsbFixed::with_json(&data)?;
|
||||
let folder_path = {
|
||||
let mut pb = std::path::PathBuf::from(custom_filename);
|
||||
pb.set_extension("");
|
||||
pb
|
||||
};
|
||||
for res in resources {
|
||||
let res = read_resource(&folder_path, &res, encoding)?;
|
||||
psb.resources_mut().push(res);
|
||||
}
|
||||
for res in extra_resources {
|
||||
let res = read_resource(&folder_path, &res, encoding)?;
|
||||
psb.extra_mut().push(res);
|
||||
}
|
||||
let psb = psb.to_psb(false);
|
||||
let psb_writer = PsbWriter::new(psb, &mut writer);
|
||||
psb_writer
|
||||
.finish()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to write psb: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user