This commit is contained in:
2026-07-09 02:59:53 +03:00
commit 7ace048d94
817 changed files with 234289 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "hcie-native"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
bincode = "1.3"
hcie-protocol = { path = "../hcie-protocol" }
[lib]
crate-type = ["rlib"]
+153
View File
@@ -0,0 +1,153 @@
use std::io::Read;
use std::path::Path;
use hcie_protocol::{Layer, LayerType, LayerData, LayerStyle, BlendMode};
const HCIE_MAGIC: &[u8] = b"HCIE";
const HCIE_VERSION: u32 = 1;
#[derive(Clone, serde::Serialize, serde::Deserialize)]
struct HcieLayerMeta {
id: u64,
name: String,
layer_type: LayerType,
data: LayerData,
width: u32,
height: u32,
visible: bool,
opacity: f32,
blend_mode: BlendMode,
locked: bool,
parent_id: Option<u64>,
styles: Vec<LayerStyle>,
clipping_mask: bool,
collapsed: bool,
pixel_offset: u64,
pixel_len: u64,
#[serde(default)]
effects: Vec<hcie_protocol::effects::LayerEffect>,
#[serde(default = "default_fill_opacity")]
fill_opacity: f32,
}
fn default_fill_opacity() -> f32 { 1.0 }
#[derive(Clone, serde::Serialize, serde::Deserialize)]
struct HcieDocumentMeta {
name: String,
canvas_width: u32,
canvas_height: u32,
layers: Vec<HcieLayerMeta>,
}
pub fn save_native(layers: &[Layer], path: &Path) -> Result<(), String> {
use std::io::Write;
let mut file = std::fs::File::create(path).map_err(|e| e.to_string())?;
let mut pixel_offset = 0u64;
let mut layer_metas = Vec::with_capacity(layers.len());
for layer in layers {
let pixel_len = layer.pixels.len() as u64;
layer_metas.push(HcieLayerMeta {
id: layer.id,
name: layer.name.clone(),
layer_type: layer.layer_type,
data: layer.data.clone(),
width: layer.width,
height: layer.height,
visible: layer.visible,
opacity: layer.opacity,
blend_mode: layer.blend_mode,
locked: layer.locked,
parent_id: layer.parent_id,
styles: layer.styles.clone(),
clipping_mask: layer.clipping_mask,
collapsed: layer.collapsed,
pixel_offset,
pixel_len,
effects: layer.effects.clone(),
fill_opacity: layer.fill_opacity,
});
pixel_offset += pixel_len;
}
let doc_meta = HcieDocumentMeta {
name: "Untitled".to_string(),
canvas_width: layers.first().map(|l| l.width).unwrap_or(800),
canvas_height: layers.first().map(|l| l.height).unwrap_or(600),
layers: layer_metas,
};
let json = serde_json::to_vec(&doc_meta).map_err(|e| e.to_string())?;
let json_len = json.len() as u32;
file.write_all(HCIE_MAGIC).map_err(|e| e.to_string())?;
file.write_all(&HCIE_VERSION.to_le_bytes()).map_err(|e| e.to_string())?;
file.write_all(&json_len.to_le_bytes()).map_err(|e| e.to_string())?;
file.write_all(&json).map_err(|e| e.to_string())?;
for layer in layers {
file.write_all(&layer.pixels).map_err(|e| e.to_string())?;
}
Ok(())
}
pub fn load_native(path: &Path) -> Result<Vec<Layer>, String> {
let mut file = std::fs::File::open(path).map_err(|e| e.to_string())?;
let mut magic = [0u8; 4];
file.read_exact(&mut magic).map_err(|e| e.to_string())?;
if &magic != HCIE_MAGIC {
return Err("Not a valid HCIE file".to_string());
}
let mut version_buf = [0u8; 4];
file.read_exact(&mut version_buf).map_err(|e| e.to_string())?;
let version = u32::from_le_bytes(version_buf);
if version != HCIE_VERSION {
return Err(format!("Unsupported HCIE version: {}", version));
}
let mut json_len_buf = [0u8; 4];
file.read_exact(&mut json_len_buf).map_err(|e| e.to_string())?;
let json_len = u32::from_le_bytes(json_len_buf) as usize;
let mut json = vec![0u8; json_len];
file.read_exact(&mut json).map_err(|e| e.to_string())?;
let doc_meta: HcieDocumentMeta = serde_json::from_slice(&json).map_err(|e| e.to_string())?;
let mut pixel_data = Vec::new();
file.read_to_end(&mut pixel_data).map_err(|e| e.to_string())?;
let mut layers = Vec::with_capacity(doc_meta.layers.len());
for meta in doc_meta.layers {
let offset = meta.pixel_offset as usize;
let len = meta.pixel_len as usize;
let pixels = if offset + len <= pixel_data.len() {
pixel_data[offset..offset + len].to_vec()
} else {
vec![0u8; (meta.width * meta.height * 4) as usize]
};
let mut layer = Layer::from_rgba(meta.name.clone(), meta.width, meta.height, pixels);
layer.layer_type = meta.layer_type;
layer.data = meta.data;
layer.visible = meta.visible;
layer.opacity = meta.opacity;
layer.blend_mode = meta.blend_mode;
layer.locked = meta.locked;
layer.parent_id = meta.parent_id;
layer.styles = meta.styles;
layer.clipping_mask = meta.clipping_mask;
layer.collapsed = meta.collapsed;
layer.id = meta.id;
layer.effects = meta.effects;
layer.fill_opacity = meta.fill_opacity;
layers.push(layer);
}
Ok(layers)
}