1use byteorder::{BigEndian, ReadBytesExt};
2use std::io::Read;
3
4use crate::data::error::Error;
5use crate::data::xcf::XcfCompression;
6use crate::RgbaPixel;
7
8#[derive(Debug, PartialEq)]
9pub struct ResolutionProperty {
10 pub xres: f32,
11 pub yres: f32,
12}
13
14#[derive(Debug, PartialEq)]
15pub struct ParasiteProperty {
16 pub name: String,
17 pub flags: u32,
18 pub data: String,
19}
20
21#[derive(Debug, PartialEq)]
22pub enum PropertyPayload {
23 ColorMap { colors: usize },
24 End,
25 Compression(XcfCompression),
26 ResolutionProperty(ResolutionProperty),
27 Tatoo(u32),
28 Unit(u32),
29 Parasites(Vec<ParasiteProperty>),
30 ActiveLayer(),
32 OpacityLayer(RgbaPixel),
33 FloatOpacityLayer(),
34 VisibleLayer(),
35 LinkedLayer(u32),
36 ColorTagLayer(u32),
37 LockContentLayer(u32),
38 LockAlphaLayer(u32),
39 LockPositionLayer(u32),
40 ApplyMaskLayer(u32),
41 EditMaskLayer(u32),
42 ShowMaskLayer(u32),
43 OffsetsLayer(u32, u32),
44 ModeLayer(u32),
45 BlendSpaceLayer(u32),
46 CompositeSpaceLayer(u32),
47 CompositeModeLayer(u32),
48 Unknown(Vec<u8>),
49}
50
51#[derive(Debug, PartialEq)]
52pub struct Property {
53 pub kind: PropertyIdentifier,
54 pub length: usize,
55 pub payload: PropertyPayload,
56}
57
58impl Property {
59 fn guess_size(&self) -> usize {
62 match self.payload {
63 PropertyPayload::ColorMap { colors, .. } => {
64 3 * colors + 4
66 }
67 _ => self.length,
69 }
70 }
71
72 fn parse<R: Read>(mut rdr: R) -> Result<Property, Error> {
73 let kind = PropertyIdentifier::new(rdr.read_u32::<BigEndian>()?);
74 let length = rdr.read_u32::<BigEndian>()? as usize;
75 let payload = PropertyPayload::parse(&mut rdr, kind, length)?;
76 Ok(Property {
77 kind,
78 length,
79 payload,
80 })
81 }
82
83 pub fn parse_list<R: Read>(mut rdr: R) -> Result<Vec<Property>, Error> {
84 let mut props = Vec::new();
85 loop {
86 let p = Property::parse(&mut rdr)?;
87 if let PropertyIdentifier::PropEnd = p.kind {
88 break;
89 }
90 props.push(p);
92 }
93 Ok(props)
94 }
95}
96
97macro_rules! prop_ident_gen {
98 (
99 #[derive(Debug, Clone, Copy, PartialEq)]
100 #[repr(u32)]
101 pub enum PropertyIdentifier {
102 $(
104 $prop:ident = $val:expr
105 ),+,
106 }
107 ) => {
108 #[derive(Debug, Clone, Copy, PartialEq)]
109 #[repr(u32)]
110 pub enum PropertyIdentifier {
111 $(
112 $prop = $val
113 ),+,
114 }
119
120 impl PropertyIdentifier {
121 pub fn new(prop: u32) -> PropertyIdentifier {
122 match prop {
123 $(
124 $val => PropertyIdentifier::$prop
125 ),+,
126 _ => todo!()
127 }
129 }
130 }
131 }
132}
133
134prop_ident_gen! {
135 #[derive(Debug, Clone, Copy, PartialEq)]
136 #[repr(u32)]
137 pub enum PropertyIdentifier {
138 PropEnd = 0,
139 PropColormap = 1,
140 PropActiveLayer = 2,
141 PropActiveChannel = 3,
142 PropSelection = 4,
143 PropFloatingSelection = 5,
144 PropOpacity = 6,
145 PropMode = 7,
146 PropVisible = 8,
147 PropLinked = 9,
148 PropLockAlpha = 10,
149 PropApplyMask = 11,
150 PropEditMask = 12,
151 PropShowMask = 13,
152 PropOffsets = 15,
153 PropCompression = 17,
154 TypeIdentification = 18,
155 PropResolution = 19,
156 PropTattoo = 20,
157 PropParasites = 21,
158 PropUnit = 22,
159 PropPaths = 23,
160 PropUserUnit = 24,
161 PropVectors = 25,
162 PropTextLayerFlags = 26,
163 PropOldSamplePoints = 27,
164 PropLockContent = 28,
165 PropLockPosition = 32,
166 PropFloatOpacity = 33,
167 PropColorTag = 34,
168 PropCompositeMode = 35,
169 PropCompositeSpace = 36,
170 PropBlendSpace = 37,
171 PropFloatColor = 38,
172 PropSamplePoints = 39,
173 PropItemSet = 40,
174 PropItemSetItem = 41,
175 PropLockVisibility = 42,
176 PropSelectedPath = 43,
177 PropFilterRegion = 44,
178 PropFilterArgument = 45,
179 PropFilterClip = 46,
180 }
181}