1 extern crate crc32fast;
2 extern crate deflate;
3
4 use std::borrow::Cow;
5 use std::error;
6 use std::fmt;
7 use std::io::{self, Read, Write};
8 use std::mem;
9 use std::result;
10
11 use crc32fast::Hasher as Crc32;
12
13 use crate::chunk;
14 use crate::common::{BitDepth, BytesPerPixel, ColorType, Compression, Info};
15 use crate::filter::{filter, FilterType};
16 use crate::traits::WriteBytesExt;
17
18 pub type Result<T> = result::Result<T, EncodingError>;
19
20 #[derive(Debug)]
21 pub enum EncodingError {
22 IoError(io::Error),
23 Format(Cow<'static, str>),
24 }
25
26 impl error::Error for EncodingError {
cause(&self) -> Option<&(dyn error::Error + 'static)>27 fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
28 match self {
29 EncodingError::IoError(err) => Some(err),
30 _ => None,
31 }
32 }
33 }
34
35 impl fmt::Display for EncodingError {
fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error>36 fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
37 use self::EncodingError::*;
38 match self {
39 IoError(err) => write!(fmt, "{}", err),
40 Format(desc) => write!(fmt, "{}", desc),
41 }
42 }
43 }
44
45 impl From<io::Error> for EncodingError {
from(err: io::Error) -> EncodingError46 fn from(err: io::Error) -> EncodingError {
47 EncodingError::IoError(err)
48 }
49 }
50 impl From<EncodingError> for io::Error {
from(err: EncodingError) -> io::Error51 fn from(err: EncodingError) -> io::Error {
52 io::Error::new(io::ErrorKind::Other, err.to_string())
53 }
54 }
55
56 /// PNG Encoder
57 pub struct Encoder<W: Write> {
58 w: W,
59 info: Info,
60 }
61
62 impl<W: Write> Encoder<W> {
new(w: W, width: u32, height: u32) -> Encoder<W>63 pub fn new(w: W, width: u32, height: u32) -> Encoder<W> {
64 let mut info = Info::default();
65 info.width = width;
66 info.height = height;
67 Encoder { w, info }
68 }
69
set_palette(&mut self, palette: Vec<u8>)70 pub fn set_palette(&mut self, palette: Vec<u8>) {
71 self.info.palette = Some(palette);
72 }
73
set_trns(&mut self, trns: Vec<u8>)74 pub fn set_trns(&mut self, trns: Vec<u8>) {
75 self.info.trns = Some(trns);
76 }
77
write_header(self) -> Result<Writer<W>>78 pub fn write_header(self) -> Result<Writer<W>> {
79 Writer::new(self.w, self.info).init()
80 }
81
82 /// Set the color of the encoded image.
83 ///
84 /// These correspond to the color types in the png IHDR data that will be written. The length
85 /// of the image data that is later supplied must match the color type, otherwise an error will
86 /// be emitted.
set_color(&mut self, color: ColorType)87 pub fn set_color(&mut self, color: ColorType) {
88 self.info.color_type = color;
89 }
90
91 /// Set the indicated depth of the image data.
set_depth(&mut self, depth: BitDepth)92 pub fn set_depth(&mut self, depth: BitDepth) {
93 self.info.bit_depth = depth;
94 }
95
96 /// Set compression parameters.
97 ///
98 /// Accepts a `Compression` or any type that can transform into a `Compression`. Notably `deflate::Compression` and
99 /// `deflate::CompressionOptions` which "just work".
set_compression<C: Into<Compression>>(&mut self, compression: C)100 pub fn set_compression<C: Into<Compression>>(&mut self, compression: C) {
101 self.info.compression = compression.into();
102 }
103
104 /// Set the used filter type.
105 ///
106 /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
107 /// sample values based on the previous. For a potentially better compression ratio, at the
108 /// cost of more complex processing, try out [`FilterType::Paeth`].
109 ///
110 /// [`FilterType::Sub`]: enum.FilterType.html#variant.Sub
111 /// [`FilterType::Paeth`]: enum.FilterType.html#variant.Paeth
set_filter(&mut self, filter: FilterType)112 pub fn set_filter(&mut self, filter: FilterType) {
113 self.info.filter = filter;
114 }
115 }
116
117 /// PNG writer
118 pub struct Writer<W: Write> {
119 w: W,
120 info: Info,
121 }
122
123 const DEFAULT_BUFFER_LENGTH: usize = 4 * 1024;
124
write_chunk<W: Write>(mut w: W, name: [u8; 4], data: &[u8]) -> Result<()>125 fn write_chunk<W: Write>(mut w: W, name: [u8; 4], data: &[u8]) -> Result<()> {
126 w.write_be(data.len() as u32)?;
127 w.write_all(&name)?;
128 w.write_all(data)?;
129 let mut crc = Crc32::new();
130 crc.update(&name);
131 crc.update(data);
132 w.write_be(crc.finalize())?;
133 Ok(())
134 }
135
136 impl<W: Write> Writer<W> {
new(w: W, info: Info) -> Writer<W>137 fn new(w: W, info: Info) -> Writer<W> {
138 Writer { w, info }
139 }
140
init(mut self) -> Result<Self>141 fn init(mut self) -> Result<Self> {
142 if self.info.width == 0 {
143 return Err(EncodingError::Format("Zero width not allowed".into()));
144 }
145
146 if self.info.height == 0 {
147 return Err(EncodingError::Format("Zero height not allowed".into()));
148 }
149
150 // TODO: this could yield the typified BytesPerPixel.
151 if self
152 .info
153 .color_type
154 .is_combination_invalid(self.info.bit_depth)
155 {
156 return Err(EncodingError::Format(
157 format!(
158 "Invalid combination of bit-depth '{:?}' and color-type '{:?}'",
159 self.info.bit_depth, self.info.color_type
160 )
161 .into(),
162 ));
163 }
164
165 self.w.write_all(&[137, 80, 78, 71, 13, 10, 26, 10])?;
166 let mut data = [0; 13];
167 (&mut data[..]).write_be(self.info.width)?;
168 (&mut data[4..]).write_be(self.info.height)?;
169 data[8] = self.info.bit_depth as u8;
170 data[9] = self.info.color_type as u8;
171 data[12] = if self.info.interlaced { 1 } else { 0 };
172 self.write_chunk(chunk::IHDR, &data)?;
173
174 if let Some(p) = &self.info.palette {
175 write_chunk(&mut self.w, chunk::PLTE, p)?;
176 };
177
178 if let Some(t) = &self.info.trns {
179 write_chunk(&mut self.w, chunk::tRNS, t)?;
180 }
181
182 Ok(self)
183 }
184
write_chunk(&mut self, name: [u8; 4], data: &[u8]) -> Result<()>185 pub fn write_chunk(&mut self, name: [u8; 4], data: &[u8]) -> Result<()> {
186 write_chunk(&mut self.w, name, data)
187 }
188
189 /// Writes the image data.
write_image_data(&mut self, data: &[u8]) -> Result<()>190 pub fn write_image_data(&mut self, data: &[u8]) -> Result<()> {
191 const MAX_CHUNK_LEN: u32 = (1u32 << 31) - 1;
192
193 if self.info.color_type == ColorType::Indexed && self.info.palette.is_none() {
194 return Err(EncodingError::Format(
195 "can't write indexed image without palette".into(),
196 ));
197 }
198
199 let bpp = self.info.bpp_in_prediction();
200 let in_len = self.info.raw_row_length() - 1;
201 let prev = vec![0; in_len];
202 let mut prev = prev.as_slice();
203 let mut current = vec![0; in_len];
204 let data_size = in_len * self.info.height as usize;
205 if data_size != data.len() {
206 let message = format!("wrong data size, expected {} got {}", data_size, data.len());
207 return Err(EncodingError::Format(message.into()));
208 }
209 let mut zlib = deflate::write::ZlibEncoder::new(Vec::new(), self.info.compression.clone());
210 let filter_method = self.info.filter;
211 for line in data.chunks(in_len) {
212 current.copy_from_slice(&line);
213 zlib.write_all(&[filter_method as u8])?;
214 filter(filter_method, bpp, &prev, &mut current);
215 zlib.write_all(¤t)?;
216 prev = line;
217 }
218 let zlib_encoded = zlib.finish()?;
219 for chunk in zlib_encoded.chunks(MAX_CHUNK_LEN as usize) {
220 self.write_chunk(chunk::IDAT, &chunk)?;
221 }
222 Ok(())
223 }
224
225 /// Create an stream writer.
226 ///
227 /// This allows you create images that do not fit in memory. The default
228 /// chunk size is 4K, use `stream_writer_with_size` to set another chuck
229 /// size.
230 ///
231 /// This borrows the writer. This preserves it which allows manually
232 /// appending additional chunks after the image data has been written
stream_writer(&mut self) -> StreamWriter<W>233 pub fn stream_writer(&mut self) -> StreamWriter<W> {
234 self.stream_writer_with_size(DEFAULT_BUFFER_LENGTH)
235 }
236
237 /// Create a stream writer with custom buffer size.
238 ///
239 /// See [`stream_writer`].
240 ///
241 /// [`stream_writer`]: #fn.stream_writer
stream_writer_with_size(&mut self, size: usize) -> StreamWriter<W>242 pub fn stream_writer_with_size(&mut self, size: usize) -> StreamWriter<W> {
243 StreamWriter::new(ChunkOutput::Borrowed(self), size)
244 }
245
246 /// Turn this into a stream writer for image data.
247 ///
248 /// This allows you create images that do not fit in memory. The default
249 /// chunk size is 4K, use `stream_writer_with_size` to set another chuck
250 /// size.
into_stream_writer(self) -> StreamWriter<'static, W>251 pub fn into_stream_writer(self) -> StreamWriter<'static, W> {
252 self.into_stream_writer_with_size(DEFAULT_BUFFER_LENGTH)
253 }
254
255 /// Turn this into a stream writer with custom buffer size.
256 ///
257 /// See [`into_stream_writer`].
258 ///
259 /// [`into_stream_writer`]: #fn.into_stream_writer
into_stream_writer_with_size(self, size: usize) -> StreamWriter<'static, W>260 pub fn into_stream_writer_with_size(self, size: usize) -> StreamWriter<'static, W> {
261 StreamWriter::new(ChunkOutput::Owned(self), size)
262 }
263 }
264
265 impl<W: Write> Drop for Writer<W> {
drop(&mut self)266 fn drop(&mut self) {
267 let _ = self.write_chunk(chunk::IEND, &[]);
268 }
269 }
270
271 struct ChunkWriter<'a, W: Write> {
272 writer: ChunkOutput<'a, W>,
273 buffer: Vec<u8>,
274 index: usize,
275 }
276
277 enum ChunkOutput<'a, W: Write> {
278 Borrowed(&'a mut Writer<W>),
279 Owned(Writer<W>),
280 }
281
282 impl<'a, W: Write> ChunkWriter<'a, W> {
new(writer: ChunkOutput<'a, W>, buf_len: usize) -> ChunkWriter<'a, W>283 fn new(writer: ChunkOutput<'a, W>, buf_len: usize) -> ChunkWriter<'a, W> {
284 ChunkWriter {
285 writer,
286 buffer: vec![0; buf_len],
287 index: 0,
288 }
289 }
290 }
291
292 impl<'a, W: Write> AsMut<Writer<W>> for ChunkOutput<'a, W> {
as_mut(&mut self) -> &mut Writer<W>293 fn as_mut(&mut self) -> &mut Writer<W> {
294 match self {
295 ChunkOutput::Borrowed(writer) => writer,
296 ChunkOutput::Owned(writer) => writer,
297 }
298 }
299 }
300
301 impl<'a, W: Write> Write for ChunkWriter<'a, W> {
write(&mut self, mut buf: &[u8]) -> io::Result<usize>302 fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
303 let written = buf.read(&mut self.buffer[self.index..])?;
304 self.index += written;
305
306 if self.index + 1 >= self.buffer.len() {
307 self.writer
308 .as_mut()
309 .write_chunk(chunk::IDAT, &self.buffer)?;
310 self.index = 0;
311 }
312
313 Ok(written)
314 }
315
flush(&mut self) -> io::Result<()>316 fn flush(&mut self) -> io::Result<()> {
317 if self.index > 0 {
318 self.writer
319 .as_mut()
320 .write_chunk(chunk::IDAT, &self.buffer[..=self.index])?;
321 }
322 self.index = 0;
323 Ok(())
324 }
325 }
326
327 impl<'a, W: Write> Drop for ChunkWriter<'a, W> {
drop(&mut self)328 fn drop(&mut self) {
329 let _ = self.flush();
330 }
331 }
332
333 /// Streaming png writer
334 ///
335 /// This may silently fail in the destructor, so it is a good idea to call
336 /// [`finish`](#method.finish) or [`flush`](https://doc.rust-lang.org/stable/std/io/trait.Write.html#tymethod.flush) before dropping.
337 pub struct StreamWriter<'a, W: Write> {
338 writer: deflate::write::ZlibEncoder<ChunkWriter<'a, W>>,
339 prev_buf: Vec<u8>,
340 curr_buf: Vec<u8>,
341 index: usize,
342 bpp: BytesPerPixel,
343 filter: FilterType,
344 }
345
346 impl<'a, W: Write> StreamWriter<'a, W> {
new(mut writer: ChunkOutput<'a, W>, buf_len: usize) -> StreamWriter<'a, W>347 fn new(mut writer: ChunkOutput<'a, W>, buf_len: usize) -> StreamWriter<'a, W> {
348 let bpp = writer.as_mut().info.bpp_in_prediction();
349 let in_len = writer.as_mut().info.raw_row_length() - 1;
350 let filter = writer.as_mut().info.filter;
351 let prev_buf = vec![0; in_len];
352 let curr_buf = vec![0; in_len];
353
354 let compression = writer.as_mut().info.compression.clone();
355 let chunk_writer = ChunkWriter::new(writer, buf_len);
356 let zlib = deflate::write::ZlibEncoder::new(chunk_writer, compression);
357
358 StreamWriter {
359 writer: zlib,
360 index: 0,
361 prev_buf,
362 curr_buf,
363 bpp,
364 filter,
365 }
366 }
367
finish(mut self) -> Result<()>368 pub fn finish(mut self) -> Result<()> {
369 // TODO: call `writer.finish` somehow?
370 self.flush()?;
371 Ok(())
372 }
373 }
374
375 impl<'a, W: Write> Write for StreamWriter<'a, W> {
write(&mut self, mut buf: &[u8]) -> io::Result<usize>376 fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
377 let written = buf.read(&mut self.curr_buf[self.index..])?;
378 self.index += written;
379
380 if self.index >= self.curr_buf.len() {
381 self.writer.write_all(&[self.filter as u8])?;
382 filter(self.filter, self.bpp, &self.prev_buf, &mut self.curr_buf);
383 self.writer.write_all(&self.curr_buf)?;
384 mem::swap(&mut self.prev_buf, &mut self.curr_buf);
385 self.index = 0;
386 }
387
388 Ok(written)
389 }
390
flush(&mut self) -> io::Result<()>391 fn flush(&mut self) -> io::Result<()> {
392 self.writer.flush()?;
393 if self.index > 0 {
394 let message = format!("wrong data size, got {} bytes too many", self.index);
395 return Err(EncodingError::Format(message.into()).into());
396 }
397 Ok(())
398 }
399 }
400
401 impl<'a, W: Write> Drop for StreamWriter<'a, W> {
drop(&mut self)402 fn drop(&mut self) {
403 let _ = self.flush();
404 }
405 }
406
407 #[cfg(test)]
408 mod tests {
409 use super::*;
410
411 extern crate glob;
412
413 use rand::{thread_rng, Rng};
414 use std::fs::File;
415 use std::io::Write;
416 use std::{cmp, io};
417
418 #[test]
roundtrip()419 fn roundtrip() {
420 // More loops = more random testing, but also more test wait time
421 for _ in 0..10 {
422 for path in glob::glob("tests/pngsuite/*.png")
423 .unwrap()
424 .map(|r| r.unwrap())
425 {
426 if path.file_name().unwrap().to_str().unwrap().starts_with("x") {
427 // x* files are expected to fail to decode
428 continue;
429 }
430 eprintln!("{}", path.display());
431 // Decode image
432 let decoder = crate::Decoder::new(File::open(path).unwrap());
433 let (info, mut reader) = decoder.read_info().unwrap();
434 if info.line_size != 32 {
435 // TODO encoding only works with line size 32?
436 continue;
437 }
438 let mut buf = vec![0; info.buffer_size()];
439 eprintln!("{:?}", info);
440 reader.next_frame(&mut buf).unwrap();
441 // Encode decoded image
442 let mut out = Vec::new();
443 {
444 let mut wrapper = RandomChunkWriter {
445 rng: thread_rng(),
446 w: &mut out,
447 };
448
449 let mut encoder = Encoder::new(&mut wrapper, info.width, info.height)
450 .write_header()
451 .unwrap();
452 encoder.write_image_data(&buf).unwrap();
453 }
454 // Decode encoded decoded image
455 let decoder = crate::Decoder::new(&*out);
456 let (info, mut reader) = decoder.read_info().unwrap();
457 let mut buf2 = vec![0; info.buffer_size()];
458 reader.next_frame(&mut buf2).unwrap();
459 // check if the encoded image is ok:
460 assert_eq!(buf, buf2);
461 }
462 }
463 }
464
465 #[test]
roundtrip_stream()466 fn roundtrip_stream() {
467 // More loops = more random testing, but also more test wait time
468 for _ in 0..10 {
469 for path in glob::glob("tests/pngsuite/*.png")
470 .unwrap()
471 .map(|r| r.unwrap())
472 {
473 if path.file_name().unwrap().to_str().unwrap().starts_with("x") {
474 // x* files are expected to fail to decode
475 continue;
476 }
477 // Decode image
478 let decoder = crate::Decoder::new(File::open(path).unwrap());
479 let (info, mut reader) = decoder.read_info().unwrap();
480 if info.line_size != 32 {
481 // TODO encoding only works with line size 32?
482 continue;
483 }
484 let mut buf = vec![0; info.buffer_size()];
485 reader.next_frame(&mut buf).unwrap();
486 // Encode decoded image
487 let mut out = Vec::new();
488 {
489 let mut wrapper = RandomChunkWriter {
490 rng: thread_rng(),
491 w: &mut out,
492 };
493
494 let mut encoder = Encoder::new(&mut wrapper, info.width, info.height)
495 .write_header()
496 .unwrap();
497 let mut stream_writer = encoder.stream_writer();
498
499 let mut outer_wrapper = RandomChunkWriter {
500 rng: thread_rng(),
501 w: &mut stream_writer,
502 };
503
504 outer_wrapper.write_all(&buf).unwrap();
505 }
506 // Decode encoded decoded image
507 let decoder = crate::Decoder::new(&*out);
508 let (info, mut reader) = decoder.read_info().unwrap();
509 let mut buf2 = vec![0; info.buffer_size()];
510 reader.next_frame(&mut buf2).unwrap();
511 // check if the encoded image is ok:
512 assert_eq!(buf, buf2);
513 }
514 }
515 }
516
517 #[test]
image_palette() -> Result<()>518 fn image_palette() -> Result<()> {
519 let samples = 3;
520 for bit_depth in vec![1u8, 2, 4, 8] {
521 // Do a reference decoding, choose a fitting palette image from pngsuite
522 let path = format!("tests/pngsuite/basn3p0{}.png", bit_depth);
523 let decoder = crate::Decoder::new(File::open(&path).unwrap());
524 let (info, mut reader) = decoder.read_info().unwrap();
525
526 let palette: Vec<u8> = reader.info().palette.clone().unwrap();
527 let mut decoded_pixels = vec![0; info.buffer_size()];
528 assert_eq!(
529 info.width as usize * info.height as usize * samples,
530 decoded_pixels.len()
531 );
532 reader.next_frame(&mut decoded_pixels).unwrap();
533
534 let pixels_per_byte = 8 / usize::from(bit_depth);
535 let mut indexed_data = vec![0; decoded_pixels.len() / samples];
536 {
537 // Retransform the image into palette bits.
538 let mut indexes = vec![];
539 for color in decoded_pixels.chunks(samples) {
540 let j = palette
541 .chunks(samples)
542 .position(|pcolor| color == pcolor)
543 .unwrap();
544 indexes.push(j as u8);
545 }
546
547 let idx_per_byte = indexes.chunks(pixels_per_byte);
548 indexed_data.truncate(idx_per_byte.len());
549 for (pixels, byte) in idx_per_byte.zip(&mut indexed_data) {
550 let mut shift = 8;
551 for idx in pixels {
552 shift -= bit_depth;
553 *byte = *byte | idx << shift;
554 }
555 }
556 };
557
558 let mut out = Vec::new();
559 {
560 let mut encoder = Encoder::new(&mut out, info.width, info.height);
561 encoder.set_depth(BitDepth::from_u8(bit_depth).unwrap());
562 encoder.set_color(ColorType::Indexed);
563 encoder.set_palette(palette.clone());
564
565 let mut writer = encoder.write_header().unwrap();
566 writer.write_image_data(&indexed_data).unwrap();
567 }
568
569 // Decode re-encoded image
570 let decoder = crate::Decoder::new(&*out);
571 let (info, mut reader) = decoder.read_info().unwrap();
572 let mut redecoded = vec![0; info.buffer_size()];
573 reader.next_frame(&mut redecoded).unwrap();
574 // check if the encoded image is ok:
575 assert_eq!(decoded_pixels, redecoded);
576 }
577 Ok(())
578 }
579
580 #[test]
expect_error_on_wrong_image_len() -> Result<()>581 fn expect_error_on_wrong_image_len() -> Result<()> {
582 use std::io::Cursor;
583
584 let width = 10;
585 let height = 10;
586
587 let output = vec![0u8; 1024];
588 let writer = Cursor::new(output);
589 let mut encoder = Encoder::new(writer, width as u32, height as u32);
590 encoder.set_depth(BitDepth::Eight);
591 encoder.set_color(ColorType::RGB);
592 let mut png_writer = encoder.write_header()?;
593
594 let correct_image_size = width * height * 3;
595 let image = vec![0u8; correct_image_size + 1];
596 let result = png_writer.write_image_data(image.as_ref());
597 assert!(result.is_err());
598
599 Ok(())
600 }
601
602 #[test]
expect_error_on_empty_image() -> Result<()>603 fn expect_error_on_empty_image() -> Result<()> {
604 use std::io::Cursor;
605
606 let output = vec![0u8; 1024];
607 let mut writer = Cursor::new(output);
608
609 let encoder = Encoder::new(&mut writer, 0, 0);
610 assert!(encoder.write_header().is_err());
611
612 let encoder = Encoder::new(&mut writer, 100, 0);
613 assert!(encoder.write_header().is_err());
614
615 let encoder = Encoder::new(&mut writer, 0, 100);
616 assert!(encoder.write_header().is_err());
617
618 Ok(())
619 }
620
621 #[test]
expect_error_on_invalid_bit_depth_color_type_combination() -> Result<()>622 fn expect_error_on_invalid_bit_depth_color_type_combination() -> Result<()> {
623 use std::io::Cursor;
624
625 let output = vec![0u8; 1024];
626 let mut writer = Cursor::new(output);
627
628 let mut encoder = Encoder::new(&mut writer, 1, 1);
629 encoder.set_depth(BitDepth::One);
630 encoder.set_color(ColorType::RGB);
631 assert!(encoder.write_header().is_err());
632
633 let mut encoder = Encoder::new(&mut writer, 1, 1);
634 encoder.set_depth(BitDepth::One);
635 encoder.set_color(ColorType::GrayscaleAlpha);
636 assert!(encoder.write_header().is_err());
637
638 let mut encoder = Encoder::new(&mut writer, 1, 1);
639 encoder.set_depth(BitDepth::One);
640 encoder.set_color(ColorType::RGBA);
641 assert!(encoder.write_header().is_err());
642
643 let mut encoder = Encoder::new(&mut writer, 1, 1);
644 encoder.set_depth(BitDepth::Two);
645 encoder.set_color(ColorType::RGB);
646 assert!(encoder.write_header().is_err());
647
648 let mut encoder = Encoder::new(&mut writer, 1, 1);
649 encoder.set_depth(BitDepth::Two);
650 encoder.set_color(ColorType::GrayscaleAlpha);
651 assert!(encoder.write_header().is_err());
652
653 let mut encoder = Encoder::new(&mut writer, 1, 1);
654 encoder.set_depth(BitDepth::Two);
655 encoder.set_color(ColorType::RGBA);
656 assert!(encoder.write_header().is_err());
657
658 let mut encoder = Encoder::new(&mut writer, 1, 1);
659 encoder.set_depth(BitDepth::Four);
660 encoder.set_color(ColorType::RGB);
661 assert!(encoder.write_header().is_err());
662
663 let mut encoder = Encoder::new(&mut writer, 1, 1);
664 encoder.set_depth(BitDepth::Four);
665 encoder.set_color(ColorType::GrayscaleAlpha);
666 assert!(encoder.write_header().is_err());
667
668 let mut encoder = Encoder::new(&mut writer, 1, 1);
669 encoder.set_depth(BitDepth::Four);
670 encoder.set_color(ColorType::RGBA);
671 assert!(encoder.write_header().is_err());
672
673 let mut encoder = Encoder::new(&mut writer, 1, 1);
674 encoder.set_depth(BitDepth::Sixteen);
675 encoder.set_color(ColorType::Indexed);
676 assert!(encoder.write_header().is_err());
677
678 Ok(())
679 }
680
681 #[test]
can_write_header_with_valid_bit_depth_color_type_combination() -> Result<()>682 fn can_write_header_with_valid_bit_depth_color_type_combination() -> Result<()> {
683 use std::io::Cursor;
684
685 let output = vec![0u8; 1024];
686 let mut writer = Cursor::new(output);
687
688 let mut encoder = Encoder::new(&mut writer, 1, 1);
689 encoder.set_depth(BitDepth::One);
690 encoder.set_color(ColorType::Grayscale);
691 assert!(encoder.write_header().is_ok());
692
693 let mut encoder = Encoder::new(&mut writer, 1, 1);
694 encoder.set_depth(BitDepth::One);
695 encoder.set_color(ColorType::Indexed);
696 assert!(encoder.write_header().is_ok());
697
698 let mut encoder = Encoder::new(&mut writer, 1, 1);
699 encoder.set_depth(BitDepth::Two);
700 encoder.set_color(ColorType::Grayscale);
701 assert!(encoder.write_header().is_ok());
702
703 let mut encoder = Encoder::new(&mut writer, 1, 1);
704 encoder.set_depth(BitDepth::Two);
705 encoder.set_color(ColorType::Indexed);
706 assert!(encoder.write_header().is_ok());
707
708 let mut encoder = Encoder::new(&mut writer, 1, 1);
709 encoder.set_depth(BitDepth::Four);
710 encoder.set_color(ColorType::Grayscale);
711 assert!(encoder.write_header().is_ok());
712
713 let mut encoder = Encoder::new(&mut writer, 1, 1);
714 encoder.set_depth(BitDepth::Four);
715 encoder.set_color(ColorType::Indexed);
716 assert!(encoder.write_header().is_ok());
717
718 let mut encoder = Encoder::new(&mut writer, 1, 1);
719 encoder.set_depth(BitDepth::Eight);
720 encoder.set_color(ColorType::Grayscale);
721 assert!(encoder.write_header().is_ok());
722
723 let mut encoder = Encoder::new(&mut writer, 1, 1);
724 encoder.set_depth(BitDepth::Eight);
725 encoder.set_color(ColorType::RGB);
726 assert!(encoder.write_header().is_ok());
727
728 let mut encoder = Encoder::new(&mut writer, 1, 1);
729 encoder.set_depth(BitDepth::Eight);
730 encoder.set_color(ColorType::Indexed);
731 assert!(encoder.write_header().is_ok());
732
733 let mut encoder = Encoder::new(&mut writer, 1, 1);
734 encoder.set_depth(BitDepth::Eight);
735 encoder.set_color(ColorType::GrayscaleAlpha);
736 assert!(encoder.write_header().is_ok());
737
738 let mut encoder = Encoder::new(&mut writer, 1, 1);
739 encoder.set_depth(BitDepth::Eight);
740 encoder.set_color(ColorType::RGBA);
741 assert!(encoder.write_header().is_ok());
742
743 let mut encoder = Encoder::new(&mut writer, 1, 1);
744 encoder.set_depth(BitDepth::Sixteen);
745 encoder.set_color(ColorType::Grayscale);
746 assert!(encoder.write_header().is_ok());
747
748 let mut encoder = Encoder::new(&mut writer, 1, 1);
749 encoder.set_depth(BitDepth::Sixteen);
750 encoder.set_color(ColorType::RGB);
751 assert!(encoder.write_header().is_ok());
752
753 let mut encoder = Encoder::new(&mut writer, 1, 1);
754 encoder.set_depth(BitDepth::Sixteen);
755 encoder.set_color(ColorType::GrayscaleAlpha);
756 assert!(encoder.write_header().is_ok());
757
758 let mut encoder = Encoder::new(&mut writer, 1, 1);
759 encoder.set_depth(BitDepth::Sixteen);
760 encoder.set_color(ColorType::RGBA);
761 assert!(encoder.write_header().is_ok());
762
763 Ok(())
764 }
765
766 #[test]
all_filters_roundtrip() -> io::Result<()>767 fn all_filters_roundtrip() -> io::Result<()> {
768 let pixel: Vec<_> = (0..48).collect();
769
770 let roundtrip = |filter: FilterType| -> io::Result<()> {
771 let mut buffer = vec![];
772 let mut encoder = Encoder::new(&mut buffer, 4, 4);
773 encoder.set_depth(BitDepth::Eight);
774 encoder.set_color(ColorType::RGB);
775 encoder.set_filter(filter);
776 encoder.write_header()?.write_image_data(&pixel)?;
777
778 let decoder = crate::Decoder::new(io::Cursor::new(buffer));
779 let (info, mut reader) = decoder.read_info()?;
780 assert_eq!(info.width, 4);
781 assert_eq!(info.height, 4);
782 let mut dest = vec![0; pixel.len()];
783 reader.next_frame(&mut dest)?;
784 assert_eq!(dest, pixel, "Deviation with filter type {:?}", filter);
785
786 Ok(())
787 };
788
789 roundtrip(FilterType::NoFilter)?;
790 roundtrip(FilterType::Sub)?;
791 roundtrip(FilterType::Up)?;
792 roundtrip(FilterType::Avg)?;
793 roundtrip(FilterType::Paeth)?;
794
795 Ok(())
796 }
797
798 /// A Writer that only writes a few bytes at a time
799 struct RandomChunkWriter<'a, R: Rng, W: Write + 'a> {
800 rng: R,
801 w: &'a mut W,
802 }
803
804 impl<'a, R: Rng, W: Write + 'a> Write for RandomChunkWriter<'a, R, W> {
write(&mut self, buf: &[u8]) -> io::Result<usize>805 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
806 // choose a random length to write
807 let len = cmp::min(self.rng.gen_range(1, 50), buf.len());
808
809 self.w.write(&buf[0..len])
810 }
811
flush(&mut self) -> io::Result<()>812 fn flush(&mut self) -> io::Result<()> {
813 self.w.flush()
814 }
815 }
816 }
817