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(); } }