xcf_rs/
lib.rs

1//! Read pixel data from GIMP's native XCF files.
2//!
3//! See [`Xcf`] for usage (methods `open` and `load`). For extracting pixel data, you probably want
4//! to access a layer via `Xcf::layer` and `Layer::raw_sub_buffer`, which you can use to
5//! create `ImageBuffer`s from the `image` crate. You can also do direct pixel access via
6//! `Layer::pixel`.
7//!
8//! [`Xcf`]: struct.Xcf.html
9
10#[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        // TODO
117        // let mptr = rdr.read_uint::<BigEndian>(version.bytes_per_offset())?;
118        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
201// TODO: I like the use of a struct but this isn't really any kind of cursor.
202// The use of a struct allows us to seperate the state we need to refer to from the number of
203// stuff we need to store within the "algorithm." A better design is very welcome! i should be
204// moved into feed as a local.
205impl 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    /// Feed the cursor a stream starting at the beginning of an XCF tile structure.
218    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        // each channel is laid out one after the other
223        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                    // A short run of identical bytes
229                    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                    // A long run of identical bytes
238                    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                    // A long run of different bytes
247                    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                    // A short run of different bytes
256                    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    // read the DUMB trailing null byte... uhh GIMP team RIIR already? ;p
278    rdr.read_exact(&mut [0u8])?;
279    Ok(String::from_utf8(buffer)?)
280}
281
282/// A GIMP XCF file.
283///
284/// If you need to access multiple layers at once, access layers field and use `split_at`.
285impl Xcf {
286    /// Open an XCF file at the path specified.
287    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    /// Read an XCF file from a Reader.
293    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        // TODO: Read channels
309
310        Ok(Xcf { header, layers })
311    }
312
313    /// Get the width of the canvas.
314    pub fn width(&self) -> u32 {
315        self.header.width
316    }
317
318    /// Get the height of the canvas.
319    pub fn height(&self) -> u32 {
320        self.header.height
321    }
322
323    // Get the dimensions (width, height) of the canvas.
324    pub fn dimensions(&self) -> (u32, u32) {
325        (self.width(), self.height())
326    }
327
328    /// Get a reference to a layer by `name`.
329    pub fn layer(&self, name: &str) -> Option<&Layer> {
330        self.layers.iter().find(|l| l.name == name)
331    }
332
333    /// Get a mutable reference to a layer by `name`.
334    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        /*if version.num() > 11 {
349            return Err(Error::UnknownVersion);
350        }*/
351
352        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        /*
360        if color_type != ColorType::Rgb {
361            unimplemented!("Only RGB/RGBA color images supported");
362        }
363        */
364
365        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}