mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 13:28:47 +08:00
Add support to export pimg file as PSD file
This commit is contained in:
@@ -9,6 +9,26 @@ use anyhow::Result;
|
||||
use std::io::Write;
|
||||
use types::*;
|
||||
|
||||
#[derive(Debug, Clone, msg_tool_macro::Default)]
|
||||
pub struct PsdLayerOption {
|
||||
#[default(true)]
|
||||
/// Whether the layer is visible.
|
||||
pub visible: bool,
|
||||
#[default(255)]
|
||||
/// The opacity of the layer (0-255).
|
||||
pub opacity: u8,
|
||||
}
|
||||
|
||||
impl PsdLayerOption {
|
||||
fn to_flags(&self) -> u8 {
|
||||
let mut flags = 0u8;
|
||||
if !self.visible {
|
||||
flags |= 0b0000_0010;
|
||||
}
|
||||
flags
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple PSD writer.
|
||||
pub struct PsdWriter {
|
||||
psd: PsdFile,
|
||||
@@ -86,8 +106,21 @@ impl PsdWriter {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a visible layer to the PSD file.
|
||||
pub fn add_layer(&mut self, name: &str, x: u32, y: u32, mut data: ImageData) -> Result<()> {
|
||||
/// Add a layer to the PSD file.
|
||||
///
|
||||
/// * `name` - The name of the layer.
|
||||
/// * `x` - The x position of the layer.
|
||||
/// * `y` - The y position of the layer.
|
||||
/// * `data` - The image data of the layer.
|
||||
/// * `option` - The options for the layer.
|
||||
pub fn add_layer(
|
||||
&mut self,
|
||||
name: &str,
|
||||
x: u32,
|
||||
y: u32,
|
||||
mut data: ImageData,
|
||||
option: Option<PsdLayerOption>,
|
||||
) -> Result<()> {
|
||||
if data.color_type == ImageColorType::Bgr {
|
||||
convert_bgr_to_rgb(&mut data)?;
|
||||
}
|
||||
@@ -106,6 +139,16 @@ impl PsdWriter {
|
||||
channel_ids.push(-1); // Alpha
|
||||
}
|
||||
}
|
||||
let flags = if let Some(opt) = &option {
|
||||
opt.to_flags()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let opacity = if let Some(opt) = &option {
|
||||
opt.opacity
|
||||
} else {
|
||||
255
|
||||
};
|
||||
let mut layer_base = LayerRecordBase {
|
||||
top: y as i32,
|
||||
left: x as i32,
|
||||
@@ -115,9 +158,9 @@ impl PsdWriter {
|
||||
channel_infos: Vec::new(),
|
||||
blend_mode_signature: *IMAGE_RESOURCE_SIGNATURE,
|
||||
blend_mode_key: *b"norm",
|
||||
opacity: 255,
|
||||
opacity,
|
||||
clipping: 0,
|
||||
flags: 1,
|
||||
flags,
|
||||
filler: 0,
|
||||
};
|
||||
let mut channel_ranges = Vec::new();
|
||||
|
||||
@@ -112,8 +112,11 @@ impl StructPack for PascalString4 {
|
||||
let mut encoded = encode_string(encoding, &self.0, true)?;
|
||||
let len = encoded.len() as u8;
|
||||
len.pack(writer, big, encoding, info)?;
|
||||
while (len as usize + 1) % 4 != 0 {
|
||||
encoded.push(0); // padding bytes
|
||||
let padding = 4 - (len as usize + 1) % 4;
|
||||
if padding != 4 {
|
||||
for _ in 0..padding {
|
||||
encoded.push(0); // padding bytes
|
||||
}
|
||||
}
|
||||
writer.write_all(&encoded)?;
|
||||
Ok(())
|
||||
@@ -129,8 +132,17 @@ impl StructUnpack for PascalString4 {
|
||||
) -> Result<Self> {
|
||||
let len = u8::unpack(reader, big, encoding, info)?;
|
||||
let encoded = reader.read_exact_vec(len as usize)?;
|
||||
while (len as usize + 1) % 4 != 0 {
|
||||
reader.read_u8()?; // padding bytes
|
||||
let padding = 4 - (len as usize + 1) % 4;
|
||||
if padding != 4 {
|
||||
for _ in 0..padding {
|
||||
let pad_byte = reader.read_u8()?;
|
||||
if pad_byte != 0 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected padding byte to be 0, got {}",
|
||||
pad_byte
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
let string = decode_to_string(encoding, &encoded, true)?;
|
||||
Ok(PascalString4(string))
|
||||
|
||||
Reference in New Issue
Block a user