1#[macro_use]
11extern crate derive_error;
12extern crate byteorder;
13
14use std::io::{Read, Seek, SeekFrom};
15
16use byteorder::{BigEndian, ReadBytesExt};
17use std::borrow::Cow;
18use std::cmp;
19use std::fs::File;
20use std::io::BufReader;
21use std::path::Path;
22
23pub mod create;
24pub mod data;
25pub mod parser;
26
27use crate::data::{
28 color::ColorType, error::Error, header::XcfHeader, layer::Layer, pixeldata::PixelData,
29 precision::Precision, property::PropertyPayload, rgba::RgbaPixel, version::Version, xcf::Xcf,
30};
31use crate::parser::ParseVersion;
32
33use crate::data::property::{Property, PropertyIdentifier};
34
35impl Precision {
36 fn parse<R: Read>(mut rdr: R, version: Version) -> Result<Self, Error> {
37 let precision = rdr.read_u32::<BigEndian>()?;
38 Ok(match version.num() {
39 4 => match precision {
40 0 => Precision::NonLinearU8,
41 1 => Precision::NonLinearU16,
42 2 => Precision::LinearU32,
43 3 => Precision::LinearF16,
44 4 => Precision::LinearF32,
45 _ => return Err(Error::InvalidPrecision),
46 },
47 5..=6 => match precision {
48 100 => Precision::LinearU8,
49 150 => Precision::NonLinearU8,
50 200 => Precision::LinearU16,
51 250 => Precision::NonLinearU16,
52 300 => Precision::LinearU32,
53 350 => Precision::NonLinearU32,
54 400 => Precision::LinearF16,
55 450 => Precision::NonLinearF16,
56 500 => Precision::LinearF32,
57 550 => Precision::NonLinearF32,
58 _ => return Err(Error::InvalidPrecision),
59 },
60 7.. => match precision {
61 100 => Precision::LinearU8,
62 150 => Precision::NonLinearU8,
63 175 => Precision::PerceptualU8,
64 200 => Precision::LinearU16,
65 250 => Precision::NonLinearU16,
66 275 => Precision::PerceptualU16,
67 300 => Precision::LinearU32,
68 350 => Precision::NonLinearU32,
69 375 => Precision::PerceptualU32,
70 500 => Precision::LinearF16,
71 550 => Precision::NonLinearF16,
72 575 => Precision::PerceptualF16,
73 600 => Precision::LinearF32,
74 650 => Precision::NonLinearF32,
75 675 => Precision::PerceptualF32,
76 700 => Precision::LinearF64,
77 750 => Precision::NonLinearF64,
78 775 => Precision::PerceptualF64,
79 _ => return Err(Error::InvalidPrecision),
80 },
81 _ => return Err(Error::InvalidPrecision),
82 })
83 }
84}
85
86impl PropertyPayload {
87 fn parse<R: Read>(
88 mut rdr: R,
89 kind: PropertyIdentifier,
90 length: usize,
91 ) -> Result<PropertyPayload, Error> {
92 use self::PropertyIdentifier::*;
93 Ok(match kind {
94 PropEnd => PropertyPayload::End,
95 _ => {
96 let mut p = vec![0; length];
97 rdr.read_exact(&mut p)?;
98 PropertyPayload::Unknown(p)
99 }
100 })
101 }
102}
103
104impl Layer {
105 fn parse<R: Read + Seek>(mut rdr: R, version: Version) -> Result<Layer, Error> {
106 let width = rdr.read_u32::<BigEndian>()?;
107 let height = rdr.read_u32::<BigEndian>()?;
108 let kind = LayerColorType::new(rdr.read_u32::<BigEndian>()?)?;
109 let name = read_gimp_string(&mut rdr)?;
110 let properties = Property::parse_list(&mut rdr)?;
111 let hptr = rdr.read_uint::<BigEndian>(version.bytes_per_offset())?;
112 let current_pos = rdr.stream_position()?;
113 rdr.seek(SeekFrom::Start(hptr))?;
114 let pixels = PixelData::parse_hierarchy(&mut rdr, version)?;
115 rdr.seek(SeekFrom::Start(current_pos))?;
116 Ok(Layer {
119 width,
120 height,
121 kind,
122 name,
123 properties,
124 pixels,
125 })
126 }
127
128 pub fn pixel(&self, x: u32, y: u32) -> Option<RgbaPixel> {
129 self.pixels.pixel(x, y)
130 }
131
132 pub fn dimensions(&self) -> (u32, u32) {
133 (self.width, self.height)
134 }
135
136 pub fn raw_rgba_buffer(&self) -> Cow<[RgbaPixel]> {
137 Cow::from(&self.pixels.pixels)
138 }
139
140 pub fn raw_sub_rgba_buffer(&self, x: u32, y: u32, width: u32, height: u32) -> Vec<u8> {
141 self.pixels.raw_sub_rgba_buffer(x, y, width, height)
142 }
143}
144
145#[repr(u32)]
146#[derive(Debug, PartialEq, Clone)]
147pub enum LayerColorValue {
148 Rgb = 0,
149 Rgba = 1,
150 Grayscale = 2,
151 GrayscaleWithAlpha = 3,
152 Indexed = 4,
153 IndexedWithAlpha = 5
154}
155
156impl LayerColorValue {
157 pub(crate) fn new(kind: u32) -> Result<LayerColorValue, Error> {
158 use self::LayerColorValue::*;
159 Ok(match kind {
160 0 => Rgb,
161 1 => Rgba,
162 2 => Grayscale,
163 3 => GrayscaleWithAlpha,
164 4 => Indexed,
165 5 => Self::IndexedWithAlpha,
166 _ => return Err(Error::InvalidFormat),
167 })
168 }
169
170 pub(crate) fn has_alpha(value: LayerColorValue) -> bool {
171 match value {
172 LayerColorValue::Rgba | LayerColorValue::GrayscaleWithAlpha | LayerColorValue::IndexedWithAlpha => true,
173 LayerColorValue::Rgb | LayerColorValue::Grayscale | LayerColorValue::Indexed => false
174 }
175 }
176}
177
178#[derive(Debug, PartialEq)]
179pub struct LayerColorType {
180 pub kind: LayerColorValue,
181 pub alpha: bool,
182}
183
184impl LayerColorType {
185 fn new(identifier: u32) -> Result<LayerColorType, Error> {
186 let kind = LayerColorValue::new(identifier / 2)?;
187 let alpha = identifier % 2 == 1;
188 Ok(LayerColorType { alpha, kind })
189 }
190}
191
192pub struct TileCursor {
193 width: u32,
194 height: u32,
195 channels: u32,
196 x: u32,
197 y: u32,
198 i: u32,
199}
200
201impl TileCursor {
206 fn new(width: u32, height: u32, tx: u32, ty: u32, channels: u32) -> TileCursor {
207 TileCursor {
208 width,
209 height,
210 channels,
211 x: tx * 64,
212 y: ty * 64,
213 i: 0,
214 }
215 }
216
217 fn feed<R: Read>(&mut self, mut rdr: R, pixels: &mut [RgbaPixel]) -> Result<(), Error> {
219 let twidth = cmp::min(self.x + 64, self.width) - self.x;
220 let theight = cmp::min(self.y + 64, self.height) - self.y;
221 let base_offset = self.y * self.width + self.x;
222 let mut channel = 0;
224 while channel < self.channels {
225 while self.i < twidth * theight {
226 let determinant = rdr.read_u8()?;
227 if determinant < 127 {
228 let run = u32::from(determinant + 1);
230 let v = rdr.read_u8()?;
231 for i in (self.i)..(self.i + run) {
232 let index = base_offset + (i / twidth) * self.width + i % twidth;
233 pixels[index as usize].0[channel as usize] = v;
234 }
235 self.i += run;
236 } else if determinant == 127 {
237 let run = u32::from(rdr.read_u16::<BigEndian>()?);
239 let v = rdr.read_u8()?;
240 for i in (self.i)..(self.i + run) {
241 let index = base_offset + (i / twidth) * self.width + i % twidth;
242 pixels[index as usize].0[channel as usize] = v;
243 }
244 self.i += run;
245 } else if determinant == 128 {
246 let stream_run = u32::from(rdr.read_u16::<BigEndian>()?);
248 for i in (self.i)..(self.i + stream_run) {
249 let index = base_offset + (i / twidth) * self.width + i % twidth;
250 let v = rdr.read_u8()?;
251 pixels[index as usize].0[channel as usize] = v;
252 }
253 self.i += stream_run;
254 } else {
255 let stream_run = 256 - u32::from(determinant);
257 for i in (self.i)..(self.i + stream_run) {
258 let index = base_offset + (i / twidth) * self.width + i % twidth;
259 let v = rdr.read_u8()?;
260 pixels[index as usize].0[channel as usize] = v;
261 }
262 self.i += stream_run;
263 }
264 }
265
266 self.i = 0;
267 channel += 1;
268 }
269 Ok(())
270 }
271}
272
273fn read_gimp_string<R: Read>(mut rdr: R) -> Result<String, Error> {
274 let length = rdr.read_u32::<BigEndian>()?;
275 let mut buffer = vec![0; length as usize - 1];
276 rdr.read_exact(&mut buffer)?;
277 rdr.read_exact(&mut [0u8])?;
279 Ok(String::from_utf8(buffer)?)
280}
281
282impl Xcf {
286 pub fn open<P: AsRef<Path>>(p: P) -> Result<Xcf, Error> {
288 let rdr = BufReader::new(File::open(p)?);
289 Xcf::load(rdr)
290 }
291
292 pub fn load<R: Read + Seek>(mut rdr: R) -> Result<Xcf, Error> {
294 let header = XcfHeader::parse(&mut rdr)?;
295
296 let mut layers = Vec::new();
297 loop {
298 let layer_pointer = rdr.read_uint::<BigEndian>(header.version.bytes_per_offset())?;
299 if layer_pointer == 0 {
300 break;
301 }
302 let current_pos = rdr.stream_position()?;
303 rdr.seek(SeekFrom::Start(layer_pointer))?;
304 layers.push(Layer::parse(&mut rdr, header.version)?);
305 rdr.seek(SeekFrom::Start(current_pos))?;
306 }
307
308 Ok(Xcf { header, layers })
311 }
312
313 pub fn width(&self) -> u32 {
315 self.header.width
316 }
317
318 pub fn height(&self) -> u32 {
320 self.header.height
321 }
322
323 pub fn dimensions(&self) -> (u32, u32) {
325 (self.width(), self.height())
326 }
327
328 pub fn layer(&self, name: &str) -> Option<&Layer> {
330 self.layers.iter().find(|l| l.name == name)
331 }
332
333 pub fn layer_mut(&mut self, name: &str) -> Option<&mut Layer> {
335 self.layers.iter_mut().find(|l| l.name == name)
336 }
337}
338
339impl XcfHeader {
340 fn parse<R: Read>(mut rdr: R) -> Result<XcfHeader, Error> {
341 let mut magic = [0u8; 9];
342 rdr.read_exact(&mut magic)?;
343 if magic != *b"gimp xcf " {
344 return Err(Error::InvalidFormat);
345 }
346
347 let version = Version::parse(&mut rdr)?;
348 rdr.read_exact(&mut [0u8])?;
353
354 let width = rdr.read_u32::<BigEndian>()?;
355 let height = rdr.read_u32::<BigEndian>()?;
356
357 let color_type = ColorType::new(rdr.read_u32::<BigEndian>()?)?;
358
359 let precision = if version.num() >= 4 {
366 Precision::parse(&mut rdr, version)?
367 } else {
368 Precision::NonLinearU8
369 };
370
371 let properties = Property::parse_list(&mut rdr)?;
372
373 Ok(XcfHeader {
374 version,
375 width,
376 height,
377 color_type,
378 precision,
379 properties,
380 })
381 }
382}