From 33a513ef15adfbf802386e4223d52ffe18cba21b Mon Sep 17 00:00:00 2001 From: lifegpc Date: Wed, 4 Feb 2026 11:32:11 +0800 Subject: [PATCH] Add support to export layer id --- src/ext/io.rs | 6 ++++++ src/scripts/emote/pimg.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/utils/psd/mod.rs | 33 ++++++++++++++++++++++++--------- src/utils/psd/types.rs | 14 ++++++++++++++ 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/ext/io.rs b/src/ext/io.rs index dc09452..80c3876 100644 --- a/src/ext/io.rs +++ b/src/ext/io.rs @@ -1456,6 +1456,8 @@ pub trait SeekExt { /// Aligns the current position to the given alignment. /// Returns the new position after alignment. fn align(&mut self, align: u64) -> Result; + /// Seeks to the end of the stream. + fn seek_to_end(&mut self) -> Result; } impl SeekExt for T { @@ -1474,6 +1476,10 @@ impl SeekExt for T { } Ok(aligned_pos) } + + fn seek_to_end(&mut self) -> Result { + self.seek(SeekFrom::End(0)) + } } #[derive(Clone)] diff --git a/src/scripts/emote/pimg.rs b/src/scripts/emote/pimg.rs index 5dde688..9adf04e 100644 --- a/src/scripts/emote/pimg.rs +++ b/src/scripts/emote/pimg.rs @@ -6,6 +6,7 @@ use crate::try_option; use crate::types::*; use crate::utils::img::*; use crate::utils::psd::*; +use crate::utils::struct_pack::*; use anyhow::Result; use emote_psb::PsbReader; use libtlg_rs::*; @@ -247,9 +248,20 @@ impl<'a> PImgLayer<'a> { if visible { draw_on_img_with_opacity(base, &img, self.left, self.top, self.opacity)?; } + let layer_name_source_setting = LayerNameSourceSetting { + id: self.layer_id as i32, + }; + let mut packed = Vec::new(); + layer_name_source_setting.pack(&mut packed, true, Encoding::Utf8, &None)?; + let additional_info = vec![AdditionalLayerInfo { + signature: *IMAGE_RESOURCE_SIGNATURE, + key: *LAYER_NAME_SOURCE_SETTING_KEY, + data: packed, + }]; let option = PsdLayerOption { visible, opacity: self.opacity, + additional_info, }; psd.add_layer(self.name, self.left, self.top, img, Some(option))?; } else { @@ -260,21 +272,46 @@ impl<'a> PImgLayer<'a> { if visible { draw_on_img_with_opacity(base, &img, self.left, self.top, self.opacity)?; } + let layer_name_source_setting = LayerNameSourceSetting { + id: self.layer_id as i32, + }; + let mut packed = Vec::new(); + layer_name_source_setting.pack(&mut packed, true, Encoding::Utf8, &None)?; + let additional_info = vec![AdditionalLayerInfo { + signature: *IMAGE_RESOURCE_SIGNATURE, + key: *LAYER_NAME_SOURCE_SETTING_KEY, + data: packed, + }]; let option = PsdLayerOption { visible, opacity: self.opacity, + additional_info, }; psd.add_layer(self.name, self.left, self.top, img, Some(option))?; } for child in &self.children { child.save_to_psd(img, psd, base)?; } + let layer_name_source_setting = LayerNameSourceSetting { + id: self.layer_id as i32, + }; + let mut packed = Vec::new(); + layer_name_source_setting.pack(&mut packed, true, Encoding::Utf8, &None)?; + let additional_info = vec![AdditionalLayerInfo { + signature: *IMAGE_RESOURCE_SIGNATURE, + key: *LAYER_NAME_SOURCE_SETTING_KEY, + data: packed, + }]; let option = if self.layer_type == 0 { - None + Some(PsdLayerOption { + additional_info, + ..Default::default() + }) } else { Some(PsdLayerOption { visible: self.visible, opacity: self.opacity, + additional_info, }) }; psd.add_layer_group(self.name, self.layer_type == 2, option)?; diff --git a/src/utils/psd/mod.rs b/src/utils/psd/mod.rs index 924d3ae..97b1e77 100644 --- a/src/utils/psd/mod.rs +++ b/src/utils/psd/mod.rs @@ -10,6 +10,11 @@ use anyhow::Result; use std::io::Write; use types::*; +pub use types::{ + AdditionalLayerInfo, IMAGE_RESOURCE_SIGNATURE, LAYER_ID_KEY, LAYER_NAME_SOURCE_SETTING_KEY, + LayerID, LayerNameSourceSetting, +}; + #[derive(Debug, Clone, msg_tool_macro::Default)] pub struct PsdLayerOption { #[default(true)] @@ -18,6 +23,8 @@ pub struct PsdLayerOption { #[default(255)] /// The opacity of the layer (0-255). pub opacity: u8, + /// Additional layer information. + pub additional_info: Vec, } impl PsdLayerOption { @@ -238,12 +245,16 @@ impl PsdWriter { }); } let encoded = encode_string(self.encoding, &name, false)?; + let mut infos = vec![encode_unicode_layer(name)?]; + if let Some(opt) = option { + infos.extend(opt.additional_info); + } let layer = LayerRecord { base: layer_base, layer_mask: None, layer_blending_ranges, layer_name: PascalString4(encoded), - infos: vec![encode_unicode_layer(name)?], + infos, }; self.psd .layer_and_mask_info @@ -286,6 +297,17 @@ impl PsdWriter { } else { 255 }; + let mut infos = vec![ + AdditionalLayerInfo { + signature: *IMAGE_RESOURCE_SIGNATURE, + key: *b"lsct", + data: data.into_inner(), + }, + encode_unicode_layer(name)?, + ]; + if let Some(opt) = option { + infos.extend(opt.additional_info); + } let layer = LayerRecord { base: LayerRecordBase { top: 0, @@ -308,14 +330,7 @@ impl PsdWriter { channel_ranges: vec![], }, layer_name: PascalString4(encoded), - infos: vec![ - AdditionalLayerInfo { - signature: *IMAGE_RESOURCE_SIGNATURE, - key: *b"lsct", - data: data.into_inner(), - }, - encode_unicode_layer(name)?, - ], + infos, }; self.psd .layer_and_mask_info diff --git a/src/utils/psd/types.rs b/src/utils/psd/types.rs index c7b042d..d4b2913 100644 --- a/src/utils/psd/types.rs +++ b/src/utils/psd/types.rs @@ -8,6 +8,8 @@ use std::io::{Read, Seek, Write}; pub const PSD_SIGNATURE: &[u8; 4] = b"8BPS"; pub const IMAGE_RESOURCE_SIGNATURE: &[u8; 4] = b"8BIM"; +pub const LAYER_NAME_SOURCE_SETTING_KEY: &[u8; 4] = b"lnsr"; +pub const LAYER_ID_KEY: &[u8; 4] = b"lyid"; #[derive(Debug, Clone)] pub struct UnicodeString(pub String); @@ -932,3 +934,15 @@ pub struct SectionDividerSetting { pub struct UnicodeLayer { pub name: UnicodeString, } + +#[derive(Debug, Clone, StructPack, StructUnpack)] +pub struct LayerID { + /// ID for the layer + pub id: i32, +} + +#[derive(Debug, Clone, StructPack, StructUnpack)] +pub struct LayerNameSourceSetting { + /// ID for the layer name + pub id: i32, +}