100 lines
4.8 KiB
Rust
100 lines
4.8 KiB
Rust
fn main() {
|
|
let psd_path = "/home/hc/Pictures/Forest Text Effect/Forest-Text-mini.psd";
|
|
let bytes = std::fs::read(psd_path).unwrap();
|
|
let mut r = psd::psd_reader::PsdReader::new(&bytes);
|
|
|
|
r.read(26).unwrap();
|
|
let color_mode_len = r.read_u32().unwrap() as usize;
|
|
r.read(color_mode_len).unwrap();
|
|
let img_res_len = r.read_u32().unwrap() as usize;
|
|
r.read(img_res_len).unwrap();
|
|
let _layer_mask_len_val = r.read_u32().unwrap() as usize;
|
|
let _layer_info_len = r.read_u32().unwrap() as usize;
|
|
let layer_count_raw = r.read_i16().unwrap();
|
|
let layer_count = layer_count_raw.abs() as usize;
|
|
|
|
for idx in 0..layer_count {
|
|
let _top = r.read_i32().unwrap();
|
|
let _left = r.read_i32().unwrap();
|
|
let _bottom = r.read_i32().unwrap();
|
|
let _right = r.read_i32().unwrap();
|
|
let channel_count = r.read_u16().unwrap() as usize;
|
|
for _ in 0..channel_count {
|
|
let _id = r.read_i16().unwrap();
|
|
let _len = r.read_u32().unwrap();
|
|
}
|
|
r.read(4).unwrap(); r.read(4).unwrap(); r.read_u8().unwrap(); r.read_u8().unwrap(); r.read_u8().unwrap(); r.read(1).unwrap();
|
|
|
|
let extra_data_len = r.read_u32().unwrap() as usize;
|
|
let extra_start = r.pos();
|
|
|
|
let layer_mask_len = r.read_u32().unwrap() as usize;
|
|
r.read(layer_mask_len).unwrap();
|
|
let blending_ranges_len = r.read_u32().unwrap() as usize;
|
|
r.read(blending_ranges_len).unwrap();
|
|
|
|
let name_len = r.read_u8().unwrap() as usize;
|
|
let name_bytes = r.read(name_len).unwrap();
|
|
let name = String::from_utf8_lossy(name_bytes).to_string();
|
|
let bytes_mod_4 = (name_len + 1) % 4;
|
|
let padding = (4 - bytes_mod_4) % 4;
|
|
r.read(padding).unwrap();
|
|
|
|
if name == "text" {
|
|
println!("\n=== Layer #{}: '{}' ===", idx, name);
|
|
|
|
while r.pos() < extra_start + extra_data_len {
|
|
let sig = r.read(4).unwrap();
|
|
if sig != b"8BIM" && sig != b"8B64" { break; }
|
|
let key_bytes = r.read(4).unwrap();
|
|
let key = String::from_utf8_lossy(key_bytes).to_string();
|
|
let block_len = r.read_u32().unwrap() as usize;
|
|
let block_start = r.pos();
|
|
|
|
println!(" Found block key: {}", key);
|
|
|
|
if key == "lfx2" {
|
|
let data = r.read(block_len).unwrap().to_vec();
|
|
println!(" lfx2 block data len: {}", data.len());
|
|
match hcie_fx::parser::parse_lfx2(&data) {
|
|
Ok(fx) => {
|
|
println!(" Parsed {} effects from lfx2:", fx.len());
|
|
for e in fx {
|
|
println!(" - {}: enabled={}", e.effect_name(), e.is_enabled());
|
|
if let hcie_fx::types::LayerEffect::GradientOverlay { gradient, .. } = &e {
|
|
println!(" Gradient Overlay style: {}, stops count: {}", gradient.gradient_type, gradient.color_stops.len());
|
|
}
|
|
}
|
|
}
|
|
Err(e) => { println!(" parse_lfx2 failed: {}", e); }
|
|
}
|
|
} else if key == "lrFX" {
|
|
let data = r.read(block_len).unwrap().to_vec();
|
|
println!(" lrFX block data len: {}", data.len());
|
|
match hcie_fx::parser::parse_lrFX(&data) {
|
|
Ok(fx) => {
|
|
println!(" Parsed {} effects from lrFX:", fx.len());
|
|
for e in fx {
|
|
println!(" - {}: enabled={}", e.effect_name(), e.is_enabled());
|
|
if let hcie_fx::types::LayerEffect::ColorOverlay { color, opacity, blend_mode, .. } = &e {
|
|
println!(" ColorOverlay: rgba={:?} opacity={} blend={:?}", color, opacity, blend_mode);
|
|
}
|
|
if let hcie_fx::types::LayerEffect::DropShadow { color, opacity, blend_mode, .. } = &e {
|
|
println!(" DropShadow: rgba={:?} opacity={} blend={:?}", color, opacity, blend_mode);
|
|
}
|
|
}
|
|
}
|
|
Err(e) => { println!(" parse_lrFX failed: {}", e); }
|
|
}
|
|
} else {
|
|
r.read(block_len).unwrap();
|
|
}
|
|
r.seek(block_start + block_len).unwrap();
|
|
if block_len % 2 != 0 { r.read(1).unwrap(); }
|
|
}
|
|
}
|
|
|
|
r.seek(extra_start + extra_data_len).unwrap();
|
|
}
|
|
}
|