pcx/
reader.rs

1use byteorder::ReadBytesExt;
2use std::fs::File;
3use std::io;
4use std::path::Path;
5
6use crate::low_level::rle::Decompressor;
7use crate::low_level::{Header, PALETTE_START};
8use crate::user_error;
9
10#[derive(Clone, Debug)]
11enum PixelReader<R: io::Read> {
12    Compressed(Decompressor<R>),
13    NotCompressed(R),
14}
15
16impl<R: io::Read> io::Read for PixelReader<R> {
17    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
18        match *self {
19            PixelReader::Compressed(ref mut decompressor) => decompressor.read(buffer),
20            PixelReader::NotCompressed(ref mut stream) => stream.read(buffer),
21        }
22    }
23}
24
25/// PCX file reader.
26#[derive(Clone, Debug)]
27pub struct Reader<R: io::Read> {
28    /// File header. All useful values are available via `Reader` methods so you don't actually need it.
29    pub header: Header,
30
31    pixel_reader: PixelReader<R>,
32    num_lanes_read: u32,
33}
34
35impl Reader<io::BufReader<File>> {
36    /// Start reading PCX file.
37    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
38        let file = File::open(path)?;
39        Self::new(io::BufReader::new(file))
40    }
41}
42
43impl<'a> Reader<io::Cursor<&'a [u8]>> {
44    /// Start reading PCX file from memory buffer.
45    pub fn from_mem(data: &'a [u8]) -> io::Result<Self> {
46        Self::new(io::Cursor::new(data))
47    }
48}
49
50impl<R: io::Read> Reader<R> {
51    /// Start reading PCX file.
52    pub fn new(mut stream: R) -> io::Result<Self> {
53        let header = Header::load(&mut stream)?;
54        let pixel_reader = if header.is_compressed {
55            PixelReader::Compressed(Decompressor::new(stream))
56        } else {
57            PixelReader::NotCompressed(stream)
58        };
59
60        Ok(Reader {
61            header,
62            pixel_reader,
63            num_lanes_read: 0,
64        })
65    }
66
67    /// Get width and height of the image.
68    #[inline]
69    pub fn dimensions(&self) -> (u16, u16) {
70        self.header.size
71    }
72
73    /// The width of this image.
74    #[inline]
75    pub fn width(&self) -> u16 {
76        self.header.size.0
77    }
78
79    /// The height of this image.
80    #[inline]
81    pub fn height(&self) -> u16 {
82        self.header.size.1
83    }
84
85    /// Whether this image is paletted or 24-bit RGB.
86    #[inline]
87    pub fn is_paletted(&self) -> bool {
88        self.header.palette_length().is_some()
89    }
90
91    /// Get number of colors in the palette if this image is paletted. Number of colors is either 2, 4, 8, 16 or 256.
92    #[inline]
93    pub fn palette_length(&self) -> Option<u16> {
94        self.header.palette_length()
95    }
96
97    /// Read next row of the paletted image.  Check that `is_paletted()` is `true` before calling this function.
98    ///
99    /// `buffer` length must be equal to the image width.
100    ///
101    /// Order of rows is from top to bottom, order of pixels is from left to right.
102    pub fn next_row_paletted(&mut self, buffer: &mut [u8]) -> io::Result<()> {
103        if !self.is_paletted() {
104            return user_error("pcx::Reader::next_row_paletted called on non-paletted image");
105        }
106
107        if self.palette_length() == Some(256) {
108            self.next_lane(buffer)?;
109        } else if self.header.number_of_color_planes == 1 {
110            // All packed formats, max. 16 colors.
111            let width = self.width() as usize;
112            let lane_length = self.header.lane_proper_length() as usize;
113            let buffer_len = buffer.len();
114            let offset = buffer.len() - lane_length;
115
116            // Place packed row at the end of buffer, this will allow us to easily unpack it.
117            self.next_lane(&mut buffer[offset..buffer_len])?;
118
119            macro_rules! unpack_bits {
120                ($bits:expr) => {{
121                    let n = 8 / $bits;
122
123                    for i in 0..(width * $bits) / 8 {
124                        for j in 0..n {
125                            buffer[i * n + j] = (buffer[offset + i]
126                                & (((1 << $bits) - 1) << (8 - $bits * (j + 1))))
127                                >> (8 - $bits * (j + 1));
128                        }
129                    }
130
131                    let i = (width * $bits) / 8;
132                    for j in 0..width - i * n {
133                        buffer[i * n + j] = (buffer[offset + i]
134                            & (((1 << $bits) - 1) << (8 - $bits * (j + 1))))
135                            >> (8 - $bits * (j + 1));
136                    }
137                }};
138            }
139
140            // Unpack packed bits into bytes.
141            match self.header.bit_depth {
142                1 => unpack_bits!(1),
143                2 => unpack_bits!(2),
144                4 => unpack_bits!(4),
145                _ => unreachable!(), // bit depth was checked while reading the header
146            }
147        } else {
148            // Planar, 4, 8 or 16 colors.
149            let lane_length = self.header.lane_proper_length() as usize;
150            let number_of_color_planes = self.header.number_of_color_planes as usize;
151            let half_len = buffer.len() / 2;
152
153            // Place packed rows at the first half of the buffer, this will allow us to easily unpack them.
154            for i in 0..number_of_color_planes {
155                self.next_lane(&mut buffer[(lane_length * i)..(lane_length * (i + 1))])?;
156            }
157
158            for x in 0..self.width() {
159                let m = 0x80 >> (x & 7);
160                let mut v = 0;
161                for i in (0..number_of_color_planes).rev() {
162                    v <<= 1;
163                    v += if buffer[i * lane_length + (x as usize >> 3)] & m != 0 {
164                        1
165                    } else {
166                        0
167                    };
168                }
169                if x % 2 == 0 {
170                    buffer[half_len + (x / 2) as usize] = v << 4;
171                } else {
172                    buffer[half_len + (x / 2) as usize] |= v;
173                }
174            }
175
176            for i in 0..half_len {
177                buffer[i * 2] = (buffer[half_len + i] & 0xF0) >> 4;
178                buffer[i * 2 + 1] = buffer[half_len + i] & 0xF;
179            }
180        }
181
182        Ok(())
183    }
184
185    /// Read next row of the RGB image to separate R, G and B buffers. Check that `is_paletted()` is `false` before calling this function.
186    ///
187    /// `r`, `g`, `b` buffer lengths must be equal to the image width.
188    ///
189    /// Order of rows is from top to bottom, order of pixels is from left to right.
190    pub fn next_row_rgb_separate(
191        &mut self,
192        r: &mut [u8],
193        g: &mut [u8],
194        b: &mut [u8],
195    ) -> io::Result<()> {
196        if self.is_paletted() {
197            return user_error("pcx::Reader::next_row_rgb_separate called on paletted image");
198        }
199
200        // API for reading lanes is not exposed so users have no way of messing that up.
201        assert_eq!(self.num_lanes_read % 3, 0);
202
203        self.next_lane(r)?;
204        self.next_lane(g)?;
205        self.next_lane(b)
206    }
207
208    /// Read next row of the RGB image to one buffer with interleaved RGB values. Check that `is_paletted()` is `false` before calling this function.
209    ///
210    /// `rgb` buffer length must be equal to the image width multiplied by 3.
211    ///
212    /// Order of rows is from top to bottom, order of pixels is from left to right.
213    pub fn next_row_rgb(&mut self, rgb: &mut [u8]) -> io::Result<()> {
214        if self.is_paletted() {
215            return user_error("pcx::Reader::next_row_rgb called on paletted image");
216        }
217
218        // API for reading lanes is not exposed so users have no way of messing that up.
219        assert_eq!(self.num_lanes_read % 3, 0);
220
221        if rgb.len() != (self.width() as usize) * 3 {
222            return user_error("pcx::Reader::next_row_rgb: buffer length must be equal to the width of the image multiplied by 3");
223        }
224
225        for color in 0..3 {
226            for x in 0..(self.width() as usize) {
227                rgb[x * 3 + color] = self.pixel_reader.read_u8()?;
228            }
229            self.skip_padding()?;
230        }
231
232        Ok(())
233    }
234
235    fn skip_padding(&mut self) -> io::Result<()> {
236        if self.num_lanes_read + 1
237            < u32::from(self.height()) * u32::from(self.header.number_of_color_planes)
238        {
239            // Skip padding.
240            for _ in 0..self.header.lane_padding() {
241                self.pixel_reader.read_u8()?;
242            }
243        }
244
245        self.num_lanes_read += 1;
246        Ok(())
247    }
248
249    // Read next lane. Format is dependent on file format. Buffer length must be equal to `Header::lane_proper_length()`.
250    //
251    // Order of lanes is from top to bottom.
252    fn next_lane(&mut self, buffer: &mut [u8]) -> io::Result<()> {
253        use std::io::Read;
254
255        if buffer.len() != self.header.lane_proper_length() as usize {
256            return user_error("pcx::Reader::next_lane: incorrect buffer size.");
257        }
258
259        self.pixel_reader.read_exact(buffer)?;
260        self.skip_padding()
261    }
262
263    /// Read color palette.
264    ///
265    /// If palette contains 256-colors then it is stored at the end of file and this function will read the file to the end.
266    ///
267    /// Returns number of colors in palette or zero if there is no palette. The actual number of bytes written to the output buffer is
268    /// equal to the returned value multiplied by 3. Format of the output buffer is R, G, B, R, G, B, ...
269    ///
270    /// Consider using `get_palette` instead.
271    pub fn read_palette(self, buffer: &mut [u8]) -> io::Result<usize> {
272        if let Some(palette_size) = self.get_small_palette(buffer) {
273            return Ok(palette_size);
274        }
275
276        // Stop decompressing and continue reading underlying stream.
277        let mut stream = match self.pixel_reader {
278            PixelReader::Compressed(decompressor) => decompressor.finish(),
279            PixelReader::NotCompressed(stream) => stream,
280        };
281
282        // 256-color palette is located at the end of file. To avoid seeking we are using a bit convoluted method here to read it.
283        const PALETTE_LENGTH: usize = 256 * 3;
284        const TEMP_BUFFER_LENGTH: usize = PALETTE_LENGTH + 1;
285
286        let mut temp_buffer = [0; TEMP_BUFFER_LENGTH];
287        let mut pos = 0;
288
289        loop {
290            let read = stream.read(&mut temp_buffer[pos..TEMP_BUFFER_LENGTH])?;
291            if read != 0 {
292                pos = (pos + read) % TEMP_BUFFER_LENGTH;
293            } else {
294                // We've reached the end of file, therefore temp_buffer must now contain the palette.
295                if temp_buffer[pos] != PALETTE_START {
296                    return Err(io::Error::new(
297                        io::ErrorKind::InvalidData,
298                        "no 256-color palette",
299                    ));
300                }
301
302                buffer[0..(TEMP_BUFFER_LENGTH - pos - 1)]
303                    .copy_from_slice(&temp_buffer[(pos + 1)..TEMP_BUFFER_LENGTH]);
304                buffer[(TEMP_BUFFER_LENGTH - pos - 1)..PALETTE_LENGTH]
305                    .copy_from_slice(&temp_buffer[0..pos]);
306
307                return Ok(256);
308            }
309        }
310    }
311
312    fn get_small_palette(&self, buffer: &mut [u8]) -> Option<usize> {
313        match self.header.palette_length() {
314            Some(2) => {
315                // Special case - monochrome image.
316
317                // Black.
318                buffer[0] = 0;
319                buffer[1] = 0;
320                buffer[2] = 0;
321
322                // White.
323                buffer[3] = 255;
324                buffer[4] = 255;
325                buffer[5] = 255;
326
327                return Some(2 as usize);
328            }
329            Some(palette_length @ 1..=16) => {
330                // Palettes of 16 colors or smaller are stored in the header.
331                for i in 0..(palette_length as usize) {
332                    (&mut buffer[(i * 3)..((i + 1) * 3)]).copy_from_slice(&self.header.palette[i]);
333                }
334                return Some(palette_length as usize);
335            }
336            Some(256) => {
337                // 256-color palette is located at the end of file.
338                None
339            }
340            _ => return Some(0),
341        }
342    }
343}
344
345impl<R: io::Seek + io::Read> Reader<R> {
346    /// Read the entire RGB image, converting from paletted to RGB if necessarry.
347    ///
348    /// `rgb` buffer length must be equal to `width*height*3`.
349    ///
350    /// Order of rows is from top to bottom, order of pixels is from left to right. Format of the
351    /// output buffer is R, G, B, R, G, B, ...
352    pub fn read_rgb_pixels(&mut self, rgb: &mut [u8]) -> io::Result<()> {
353        let width = self.width() as usize;
354        let height = self.height() as usize;
355        let row_size = width * 3;
356
357        if self.is_paletted() {
358            let mut palette = [0; 256 * 3];
359            self.get_palette(&mut palette)?;
360
361            for y in 0..height {
362                match self.next_row_paletted(&mut rgb[y * row_size..(y * row_size + width)]) {
363                    // parse some weird images that appear in the wild
364                    Err(error) if error.kind() == io::ErrorKind::UnexpectedEof => {}
365                    Err(error) => {
366                        return Err(error);
367                    }
368                    _ => {}
369                }
370
371                for x in (0..width).rev() {
372                    let color_index = rgb[y * row_size + x] as usize;
373                    rgb[y * row_size + x * 3 + 0] = palette[color_index * 3 + 0];
374                    rgb[y * row_size + x * 3 + 1] = palette[color_index * 3 + 1];
375                    rgb[y * row_size + x * 3 + 2] = palette[color_index * 3 + 2];
376                }
377            }
378        } else {
379            for y in 0..height {
380                self.next_row_rgb(&mut rgb[y * row_size..(y + 1) * row_size])?;
381            }
382        }
383
384        Ok(())
385    }
386
387    /// Get color palette.
388    ///
389    /// Returns number of colors in palette or zero if there is no palette. The actual number of bytes written to the output buffer is
390    /// equal to the returned value multiplied by 3. Format of the output buffer is R, G, B, R, G, B, ...
391    pub fn get_palette(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
392        if let Some(palette_size) = self.get_small_palette(buffer) {
393            return Ok(palette_size);
394        }
395
396        let stream = match &mut self.pixel_reader {
397            PixelReader::Compressed(decompressor) => &mut decompressor.stream,
398            PixelReader::NotCompressed(stream) => stream,
399        };
400
401        let original_pos = stream.stream_position()?;
402
403        stream.seek(io::SeekFrom::End(-256 * 3 - 1))?;
404        let result = Self::get_palette_impl(stream, buffer);
405        stream.seek(io::SeekFrom::Start(original_pos))?;
406        result?;
407
408        Ok(256)
409    }
410
411    fn get_palette_impl(stream: &mut R, buffer: &mut [u8]) -> io::Result<()> {
412        let mut magic = [0];
413        stream.read_exact(&mut magic)?;
414        if magic[0] != PALETTE_START {
415            return Err(io::Error::new(
416                io::ErrorKind::InvalidData,
417                "no 256-color palette",
418            ));
419        }
420
421        stream.read_exact(&mut buffer[0..256 * 3])
422    }
423}
424
425#[cfg(test)]
426mod tests {
427    use std::iter;
428
429    use super::Reader;
430    use crate::low_level::header;
431
432    #[test]
433    fn gmarbles() {
434        let data = include_bytes!("../test-data/gmarbles.pcx");
435        let read = &mut &data[..];
436        let mut reader = Reader::new(read).unwrap();
437
438        assert_eq!(reader.header.version, header::Version::V5);
439        assert_eq!(reader.header.is_compressed, true);
440        assert_eq!(reader.header.bit_depth, 8);
441        assert_eq!(reader.header.size, (141, 99));
442        assert_eq!(reader.header.start, (0, 0));
443        assert_eq!(reader.header.dpi, (300, 300));
444        assert_eq!(reader.header.number_of_color_planes, 1);
445        assert_eq!(reader.header.lane_length, 142);
446
447        assert!(reader.is_paletted());
448        assert_eq!(reader.palette_length(), Some(256));
449
450        let mut row: Vec<u8> = iter::repeat(0).take(reader.width() as usize).collect();
451        for _ in 0..reader.height() {
452            reader.next_row_paletted(&mut row[..]).unwrap();
453        }
454
455        let mut palette = [0; 256 * 3];
456        assert_eq!(reader.read_palette(&mut palette).unwrap(), 256);
457    }
458
459    #[test]
460    fn marbles() {
461        let data = include_bytes!("../test-data/marbles.pcx");
462        let read = &mut &data[..];
463        let mut reader = Reader::new(read).unwrap();
464
465        assert_eq!(reader.header.version, header::Version::V5);
466        assert!(reader.header.is_compressed);
467        assert_eq!(reader.header.bit_depth, 8);
468        assert_eq!(reader.header.size, (143, 101));
469        assert_eq!(reader.header.start, (0, 0));
470        assert_eq!(reader.header.dpi, (300, 300));
471        assert_eq!(reader.header.number_of_color_planes, 3);
472        assert_eq!(reader.header.lane_length, 144);
473
474        assert_eq!(reader.is_paletted(), false);
475
476        let mut r: Vec<u8> = iter::repeat(0).take(reader.width() as usize).collect();
477        let mut g: Vec<u8> = iter::repeat(0).take(reader.width() as usize).collect();
478        let mut b: Vec<u8> = iter::repeat(0).take(reader.width() as usize).collect();
479        for _ in 0..reader.height() {
480            reader
481                .next_row_rgb_separate(&mut r[..], &mut g[..], &mut b[..])
482                .unwrap();
483        }
484
485        let mut palette = [0; 0];
486        assert_eq!(reader.read_palette(&mut palette).unwrap(), 0);
487    }
488}