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#[derive(Clone, Debug)]
27pub struct Reader<R: io::Read> {
28 pub header: Header,
30
31 pixel_reader: PixelReader<R>,
32 num_lanes_read: u32,
33}
34
35impl Reader<io::BufReader<File>> {
36 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 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 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 #[inline]
69 pub fn dimensions(&self) -> (u16, u16) {
70 self.header.size
71 }
72
73 #[inline]
75 pub fn width(&self) -> u16 {
76 self.header.size.0
77 }
78
79 #[inline]
81 pub fn height(&self) -> u16 {
82 self.header.size.1
83 }
84
85 #[inline]
87 pub fn is_paletted(&self) -> bool {
88 self.header.palette_length().is_some()
89 }
90
91 #[inline]
93 pub fn palette_length(&self) -> Option<u16> {
94 self.header.palette_length()
95 }
96
97 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 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 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 match self.header.bit_depth {
142 1 => unpack_bits!(1),
143 2 => unpack_bits!(2),
144 4 => unpack_bits!(4),
145 _ => unreachable!(), }
147 } else {
148 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 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 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 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 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 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 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 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 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 let mut stream = match self.pixel_reader {
278 PixelReader::Compressed(decompressor) => decompressor.finish(),
279 PixelReader::NotCompressed(stream) => stream,
280 };
281
282 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 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 buffer[0] = 0;
319 buffer[1] = 0;
320 buffer[2] = 0;
321
322 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 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 None
339 }
340 _ => return Some(0),
341 }
342 }
343}
344
345impl<R: io::Seek + io::Read> Reader<R> {
346 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 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 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}