use byteorder::{BigEndian, ReadBytesExt};
use std::io::Read;
use crate::data::error::Error;
use crate::data::xcf::XcfCompression;
use crate::RgbaPixel;
#[derive(Debug, PartialEq)]
pub struct ResolutionProperty {
pub xres: f32,
pub yres: f32,
}
#[derive(Debug, PartialEq)]
pub struct ParasiteProperty {
pub name: String,
pub flags: u32,
pub data: String,
}
#[derive(Debug, PartialEq)]
pub enum PropertyPayload {
ColorMap { colors: usize },
End,
Compression(XcfCompression),
ResolutionProperty(ResolutionProperty),
Tatoo(u32),
Unit(u32),
Parasites(Vec<ParasiteProperty>),
ActiveLayer(),
OpacityLayer(RgbaPixel),
FloatOpacityLayer(),
VisibleLayer(),
LinkedLayer(u32),
ColorTagLayer(u32),
LockContentLayer(u32),
LockAlphaLayer(u32),
LockPositionLayer(u32),
ApplyMaskLayer(u32),
EditMaskLayer(u32),
ShowMaskLayer(u32),
OffsetsLayer(u32, u32),
ModeLayer(u32),
BlendSpaceLayer(u32),
CompositeSpaceLayer(u32),
CompositeModeLayer(u32),
Unknown(Vec<u8>),
}
#[derive(Debug, PartialEq)]
pub struct Property {
pub kind: PropertyIdentifier,
pub length: usize,
pub payload: PropertyPayload,
}
impl Property {
fn guess_size(&self) -> usize {
match self.payload {
PropertyPayload::ColorMap { colors, .. } => {
3 * colors + 4
}
_ => self.length,
}
}
fn parse<R: Read>(mut rdr: R) -> Result<Property, Error> {
let kind = PropertyIdentifier::new(rdr.read_u32::<BigEndian>()?);
let length = rdr.read_u32::<BigEndian>()? as usize;
let payload = PropertyPayload::parse(&mut rdr, kind, length)?;
Ok(Property {
kind,
length,
payload,
})
}
pub fn parse_list<R: Read>(mut rdr: R) -> Result<Vec<Property>, Error> {
let mut props = Vec::new();
loop {
let p = Property::parse(&mut rdr)?;
if let PropertyIdentifier::PropEnd = p.kind {
break;
}
props.push(p);
}
Ok(props)
}
}
macro_rules! prop_ident_gen {
(
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u32)]
pub enum PropertyIdentifier {
$(
$prop:ident = $val:expr
),+,
}
) => {
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u32)]
pub enum PropertyIdentifier {
$(
$prop = $val
),+,
}
impl PropertyIdentifier {
pub fn new(prop: u32) -> PropertyIdentifier {
match prop {
$(
$val => PropertyIdentifier::$prop
),+,
_ => todo!()
}
}
}
}
}
prop_ident_gen! {
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u32)]
pub enum PropertyIdentifier {
PropEnd = 0,
PropColormap = 1,
PropActiveLayer = 2,
PropActiveChannel = 3,
PropSelection = 4,
PropFloatingSelection = 5,
PropOpacity = 6,
PropMode = 7,
PropVisible = 8,
PropLinked = 9,
PropLockAlpha = 10,
PropApplyMask = 11,
PropEditMask = 12,
PropShowMask = 13,
PropOffsets = 15,
PropCompression = 17,
TypeIdentification = 18,
PropResolution = 19,
PropTattoo = 20,
PropParasites = 21,
PropUnit = 22,
PropPaths = 23,
PropUserUnit = 24,
PropVectors = 25,
PropTextLayerFlags = 26,
PropOldSamplePoints = 27,
PropLockContent = 28,
PropLockPosition = 32,
PropFloatOpacity = 33,
PropColorTag = 34,
PropCompositeMode = 35,
PropCompositeSpace = 36,
PropBlendSpace = 37,
PropFloatColor = 38,
PropSamplePoints = 39,
PropItemSet = 40,
PropItemSetItem = 41,
PropLockVisibility = 42,
PropSelectedPath = 43,
PropFilterRegion = 44,
PropFilterArgument = 45,
PropFilterClip = 46,
}
}