Coverage Report

Created: 2025-07-01 06:50

/rust/registry/src/index.crates.io-6f17d22bba15001f/png-0.17.16/src/encoder.rs
Line
Count
Source (jump to first uncovered line)
1
use borrow::Cow;
2
use io::{Read, Write};
3
use ops::{Deref, DerefMut};
4
use std::{borrow, error, fmt, io, mem, ops, result};
5
6
use crc32fast::Hasher as Crc32;
7
use flate2::write::ZlibEncoder;
8
9
use crate::chunk::{self, ChunkType};
10
use crate::common::{
11
    AnimationControl, BitDepth, BlendOp, BytesPerPixel, ColorType, Compression, DisposeOp,
12
    FrameControl, Info, ParameterError, ParameterErrorKind, PixelDimensions, ScaledFloat,
13
};
14
use crate::filter::{filter, AdaptiveFilterType, FilterType};
15
use crate::text_metadata::{
16
    encode_iso_8859_1, EncodableTextChunk, ITXtChunk, TEXtChunk, TextEncodingError, ZTXtChunk,
17
};
18
use crate::traits::WriteBytesExt;
19
20
pub type Result<T> = result::Result<T, EncodingError>;
21
22
#[derive(Debug)]
23
pub enum EncodingError {
24
    IoError(io::Error),
25
    Format(FormatError),
26
    Parameter(ParameterError),
27
    LimitsExceeded,
28
}
29
30
#[derive(Debug)]
31
pub struct FormatError {
32
    inner: FormatErrorKind,
33
}
34
35
#[derive(Debug)]
36
enum FormatErrorKind {
37
    ZeroWidth,
38
    ZeroHeight,
39
    InvalidColorCombination(BitDepth, ColorType),
40
    NoPalette,
41
    // TODO: wait, what?
42
    WrittenTooMuch(usize),
43
    NotAnimated,
44
    OutOfBounds,
45
    EndReached,
46
    ZeroFrames,
47
    MissingFrames,
48
    MissingData(usize),
49
    Unrecoverable,
50
    BadTextEncoding(TextEncodingError),
51
}
52
53
impl error::Error for EncodingError {
54
0
    fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
55
0
        match self {
56
0
            EncodingError::IoError(err) => Some(err),
57
0
            _ => None,
58
        }
59
0
    }
60
}
61
62
impl fmt::Display for EncodingError {
63
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
64
        use self::EncodingError::*;
65
0
        match self {
66
0
            IoError(err) => write!(fmt, "{}", err),
67
0
            Format(desc) => write!(fmt, "{}", desc),
68
0
            Parameter(desc) => write!(fmt, "{}", desc),
69
0
            LimitsExceeded => write!(fmt, "Limits are exceeded."),
70
        }
71
0
    }
72
}
73
74
impl fmt::Display for FormatError {
75
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
76
        use FormatErrorKind::*;
77
0
        match self.inner {
78
0
            ZeroWidth => write!(fmt, "Zero width not allowed"),
79
0
            ZeroHeight => write!(fmt, "Zero height not allowed"),
80
0
            ZeroFrames => write!(fmt, "Zero frames not allowed"),
81
0
            InvalidColorCombination(depth, color) => write!(
82
0
                fmt,
83
0
                "Invalid combination of bit-depth '{:?}' and color-type '{:?}'",
84
0
                depth, color
85
0
            ),
86
0
            NoPalette => write!(fmt, "can't write indexed image without palette"),
87
0
            WrittenTooMuch(index) => write!(fmt, "wrong data size, got {} bytes too many", index),
88
0
            NotAnimated => write!(fmt, "not an animation"),
89
0
            OutOfBounds => write!(
90
0
                fmt,
91
0
                "the dimension and position go over the frame boundaries"
92
0
            ),
93
0
            EndReached => write!(fmt, "all the frames have been already written"),
94
0
            MissingFrames => write!(fmt, "there are still frames to be written"),
95
0
            MissingData(n) => write!(fmt, "there are still {} bytes to be written", n),
96
0
            Unrecoverable => write!(
97
0
                fmt,
98
0
                "a previous error put the writer into an unrecoverable state"
99
0
            ),
100
0
            BadTextEncoding(tee) => match tee {
101
0
                TextEncodingError::Unrepresentable => write!(
102
0
                    fmt,
103
0
                    "The text metadata cannot be encoded into valid ISO 8859-1"
104
0
                ),
105
0
                TextEncodingError::InvalidKeywordSize => write!(fmt, "Invalid keyword size"),
106
                TextEncodingError::CompressionError => {
107
0
                    write!(fmt, "Unable to compress text metadata")
108
                }
109
            },
110
        }
111
0
    }
112
}
113
114
impl From<io::Error> for EncodingError {
115
0
    fn from(err: io::Error) -> EncodingError {
116
0
        EncodingError::IoError(err)
117
0
    }
118
}
119
120
impl From<EncodingError> for io::Error {
121
0
    fn from(err: EncodingError) -> io::Error {
122
0
        io::Error::new(io::ErrorKind::Other, err.to_string())
123
0
    }
124
}
125
126
// Private impl.
127
impl From<FormatErrorKind> for FormatError {
128
0
    fn from(kind: FormatErrorKind) -> Self {
129
0
        FormatError { inner: kind }
130
0
    }
131
}
132
133
impl From<TextEncodingError> for EncodingError {
134
0
    fn from(tee: TextEncodingError) -> Self {
135
0
        EncodingError::Format(FormatError {
136
0
            inner: FormatErrorKind::BadTextEncoding(tee),
137
0
        })
138
0
    }
139
}
140
141
/// PNG Encoder.
142
///
143
/// This configures the PNG format options such as animation chunks, palette use, color types,
144
/// auxiliary chunks etc.
145
///
146
/// FIXME: Configuring APNG might be easier (less individual errors) if we had an _adapter_ which
147
/// borrows this mutably but guarantees that `info.frame_control` is not `None`.
148
pub struct Encoder<'a, W: Write> {
149
    w: W,
150
    info: Info<'a>,
151
    options: Options,
152
}
153
154
/// Decoding options, internal type, forwarded to the Writer.
155
#[derive(Default)]
156
struct Options {
157
    filter: FilterType,
158
    adaptive_filter: AdaptiveFilterType,
159
    sep_def_img: bool,
160
    validate_sequence: bool,
161
}
162
163
impl<'a, W: Write> Encoder<'a, W> {
164
0
    pub fn new(w: W, width: u32, height: u32) -> Encoder<'static, W> {
165
0
        Encoder {
166
0
            w,
167
0
            info: Info::with_size(width, height),
168
0
            options: Options::default(),
169
0
        }
170
0
    }
171
172
0
    pub fn with_info(w: W, info: Info<'a>) -> Result<Encoder<'a, W>> {
173
0
        if info.animation_control.is_some() != info.frame_control.is_some() {
174
0
            return Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()));
175
0
        }
176
177
0
        if let Some(actl) = info.animation_control {
178
0
            if actl.num_frames == 0 {
179
0
                return Err(EncodingError::Format(FormatErrorKind::ZeroFrames.into()));
180
0
            }
181
0
        }
182
183
0
        Ok(Encoder {
184
0
            w,
185
0
            info,
186
0
            options: Options::default(),
187
0
        })
188
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::with_info
Unexecuted instantiation: <png::encoder::Encoder<_>>::with_info
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::with_info
189
190
    /// Specify that the image is animated.
191
    ///
192
    /// `num_frames` controls how many frames the animation has, while
193
    /// `num_plays` controls how many times the animation should be
194
    /// repeated until it stops, if it's zero then it will repeat
195
    /// infinitely.
196
    ///
197
    /// When this method is returns successfully then the images written will be encoded as fdAT
198
    /// chunks, except for the first image that is still encoded as `IDAT`. You can control if the
199
    /// first frame should be treated as an animation frame with [`Encoder::set_sep_def_img()`].
200
    ///
201
    /// This method returns an error if `num_frames` is 0.
202
0
    pub fn set_animated(&mut self, num_frames: u32, num_plays: u32) -> Result<()> {
203
0
        if num_frames == 0 {
204
0
            return Err(EncodingError::Format(FormatErrorKind::ZeroFrames.into()));
205
0
        }
206
0
207
0
        let actl = AnimationControl {
208
0
            num_frames,
209
0
            num_plays,
210
0
        };
211
0
212
0
        let fctl = FrameControl {
213
0
            sequence_number: 0,
214
0
            width: self.info.width,
215
0
            height: self.info.height,
216
0
            ..Default::default()
217
0
        };
218
0
219
0
        self.info.animation_control = Some(actl);
220
0
        self.info.frame_control = Some(fctl);
221
0
        Ok(())
222
0
    }
223
224
    /// Mark the first animated frame as a 'separate default image'.
225
    ///
226
    /// In APNG each animated frame is preceded by a special control chunk, `fcTL`. It's up to the
227
    /// encoder to decide if the first image, the standard `IDAT` data, should be part of the
228
    /// animation by emitting this chunk or by not doing so. A default image that is _not_ part of
229
    /// the animation is often interpreted as a thumbnail.
230
    ///
231
    /// This method will return an error when animation control was not configured
232
    /// (which is done by calling [`Encoder::set_animated`]).
233
0
    pub fn set_sep_def_img(&mut self, sep_def_img: bool) -> Result<()> {
234
0
        if self.info.animation_control.is_some() {
235
0
            self.options.sep_def_img = sep_def_img;
236
0
            Ok(())
237
        } else {
238
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
239
        }
240
0
    }
241
242
    /// Sets the raw byte contents of the PLTE chunk. This method accepts
243
    /// both borrowed and owned byte data.
244
0
    pub fn set_palette<T: Into<Cow<'a, [u8]>>>(&mut self, palette: T) {
245
0
        self.info.palette = Some(palette.into());
246
0
    }
247
248
    /// Sets the raw byte contents of the tRNS chunk. This method accepts
249
    /// both borrowed and owned byte data.
250
0
    pub fn set_trns<T: Into<Cow<'a, [u8]>>>(&mut self, trns: T) {
251
0
        self.info.trns = Some(trns.into());
252
0
    }
253
254
    /// Set the display gamma of the source system on which the image was generated or last edited.
255
0
    pub fn set_source_gamma(&mut self, source_gamma: ScaledFloat) {
256
0
        self.info.source_gamma = Some(source_gamma);
257
0
    }
258
259
    /// Set the chromaticities for the source system's display channels (red, green, blue) and the whitepoint
260
    /// of the source system on which the image was generated or last edited.
261
0
    pub fn set_source_chromaticities(
262
0
        &mut self,
263
0
        source_chromaticities: super::SourceChromaticities,
264
0
    ) {
265
0
        self.info.source_chromaticities = Some(source_chromaticities);
266
0
    }
267
268
    /// Mark the image data as conforming to the SRGB color space with the specified rendering intent.
269
    ///
270
    /// Matching source gamma and chromaticities chunks are added automatically.
271
    /// Any manually specified source gamma, chromaticities, or ICC profiles will be ignored.
272
    #[doc(hidden)]
273
    #[deprecated(note = "use set_source_srgb")]
274
0
    pub fn set_srgb(&mut self, rendering_intent: super::SrgbRenderingIntent) {
275
0
        self.info.set_source_srgb(rendering_intent);
276
0
        self.info.source_gamma = Some(crate::srgb::substitute_gamma());
277
0
        self.info.source_chromaticities = Some(crate::srgb::substitute_chromaticities());
278
0
    }
279
280
    /// Mark the image data as conforming to the SRGB color space with the specified rendering intent.
281
    ///
282
    /// Any ICC profiles will be ignored.
283
    ///
284
    /// Source gamma and chromaticities will be written only if they're set to fallback
285
    /// values specified in [11.3.2.5](https://www.w3.org/TR/png-3/#sRGB-gAMA-cHRM).
286
0
    pub fn set_source_srgb(&mut self, rendering_intent: super::SrgbRenderingIntent) {
287
0
        self.info.set_source_srgb(rendering_intent);
288
0
    }
289
290
    /// Start encoding by writing the header data.
291
    ///
292
    /// The remaining data can be supplied by methods on the returned [`Writer`].
293
0
    pub fn write_header(self) -> Result<Writer<W>> {
294
0
        Writer::new(self.w, PartialInfo::new(&self.info), self.options).init(&self.info)
295
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::write_header
Unexecuted instantiation: <png::encoder::Encoder<_>>::write_header
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_header
296
297
    /// Set the color of the encoded image.
298
    ///
299
    /// These correspond to the color types in the png IHDR data that will be written. The length
300
    /// of the image data that is later supplied must match the color type, otherwise an error will
301
    /// be emitted.
302
0
    pub fn set_color(&mut self, color: ColorType) {
303
0
        self.info.color_type = color;
304
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::set_color
Unexecuted instantiation: <png::encoder::Encoder<_>>::set_color
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_color
305
306
    /// Set the indicated depth of the image data.
307
0
    pub fn set_depth(&mut self, depth: BitDepth) {
308
0
        self.info.bit_depth = depth;
309
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::set_depth
Unexecuted instantiation: <png::encoder::Encoder<_>>::set_depth
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_depth
310
311
    /// Set compression parameters.
312
    ///
313
    /// Accepts a `Compression` or any type that can transform into a `Compression`. Notably `deflate::Compression` and
314
    /// `deflate::CompressionOptions` which "just work".
315
0
    pub fn set_compression(&mut self, compression: Compression) {
316
0
        self.info.compression = compression;
317
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::set_compression
Unexecuted instantiation: <png::encoder::Encoder<_>>::set_compression
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_compression
318
319
    /// Set the used filter type.
320
    ///
321
    /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
322
    /// sample values based on the previous. For a potentially better compression ratio, at the
323
    /// cost of more complex processing, try out [`FilterType::Paeth`].
324
0
    pub fn set_filter(&mut self, filter: FilterType) {
325
0
        self.options.filter = filter;
326
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::set_filter
Unexecuted instantiation: <png::encoder::Encoder<_>>::set_filter
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_filter
327
328
    /// Set the adaptive filter type.
329
    ///
330
    /// Adaptive filtering attempts to select the best filter for each line
331
    /// based on heuristics which minimize the file size for compression rather
332
    /// than use a single filter for the entire image. The default method is
333
    /// [`AdaptiveFilterType::NonAdaptive`].
334
0
    pub fn set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType) {
335
0
        self.options.adaptive_filter = adaptive_filter;
336
0
    }
Unexecuted instantiation: <png::encoder::Encoder<&mut alloc::vec::Vec<u8>>>::set_adaptive_filter
Unexecuted instantiation: <png::encoder::Encoder<_>>::set_adaptive_filter
Unexecuted instantiation: <png::encoder::Encoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_adaptive_filter
337
338
    /// Set the fraction of time every frame is going to be displayed, in seconds.
339
    ///
340
    /// *Note that this parameter can be set for each individual frame after
341
    /// [`Encoder::write_header`] is called. (see [`Writer::set_frame_delay`])*
342
    ///
343
    /// If the denominator is 0, it is to be treated as if it were 100
344
    /// (that is, the numerator then specifies 1/100ths of a second).
345
    /// If the value of the numerator is 0 the decoder should render the next frame
346
    /// as quickly as possible, though viewers may impose a reasonable lower bound.
347
    ///
348
    /// The default value is 0 for both the numerator and denominator.
349
    ///
350
    /// This method will return an error if the image is not animated.
351
    /// (see [`set_animated`])
352
    ///
353
    /// [`write_header`]: Self::write_header
354
    /// [`set_animated`]: Self::set_animated
355
0
    pub fn set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()> {
356
0
        if let Some(ref mut fctl) = self.info.frame_control {
357
0
            fctl.delay_den = denominator;
358
0
            fctl.delay_num = numerator;
359
0
            Ok(())
360
        } else {
361
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
362
        }
363
0
    }
364
365
    /// Set the blend operation for every frame.
366
    ///
367
    /// The blend operation specifies whether the frame is to be alpha blended
368
    /// into the current output buffer content, or whether it should completely
369
    /// replace its region in the output buffer.
370
    ///
371
    /// *Note that this parameter can be set for each individual frame after
372
    /// [`write_header`] is called. (see [`Writer::set_blend_op`])*
373
    ///
374
    /// See the [`BlendOp`] documentation for the possible values and their effects.
375
    ///
376
    /// *Note that for the first frame the two blend modes are functionally
377
    /// equivalent due to the clearing of the output buffer at the beginning
378
    /// of each play.*
379
    ///
380
    /// The default value is [`BlendOp::Source`].
381
    ///
382
    /// This method will return an error if the image is not animated.
383
    /// (see [`set_animated`])
384
    ///
385
    /// [`write_header`]: Self::write_header
386
    /// [`set_animated`]: Self::set_animated
387
0
    pub fn set_blend_op(&mut self, op: BlendOp) -> Result<()> {
388
0
        if let Some(ref mut fctl) = self.info.frame_control {
389
0
            fctl.blend_op = op;
390
0
            Ok(())
391
        } else {
392
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
393
        }
394
0
    }
395
396
    /// Set the dispose operation for every frame.
397
    ///
398
    /// The dispose operation specifies how the output buffer should be changed
399
    /// at the end of the delay (before rendering the next frame)
400
    ///
401
    /// *Note that this parameter can be set for each individual frame after
402
    /// [`write_header`] is called (see [`Writer::set_dispose_op`])*
403
    ///
404
    /// See the [`DisposeOp`] documentation for the possible values and their effects.
405
    ///
406
    /// *Note that if the first frame uses [`DisposeOp::Previous`]
407
    /// it will be treated as [`DisposeOp::Background`].*
408
    ///
409
    /// The default value is [`DisposeOp::None`].
410
    ///
411
    /// This method will return an error if the image is not animated.
412
    /// (see [`set_animated`])
413
    ///
414
    /// [`set_animated`]: Self::set_animated
415
    /// [`write_header`]: Self::write_header
416
0
    pub fn set_dispose_op(&mut self, op: DisposeOp) -> Result<()> {
417
0
        if let Some(ref mut fctl) = self.info.frame_control {
418
0
            fctl.dispose_op = op;
419
0
            Ok(())
420
        } else {
421
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
422
        }
423
0
    }
424
0
    pub fn set_pixel_dims(&mut self, pixel_dims: Option<PixelDimensions>) {
425
0
        self.info.pixel_dims = pixel_dims
426
0
    }
427
    /// Convenience function to add tEXt chunks to [`Info`] struct
428
0
    pub fn add_text_chunk(&mut self, keyword: String, text: String) -> Result<()> {
429
0
        let text_chunk = TEXtChunk::new(keyword, text);
430
0
        self.info.uncompressed_latin1_text.push(text_chunk);
431
0
        Ok(())
432
0
    }
433
434
    /// Convenience function to add zTXt chunks to [`Info`] struct
435
0
    pub fn add_ztxt_chunk(&mut self, keyword: String, text: String) -> Result<()> {
436
0
        let text_chunk = ZTXtChunk::new(keyword, text);
437
0
        self.info.compressed_latin1_text.push(text_chunk);
438
0
        Ok(())
439
0
    }
440
441
    /// Convenience function to add iTXt chunks to [`Info`] struct
442
    ///
443
    /// This function only sets the `keyword` and `text` field of the iTXt chunk.
444
    /// To set the other fields, create a [`ITXtChunk`] directly, and then encode it to the output stream.
445
0
    pub fn add_itxt_chunk(&mut self, keyword: String, text: String) -> Result<()> {
446
0
        let text_chunk = ITXtChunk::new(keyword, text);
447
0
        self.info.utf8_text.push(text_chunk);
448
0
        Ok(())
449
0
    }
450
451
    /// Validate the written image sequence.
452
    ///
453
    /// When validation is turned on (it's turned off by default) then attempts to write more than
454
    /// one `IDAT` image or images beyond the number of frames indicated in the animation control
455
    /// chunk will fail and return an error result instead. Attempts to [finish][finish] the image
456
    /// with missing frames will also return an error.
457
    ///
458
    /// [finish]: StreamWriter::finish
459
    ///
460
    /// (It's possible to circumvent these checks by writing raw chunks instead.)
461
0
    pub fn validate_sequence(&mut self, validate: bool) {
462
0
        self.options.validate_sequence = validate;
463
0
    }
464
}
465
466
/// PNG writer
467
///
468
/// Progresses through the image by writing images, frames, or raw individual chunks. This is
469
/// constructed through [`Encoder::write_header()`].
470
///
471
/// FIXME: Writing of animated chunks might be clearer if we had an _adapter_ that you would call
472
/// to guarantee the next image to be prefaced with a fcTL-chunk, and all other chunks would be
473
/// guaranteed to be `IDAT`/not affected by APNG's frame control.
474
pub struct Writer<W: Write> {
475
    /// The underlying writer.
476
    w: W,
477
    /// The local version of the `Info` struct.
478
    info: PartialInfo,
479
    /// Global encoding options.
480
    options: Options,
481
    /// The total number of image frames, counting all consecutive IDAT and fdAT chunks.
482
    images_written: u64,
483
    /// The total number of animation frames, that is equivalent to counting fcTL chunks.
484
    animation_written: u32,
485
    /// A flag to note when the IEND chunk was already added.
486
    /// This is only set on code paths that drop `Self` to control the destructor.
487
    iend_written: bool,
488
}
489
490
/// Contains the subset of attributes of [Info] needed for [Writer] to function
491
struct PartialInfo {
492
    width: u32,
493
    height: u32,
494
    bit_depth: BitDepth,
495
    color_type: ColorType,
496
    frame_control: Option<FrameControl>,
497
    animation_control: Option<AnimationControl>,
498
    compression: Compression,
499
    has_palette: bool,
500
}
501
502
impl PartialInfo {
503
0
    fn new(info: &Info) -> Self {
504
0
        PartialInfo {
505
0
            width: info.width,
506
0
            height: info.height,
507
0
            bit_depth: info.bit_depth,
508
0
            color_type: info.color_type,
509
0
            frame_control: info.frame_control,
510
0
            animation_control: info.animation_control,
511
0
            compression: info.compression,
512
0
            has_palette: info.palette.is_some(),
513
0
        }
514
0
    }
515
516
0
    fn bpp_in_prediction(&self) -> BytesPerPixel {
517
0
        // Passthrough
518
0
        self.to_info().bpp_in_prediction()
519
0
    }
520
521
0
    fn raw_row_length(&self) -> usize {
522
0
        // Passthrough
523
0
        self.to_info().raw_row_length()
524
0
    }
525
526
0
    fn raw_row_length_from_width(&self, width: u32) -> usize {
527
0
        // Passthrough
528
0
        self.to_info().raw_row_length_from_width(width)
529
0
    }
530
531
    /// Converts this partial info to an owned Info struct,
532
    /// setting missing values to their defaults
533
0
    fn to_info(&self) -> Info<'static> {
534
0
        Info {
535
0
            width: self.width,
536
0
            height: self.height,
537
0
            bit_depth: self.bit_depth,
538
0
            color_type: self.color_type,
539
0
            frame_control: self.frame_control,
540
0
            animation_control: self.animation_control,
541
0
            compression: self.compression,
542
0
            ..Default::default()
543
0
        }
544
0
    }
545
}
546
547
const DEFAULT_BUFFER_LENGTH: usize = 4 * 1024;
548
549
0
pub(crate) fn write_chunk<W: Write>(mut w: W, name: chunk::ChunkType, data: &[u8]) -> Result<()> {
550
0
    w.write_be(data.len() as u32)?;
551
0
    w.write_all(&name.0)?;
552
0
    w.write_all(data)?;
553
0
    let mut crc = Crc32::new();
554
0
    crc.update(&name.0);
555
0
    crc.update(data);
556
0
    w.write_be(crc.finalize())?;
557
0
    Ok(())
558
0
}
Unexecuted instantiation: png::encoder::write_chunk::<&mut &mut alloc::vec::Vec<u8>>
Unexecuted instantiation: png::encoder::write_chunk::<&mut &mut &mut alloc::vec::Vec<u8>>
Unexecuted instantiation: png::encoder::write_chunk::<_>
Unexecuted instantiation: png::encoder::write_chunk::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
Unexecuted instantiation: png::encoder::write_chunk::<&mut &mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
559
560
impl<W: Write> Writer<W> {
561
0
    fn new(w: W, info: PartialInfo, options: Options) -> Writer<W> {
562
0
        Writer {
563
0
            w,
564
0
            info,
565
0
            options,
566
0
            images_written: 0,
567
0
            animation_written: 0,
568
0
            iend_written: false,
569
0
        }
570
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::new
Unexecuted instantiation: <png::encoder::Writer<_>>::new
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
571
572
0
    fn init(mut self, info: &Info<'_>) -> Result<Self> {
573
0
        if self.info.width == 0 {
574
0
            return Err(EncodingError::Format(FormatErrorKind::ZeroWidth.into()));
575
0
        }
576
0
577
0
        if self.info.height == 0 {
578
0
            return Err(EncodingError::Format(FormatErrorKind::ZeroHeight.into()));
579
0
        }
580
0
581
0
        if self
582
0
            .info
583
0
            .color_type
584
0
            .is_combination_invalid(self.info.bit_depth)
585
        {
586
0
            return Err(EncodingError::Format(
587
0
                FormatErrorKind::InvalidColorCombination(self.info.bit_depth, self.info.color_type)
588
0
                    .into(),
589
0
            ));
590
0
        }
591
0
592
0
        self.w.write_all(&[137, 80, 78, 71, 13, 10, 26, 10])?; // PNG signature
593
        #[allow(deprecated)]
594
0
        info.encode(&mut self.w)?;
595
596
0
        Ok(self)
597
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::init
Unexecuted instantiation: <png::encoder::Writer<_>>::init
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::init
598
599
    /// Write a raw chunk of PNG data.
600
    ///
601
    /// The chunk will have its CRC calculated and correctly. The data is not filtered in any way,
602
    /// but the chunk needs to be short enough to have its length encoded correctly.
603
0
    pub fn write_chunk(&mut self, name: ChunkType, data: &[u8]) -> Result<()> {
604
        use std::convert::TryFrom;
605
606
0
        if u32::try_from(data.len()).map_or(true, |length| length > i32::MAX as u32) {
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::write_chunk::{closure#0}
Unexecuted instantiation: <png::encoder::Writer<_>>::write_chunk::{closure#0}
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_chunk::{closure#0}
607
0
            let kind = FormatErrorKind::WrittenTooMuch(data.len() - i32::MAX as usize);
608
0
            return Err(EncodingError::Format(kind.into()));
609
0
        }
610
0
611
0
        write_chunk(&mut self.w, name, data)
612
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::write_chunk
Unexecuted instantiation: <png::encoder::Writer<_>>::write_chunk
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_chunk
613
614
0
    pub fn write_text_chunk<T: EncodableTextChunk>(&mut self, text_chunk: &T) -> Result<()> {
615
0
        text_chunk.encode(&mut self.w)
616
0
    }
617
618
    /// Check if we should allow writing another image.
619
0
    fn validate_new_image(&self) -> Result<()> {
620
0
        if !self.options.validate_sequence {
621
0
            return Ok(());
622
0
        }
623
0
624
0
        match self.info.animation_control {
625
            None => {
626
0
                if self.images_written == 0 {
627
0
                    Ok(())
628
                } else {
629
0
                    Err(EncodingError::Format(FormatErrorKind::EndReached.into()))
630
                }
631
            }
632
            Some(_) => {
633
0
                if self.info.frame_control.is_some() {
634
0
                    Ok(())
635
                } else {
636
0
                    Err(EncodingError::Format(FormatErrorKind::EndReached.into()))
637
                }
638
            }
639
        }
640
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::validate_new_image
Unexecuted instantiation: <png::encoder::Writer<_>>::validate_new_image
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::validate_new_image
641
642
0
    fn validate_sequence_done(&self) -> Result<()> {
643
0
        if !self.options.validate_sequence {
644
0
            return Ok(());
645
0
        }
646
0
647
0
        if (self.info.animation_control.is_some() && self.info.frame_control.is_some())
648
0
            || self.images_written == 0
649
        {
650
0
            Err(EncodingError::Format(FormatErrorKind::MissingFrames.into()))
651
        } else {
652
0
            Ok(())
653
        }
654
0
    }
655
656
    const MAX_IDAT_CHUNK_LEN: u32 = u32::MAX >> 1;
657
    #[allow(non_upper_case_globals)]
658
    const MAX_fdAT_CHUNK_LEN: u32 = (u32::MAX >> 1) - 4;
659
660
    /// Writes the next image data.
661
0
    pub fn write_image_data(&mut self, data: &[u8]) -> Result<()> {
662
0
        if self.info.color_type == ColorType::Indexed && !self.info.has_palette {
663
0
            return Err(EncodingError::Format(FormatErrorKind::NoPalette.into()));
664
0
        }
665
0
666
0
        self.validate_new_image()?;
667
668
        let width: usize;
669
        let height: usize;
670
0
        if let Some(ref mut fctl) = self.info.frame_control {
671
0
            width = fctl.width as usize;
672
0
            height = fctl.height as usize;
673
0
        } else {
674
0
            width = self.info.width as usize;
675
0
            height = self.info.height as usize;
676
0
        }
677
678
0
        let in_len = self.info.raw_row_length_from_width(width as u32) - 1;
679
0
        let data_size = in_len * height;
680
0
        if data_size != data.len() {
681
0
            return Err(EncodingError::Parameter(
682
0
                ParameterErrorKind::ImageBufferSize {
683
0
                    expected: data_size,
684
0
                    actual: data.len(),
685
0
                }
686
0
                .into(),
687
0
            ));
688
0
        }
689
0
690
0
        let prev = vec![0; in_len];
691
0
        let mut prev = prev.as_slice();
692
0
693
0
        let bpp = self.info.bpp_in_prediction();
694
0
        let filter_method = self.options.filter;
695
0
        let adaptive_method = self.options.adaptive_filter;
696
697
0
        let zlib_encoded = match self.info.compression {
698
            Compression::Fast => {
699
0
                let mut compressor = fdeflate::Compressor::new(std::io::Cursor::new(Vec::new()))?;
700
701
0
                let mut current = vec![0; in_len + 1];
702
0
                for line in data.chunks(in_len) {
703
0
                    let filter_type = filter(
704
0
                        filter_method,
705
0
                        adaptive_method,
706
0
                        bpp,
707
0
                        prev,
708
0
                        line,
709
0
                        &mut current[1..],
710
0
                    );
711
0
712
0
                    current[0] = filter_type as u8;
713
0
                    compressor.write_data(&current)?;
714
0
                    prev = line;
715
                }
716
717
0
                let compressed = compressor.finish()?.into_inner();
718
0
                if compressed.len()
719
0
                    > fdeflate::StoredOnlyCompressor::<()>::compressed_size((in_len + 1) * height)
720
                {
721
                    // Write uncompressed data since the result from fast compression would take
722
                    // more space than that.
723
                    //
724
                    // We always use FilterType::NoFilter here regardless of the filter method
725
                    // requested by the user. Doing filtering again would only add performance
726
                    // cost for both encoding and subsequent decoding, without improving the
727
                    // compression ratio.
728
0
                    let mut compressor =
729
0
                        fdeflate::StoredOnlyCompressor::new(std::io::Cursor::new(Vec::new()))?;
730
0
                    for line in data.chunks(in_len) {
731
0
                        compressor.write_data(&[0])?;
732
0
                        compressor.write_data(line)?;
733
                    }
734
0
                    compressor.finish()?.into_inner()
735
                } else {
736
0
                    compressed
737
                }
738
            }
739
            _ => {
740
0
                let mut current = vec![0; in_len];
741
0
742
0
                let mut zlib = ZlibEncoder::new(Vec::new(), self.info.compression.to_options());
743
0
                for line in data.chunks(in_len) {
744
0
                    let filter_type = filter(
745
0
                        filter_method,
746
0
                        adaptive_method,
747
0
                        bpp,
748
0
                        prev,
749
0
                        line,
750
0
                        &mut current,
751
0
                    );
752
0
753
0
                    zlib.write_all(&[filter_type as u8])?;
754
0
                    zlib.write_all(&current)?;
755
0
                    prev = line;
756
                }
757
0
                zlib.finish()?
758
            }
759
        };
760
761
0
        match self.info.frame_control {
762
            None => {
763
0
                self.write_zlib_encoded_idat(&zlib_encoded)?;
764
            }
765
0
            Some(_) if self.should_skip_frame_control_on_default_image() => {
766
0
                self.write_zlib_encoded_idat(&zlib_encoded)?;
767
            }
768
0
            Some(ref mut fctl) => {
769
0
                fctl.encode(&mut self.w)?;
770
0
                fctl.sequence_number = fctl.sequence_number.wrapping_add(1);
771
0
                self.animation_written += 1;
772
0
773
0
                // If the default image is the first frame of an animation, it's still an IDAT.
774
0
                if self.images_written == 0 {
775
0
                    self.write_zlib_encoded_idat(&zlib_encoded)?;
776
                } else {
777
0
                    let buff_size = zlib_encoded.len().min(Self::MAX_fdAT_CHUNK_LEN as usize);
778
0
                    let mut alldata = vec![0u8; 4 + buff_size];
779
0
                    for chunk in zlib_encoded.chunks(Self::MAX_fdAT_CHUNK_LEN as usize) {
780
0
                        alldata[..4].copy_from_slice(&fctl.sequence_number.to_be_bytes());
781
0
                        alldata[4..][..chunk.len()].copy_from_slice(chunk);
782
0
                        write_chunk(&mut self.w, chunk::fdAT, &alldata[..4 + chunk.len()])?;
783
0
                        fctl.sequence_number = fctl.sequence_number.wrapping_add(1);
784
                    }
785
                }
786
            }
787
        }
788
789
0
        self.increment_images_written();
790
0
791
0
        Ok(())
792
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::write_image_data
Unexecuted instantiation: <png::encoder::Writer<_>>::write_image_data
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image_data
793
794
0
    fn increment_images_written(&mut self) {
795
0
        self.images_written = self.images_written.saturating_add(1);
796
797
0
        if let Some(actl) = self.info.animation_control {
798
0
            if actl.num_frames <= self.animation_written {
799
0
                // If we've written all animation frames, all following will be normal image chunks.
800
0
                self.info.frame_control = None;
801
0
            }
802
0
        }
803
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::increment_images_written
Unexecuted instantiation: <png::encoder::Writer<_>>::increment_images_written
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::increment_images_written
804
805
0
    fn write_iend(&mut self) -> Result<()> {
806
0
        self.iend_written = true;
807
0
        self.write_chunk(chunk::IEND, &[])
808
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::write_iend
Unexecuted instantiation: <png::encoder::Writer<_>>::write_iend
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_iend
809
810
0
    fn should_skip_frame_control_on_default_image(&self) -> bool {
811
0
        self.options.sep_def_img && self.images_written == 0
812
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::should_skip_frame_control_on_default_image
Unexecuted instantiation: <png::encoder::Writer<_>>::should_skip_frame_control_on_default_image
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::should_skip_frame_control_on_default_image
813
814
0
    fn write_zlib_encoded_idat(&mut self, zlib_encoded: &[u8]) -> Result<()> {
815
0
        for chunk in zlib_encoded.chunks(Self::MAX_IDAT_CHUNK_LEN as usize) {
816
0
            self.write_chunk(chunk::IDAT, chunk)?;
817
        }
818
0
        Ok(())
819
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>>>::write_zlib_encoded_idat
Unexecuted instantiation: <png::encoder::Writer<_>>::write_zlib_encoded_idat
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_zlib_encoded_idat
820
821
    /// Set the used filter type for the following frames.
822
    ///
823
    /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
824
    /// sample values based on the previous. For a potentially better compression ratio, at the
825
    /// cost of more complex processing, try out [`FilterType::Paeth`].
826
0
    pub fn set_filter(&mut self, filter: FilterType) {
827
0
        self.options.filter = filter;
828
0
    }
829
830
    /// Set the adaptive filter type for the following frames.
831
    ///
832
    /// Adaptive filtering attempts to select the best filter for each line
833
    /// based on heuristics which minimize the file size for compression rather
834
    /// than use a single filter for the entire image. The default method is
835
    /// [`AdaptiveFilterType::NonAdaptive`].
836
0
    pub fn set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType) {
837
0
        self.options.adaptive_filter = adaptive_filter;
838
0
    }
839
840
    /// Set the fraction of time the following frames are going to be displayed,
841
    /// in seconds
842
    ///
843
    /// If the denominator is 0, it is to be treated as if it were 100
844
    /// (that is, the numerator then specifies 1/100ths of a second).
845
    /// If the value of the numerator is 0 the decoder should render the next frame
846
    /// as quickly as possible, though viewers may impose a reasonable lower bound.
847
    ///
848
    /// This method will return an error if the image is not animated.
849
0
    pub fn set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()> {
850
0
        if let Some(ref mut fctl) = self.info.frame_control {
851
0
            fctl.delay_den = denominator;
852
0
            fctl.delay_num = numerator;
853
0
            Ok(())
854
        } else {
855
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
856
        }
857
0
    }
858
859
    /// Set the dimension of the following frames.
860
    ///
861
    /// This function will return an error when:
862
    /// - The image is not an animated;
863
    ///
864
    /// - The selected dimension, considering also the current frame position,
865
    ///   goes outside the image boundaries;
866
    ///
867
    /// - One or both the width and height are 0;
868
    ///
869
    // ??? TODO ???
870
    // - The next frame is the default image
871
0
    pub fn set_frame_dimension(&mut self, width: u32, height: u32) -> Result<()> {
872
0
        if let Some(ref mut fctl) = self.info.frame_control {
873
0
            if Some(width) > self.info.width.checked_sub(fctl.x_offset)
874
0
                || Some(height) > self.info.height.checked_sub(fctl.y_offset)
875
            {
876
0
                return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
877
0
            } else if width == 0 {
878
0
                return Err(EncodingError::Format(FormatErrorKind::ZeroWidth.into()));
879
0
            } else if height == 0 {
880
0
                return Err(EncodingError::Format(FormatErrorKind::ZeroHeight.into()));
881
0
            }
882
0
            fctl.width = width;
883
0
            fctl.height = height;
884
0
            Ok(())
885
        } else {
886
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
887
        }
888
0
    }
889
890
    /// Set the position of the following frames.
891
    ///
892
    /// An error will be returned if:
893
    /// - The image is not animated;
894
    ///
895
    /// - The selected position, considering also the current frame dimension,
896
    ///   goes outside the image boundaries;
897
    ///
898
    // ??? TODO ???
899
    // - The next frame is the default image
900
0
    pub fn set_frame_position(&mut self, x: u32, y: u32) -> Result<()> {
901
0
        if let Some(ref mut fctl) = self.info.frame_control {
902
0
            if Some(x) > self.info.width.checked_sub(fctl.width)
903
0
                || Some(y) > self.info.height.checked_sub(fctl.height)
904
            {
905
0
                return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
906
0
            }
907
0
            fctl.x_offset = x;
908
0
            fctl.y_offset = y;
909
0
            Ok(())
910
        } else {
911
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
912
        }
913
0
    }
914
915
    /// Set the frame dimension to occupy all the image, starting from
916
    /// the current position.
917
    ///
918
    /// To reset the frame to the full image size [`reset_frame_position`]
919
    /// should be called first.
920
    ///
921
    /// This method will return an error if the image is not animated.
922
    ///
923
    /// [`reset_frame_position`]: Writer::reset_frame_position
924
0
    pub fn reset_frame_dimension(&mut self) -> Result<()> {
925
0
        if let Some(ref mut fctl) = self.info.frame_control {
926
0
            fctl.width = self.info.width - fctl.x_offset;
927
0
            fctl.height = self.info.height - fctl.y_offset;
928
0
            Ok(())
929
        } else {
930
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
931
        }
932
0
    }
933
934
    /// Set the frame position to (0, 0).
935
    ///
936
    /// Equivalent to calling [`set_frame_position(0, 0)`].
937
    ///
938
    /// This method will return an error if the image is not animated.
939
    ///
940
    /// [`set_frame_position(0, 0)`]: Writer::set_frame_position
941
0
    pub fn reset_frame_position(&mut self) -> Result<()> {
942
0
        if let Some(ref mut fctl) = self.info.frame_control {
943
0
            fctl.x_offset = 0;
944
0
            fctl.y_offset = 0;
945
0
            Ok(())
946
        } else {
947
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
948
        }
949
0
    }
950
951
    /// Set the blend operation for the following frames.
952
    ///
953
    /// The blend operation specifies whether the frame is to be alpha blended
954
    /// into the current output buffer content, or whether it should completely
955
    /// replace its region in the output buffer.
956
    ///
957
    /// See the [`BlendOp`] documentation for the possible values and their effects.
958
    ///
959
    /// *Note that for the first frame the two blend modes are functionally
960
    /// equivalent due to the clearing of the output buffer at the beginning
961
    /// of each play.*
962
    ///
963
    /// This method will return an error if the image is not animated.
964
0
    pub fn set_blend_op(&mut self, op: BlendOp) -> Result<()> {
965
0
        if let Some(ref mut fctl) = self.info.frame_control {
966
0
            fctl.blend_op = op;
967
0
            Ok(())
968
        } else {
969
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
970
        }
971
0
    }
972
973
    /// Set the dispose operation for the following frames.
974
    ///
975
    /// The dispose operation specifies how the output buffer should be changed
976
    /// at the end of the delay (before rendering the next frame)
977
    ///
978
    /// See the [`DisposeOp`] documentation for the possible values and their effects.
979
    ///
980
    /// *Note that if the first frame uses [`DisposeOp::Previous`]
981
    /// it will be treated as [`DisposeOp::Background`].*
982
    ///
983
    /// This method will return an error if the image is not animated.
984
0
    pub fn set_dispose_op(&mut self, op: DisposeOp) -> Result<()> {
985
0
        if let Some(ref mut fctl) = self.info.frame_control {
986
0
            fctl.dispose_op = op;
987
0
            Ok(())
988
        } else {
989
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
990
        }
991
0
    }
992
993
    /// Create a stream writer.
994
    ///
995
    /// This allows you to create images that do not fit in memory. The default
996
    /// chunk size is 4K, use `stream_writer_with_size` to set another chunk
997
    /// size.
998
    ///
999
    /// This borrows the writer which allows for manually appending additional
1000
    /// chunks after the image data has been written.
1001
0
    pub fn stream_writer(&mut self) -> Result<StreamWriter<W>> {
1002
0
        self.stream_writer_with_size(DEFAULT_BUFFER_LENGTH)
1003
0
    }
1004
1005
    /// Create a stream writer with custom buffer size.
1006
    ///
1007
    /// See [`stream_writer`].
1008
    ///
1009
    /// [`stream_writer`]: Self::stream_writer
1010
0
    pub fn stream_writer_with_size(&mut self, size: usize) -> Result<StreamWriter<W>> {
1011
0
        StreamWriter::new(ChunkOutput::Borrowed(self), size)
1012
0
    }
1013
1014
    /// Turn this into a stream writer for image data.
1015
    ///
1016
    /// This allows you to create images that do not fit in memory. The default
1017
    /// chunk size is 4K, use [`stream_writer_with_size`] to set another chunk
1018
    /// size.
1019
    ///
1020
    /// [`stream_writer_with_size`]: Self::stream_writer_with_size
1021
0
    pub fn into_stream_writer(self) -> Result<StreamWriter<'static, W>> {
1022
0
        self.into_stream_writer_with_size(DEFAULT_BUFFER_LENGTH)
1023
0
    }
1024
1025
    /// Turn this into a stream writer with custom buffer size.
1026
    ///
1027
    /// See [`into_stream_writer`].
1028
    ///
1029
    /// [`into_stream_writer`]: Self::into_stream_writer
1030
0
    pub fn into_stream_writer_with_size(self, size: usize) -> Result<StreamWriter<'static, W>> {
1031
0
        StreamWriter::new(ChunkOutput::Owned(self), size)
1032
0
    }
1033
1034
    /// Consume the stream writer with validation.
1035
    ///
1036
    /// Unlike a simple drop this ensures that the final chunk was written correctly. When other
1037
    /// validation options (chunk sequencing) had been turned on in the configuration then it will
1038
    /// also do a check on their correctness _before_ writing the final chunk.
1039
0
    pub fn finish(mut self) -> Result<()> {
1040
0
        self.validate_sequence_done()?;
1041
0
        self.write_iend()?;
1042
0
        self.w.flush()?;
1043
1044
        // Explicitly drop `self` just for clarity.
1045
0
        drop(self);
1046
0
        Ok(())
1047
0
    }
1048
}
1049
1050
impl<W: Write> Drop for Writer<W> {
1051
0
    fn drop(&mut self) {
1052
0
        if !self.iend_written {
1053
0
            let _ = self.write_iend();
1054
0
        }
1055
0
    }
Unexecuted instantiation: <png::encoder::Writer<&mut alloc::vec::Vec<u8>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <png::encoder::Writer<_> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <png::encoder::Writer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as core::ops::drop::Drop>::drop
1056
}
1057
1058
// This should be moved to Writer after `Info::encoding` is gone
1059
0
pub(crate) fn write_iccp_chunk<W: Write>(
1060
0
    w: &mut W,
1061
0
    profile_name: &str,
1062
0
    icc_profile: &[u8],
1063
0
) -> Result<()> {
1064
0
    let profile_name = encode_iso_8859_1(profile_name)?;
1065
0
    if profile_name.len() < 1 || profile_name.len() > 79 {
1066
0
        return Err(TextEncodingError::InvalidKeywordSize.into());
1067
0
    }
1068
0
1069
0
    let estimated_compressed_size = icc_profile.len() * 3 / 4;
1070
0
    let chunk_size = profile_name
1071
0
        .len()
1072
0
        .checked_add(2) // string NUL + compression type. Checked add optimizes out later Vec reallocations.
1073
0
        .and_then(|s| s.checked_add(estimated_compressed_size))
Unexecuted instantiation: png::encoder::write_iccp_chunk::<&mut &mut alloc::vec::Vec<u8>>::{closure#0}
Unexecuted instantiation: png::encoder::write_iccp_chunk::<_>::{closure#0}
Unexecuted instantiation: png::encoder::write_iccp_chunk::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}
1074
0
        .ok_or(EncodingError::LimitsExceeded)?;
1075
1076
0
    let mut data = Vec::new();
1077
0
    data.try_reserve_exact(chunk_size)
1078
0
        .map_err(|_| EncodingError::LimitsExceeded)?;
Unexecuted instantiation: png::encoder::write_iccp_chunk::<&mut &mut alloc::vec::Vec<u8>>::{closure#1}
Unexecuted instantiation: png::encoder::write_iccp_chunk::<_>::{closure#1}
Unexecuted instantiation: png::encoder::write_iccp_chunk::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}
1079
1080
0
    data.extend(profile_name.into_iter().chain([0, 0]));
1081
0
1082
0
    let mut encoder = ZlibEncoder::new(data, flate2::Compression::default());
1083
0
    encoder.write_all(icc_profile)?;
1084
1085
0
    write_chunk(w, chunk::iCCP, &encoder.finish()?)
1086
0
}
Unexecuted instantiation: png::encoder::write_iccp_chunk::<&mut &mut alloc::vec::Vec<u8>>
Unexecuted instantiation: png::encoder::write_iccp_chunk::<_>
Unexecuted instantiation: png::encoder::write_iccp_chunk::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
1087
1088
enum ChunkOutput<'a, W: Write> {
1089
    Borrowed(&'a mut Writer<W>),
1090
    Owned(Writer<W>),
1091
}
1092
1093
// opted for deref for practical reasons
1094
impl<'a, W: Write> Deref for ChunkOutput<'a, W> {
1095
    type Target = Writer<W>;
1096
1097
0
    fn deref(&self) -> &Self::Target {
1098
0
        match self {
1099
0
            ChunkOutput::Borrowed(writer) => writer,
1100
0
            ChunkOutput::Owned(writer) => writer,
1101
        }
1102
0
    }
1103
}
1104
1105
impl<'a, W: Write> DerefMut for ChunkOutput<'a, W> {
1106
0
    fn deref_mut(&mut self) -> &mut Self::Target {
1107
0
        match self {
1108
0
            ChunkOutput::Borrowed(writer) => writer,
1109
0
            ChunkOutput::Owned(writer) => writer,
1110
        }
1111
0
    }
1112
}
1113
1114
/// This writer is used between the actual writer and the
1115
/// ZlibEncoder and has the job of packaging the compressed
1116
/// data into a PNG chunk, based on the image metadata
1117
///
1118
/// Currently the way it works is that the specified buffer
1119
/// will hold one chunk at the time and buffer the incoming
1120
/// data until `flush` is called or the maximum chunk size
1121
/// is reached.
1122
///
1123
/// The maximum chunk is the smallest between the selected buffer size
1124
/// and `u32::MAX >> 1` (`0x7fffffff` or `2147483647` dec)
1125
///
1126
/// When a chunk has to be flushed the length (that is now known)
1127
/// and the CRC will be written at the correct locations in the chunk.
1128
struct ChunkWriter<'a, W: Write> {
1129
    writer: ChunkOutput<'a, W>,
1130
    buffer: Vec<u8>,
1131
    /// keeps track of where the last byte was written
1132
    index: usize,
1133
    curr_chunk: ChunkType,
1134
}
1135
1136
impl<'a, W: Write> ChunkWriter<'a, W> {
1137
0
    fn new(writer: ChunkOutput<'a, W>, buf_len: usize) -> ChunkWriter<'a, W> {
1138
        // currently buf_len will determine the size of each chunk
1139
        // the len is capped to the maximum size every chunk can hold
1140
        // (this wont ever overflow an u32)
1141
        //
1142
        // TODO (maybe): find a way to hold two chunks at a time if `usize`
1143
        //               is 64 bits.
1144
        const CAP: usize = u32::MAX as usize >> 1;
1145
0
        let curr_chunk = if writer.images_written == 0 {
1146
0
            chunk::IDAT
1147
        } else {
1148
0
            chunk::fdAT
1149
        };
1150
0
        ChunkWriter {
1151
0
            writer,
1152
0
            buffer: vec![0; CAP.min(buf_len)],
1153
0
            index: 0,
1154
0
            curr_chunk,
1155
0
        }
1156
0
    }
1157
1158
    /// Returns the size of each scanline for the next frame
1159
    /// paired with the size of the whole frame
1160
    ///
1161
    /// This is used by the `StreamWriter` to know when the scanline ends
1162
    /// so it can filter compress it and also to know when to start
1163
    /// the next one
1164
0
    fn next_frame_info(&self) -> (usize, usize) {
1165
0
        let wrt = self.writer.deref();
1166
1167
        let width: usize;
1168
        let height: usize;
1169
0
        if let Some(fctl) = wrt.info.frame_control {
1170
0
            width = fctl.width as usize;
1171
0
            height = fctl.height as usize;
1172
0
        } else {
1173
0
            width = wrt.info.width as usize;
1174
0
            height = wrt.info.height as usize;
1175
0
        }
1176
1177
0
        let in_len = wrt.info.raw_row_length_from_width(width as u32) - 1;
1178
0
        let data_size = in_len * height;
1179
0
1180
0
        (in_len, data_size)
1181
0
    }
1182
1183
    /// NOTE: this bypasses the internal buffer so the flush method should be called before this
1184
    ///       in the case there is some data left in the buffer when this is called, it will panic
1185
0
    fn write_header(&mut self) -> Result<()> {
1186
0
        assert_eq!(self.index, 0, "Called when not flushed");
1187
0
        let wrt = self.writer.deref_mut();
1188
0
1189
0
        self.curr_chunk = if wrt.images_written == 0 {
1190
0
            chunk::IDAT
1191
        } else {
1192
0
            chunk::fdAT
1193
        };
1194
1195
0
        match wrt.info.frame_control {
1196
0
            Some(_) if wrt.should_skip_frame_control_on_default_image() => {}
1197
0
            Some(ref mut fctl) => {
1198
0
                fctl.encode(&mut wrt.w)?;
1199
0
                fctl.sequence_number += 1;
1200
            }
1201
0
            _ => {}
1202
        }
1203
1204
0
        Ok(())
1205
0
    }
1206
1207
    /// Set the [`FrameControl`] for the following frame
1208
    ///
1209
    /// It will ignore the `sequence_number` of the parameter
1210
    /// as it is updated internally.
1211
0
    fn set_fctl(&mut self, f: FrameControl) {
1212
0
        if let Some(ref mut fctl) = self.writer.info.frame_control {
1213
0
            // Ignore the sequence number
1214
0
            *fctl = FrameControl {
1215
0
                sequence_number: fctl.sequence_number,
1216
0
                ..f
1217
0
            };
1218
0
        } else {
1219
0
            panic!("This function must be called on an animated PNG")
1220
        }
1221
0
    }
1222
1223
    /// Flushes the current chunk
1224
0
    fn flush_inner(&mut self) -> io::Result<()> {
1225
0
        if self.index > 0 {
1226
            // flush the chunk and reset everything
1227
0
            write_chunk(
1228
0
                &mut self.writer.w,
1229
0
                self.curr_chunk,
1230
0
                &self.buffer[..self.index],
1231
0
            )?;
1232
1233
0
            self.index = 0;
1234
0
        }
1235
0
        Ok(())
1236
0
    }
1237
}
1238
1239
impl<'a, W: Write> Write for ChunkWriter<'a, W> {
1240
0
    fn write(&mut self, mut data: &[u8]) -> io::Result<usize> {
1241
0
        if data.is_empty() {
1242
0
            return Ok(0);
1243
0
        }
1244
0
1245
0
        // index == 0 means a chunk has been flushed out
1246
0
        if self.index == 0 {
1247
0
            let wrt = self.writer.deref_mut();
1248
0
1249
0
            // Prepare the next animated frame, if any.
1250
0
            let no_fctl = wrt.should_skip_frame_control_on_default_image();
1251
0
            if wrt.info.frame_control.is_some() && !no_fctl {
1252
0
                let fctl = wrt.info.frame_control.as_mut().unwrap();
1253
0
                self.buffer[0..4].copy_from_slice(&fctl.sequence_number.to_be_bytes());
1254
0
                fctl.sequence_number += 1;
1255
0
                self.index = 4;
1256
0
            }
1257
0
        }
1258
1259
        // Cap the buffer length to the maximum number of bytes that can't still
1260
        // be added to the current chunk
1261
0
        let written = data.len().min(self.buffer.len() - self.index);
1262
0
        data = &data[..written];
1263
0
1264
0
        self.buffer[self.index..][..written].copy_from_slice(data);
1265
0
        self.index += written;
1266
0
1267
0
        // if the maximum data for this chunk as been reached it needs to be flushed
1268
0
        if self.index == self.buffer.len() {
1269
0
            self.flush_inner()?;
1270
0
        }
1271
1272
0
        Ok(written)
1273
0
    }
1274
1275
0
    fn flush(&mut self) -> io::Result<()> {
1276
0
        self.flush_inner()
1277
0
    }
1278
}
1279
1280
impl<W: Write> Drop for ChunkWriter<'_, W> {
1281
0
    fn drop(&mut self) {
1282
0
        let _ = self.flush();
1283
0
    }
1284
}
1285
1286
// TODO: find a better name
1287
//
1288
/// This enum is used to be allow the `StreamWriter` to keep
1289
/// its inner `ChunkWriter` without wrapping it inside a
1290
/// `ZlibEncoder`. This is used in the case that between the
1291
/// change of state that happens when the last write of a frame
1292
/// is performed an error occurs, which obviously has to be returned.
1293
/// This creates the problem of where to store the writer before
1294
/// exiting the function, and this is where `Wrapper` comes in.
1295
///
1296
/// Unfortunately the `ZlibWriter` can't be used because on the
1297
/// write following the error, `finish` would be called and that
1298
/// would write some data even if 0 bytes where compressed.
1299
///
1300
/// If the `finish` function fails then there is nothing much to
1301
/// do as the `ChunkWriter` would get lost so the `Unrecoverable`
1302
/// variant is used to signal that.
1303
enum Wrapper<'a, W: Write> {
1304
    Chunk(ChunkWriter<'a, W>),
1305
    Zlib(ZlibEncoder<ChunkWriter<'a, W>>),
1306
    Unrecoverable,
1307
    /// This is used in-between, should never be matched
1308
    None,
1309
}
1310
1311
impl<'a, W: Write> Wrapper<'a, W> {
1312
    /// Like `Option::take` this returns the `Wrapper` contained
1313
    /// in `self` and replaces it with `Wrapper::None`
1314
0
    fn take(&mut self) -> Wrapper<'a, W> {
1315
0
        let mut swap = Wrapper::None;
1316
0
        mem::swap(self, &mut swap);
1317
0
        swap
1318
0
    }
1319
}
1320
1321
/// Streaming PNG writer
1322
///
1323
/// This may silently fail in the destructor, so it is a good idea to call
1324
/// [`finish`] or [`flush`] before dropping.
1325
///
1326
/// [`finish`]: Self::finish
1327
/// [`flush`]: Write::flush
1328
pub struct StreamWriter<'a, W: Write> {
1329
    /// The option here is needed in order to access the inner `ChunkWriter` in-between
1330
    /// each frame, which is needed for writing the fcTL chunks between each frame
1331
    writer: Wrapper<'a, W>,
1332
    prev_buf: Vec<u8>,
1333
    curr_buf: Vec<u8>,
1334
    /// Amount of data already written
1335
    index: usize,
1336
    /// length of the current scanline
1337
    line_len: usize,
1338
    /// size of the frame (width * height * sample_size)
1339
    to_write: usize,
1340
1341
    width: u32,
1342
    height: u32,
1343
1344
    bpp: BytesPerPixel,
1345
    filter: FilterType,
1346
    adaptive_filter: AdaptiveFilterType,
1347
    fctl: Option<FrameControl>,
1348
    compression: Compression,
1349
}
1350
1351
impl<'a, W: Write> StreamWriter<'a, W> {
1352
0
    fn new(writer: ChunkOutput<'a, W>, buf_len: usize) -> Result<StreamWriter<'a, W>> {
1353
0
        let PartialInfo {
1354
0
            width,
1355
0
            height,
1356
0
            frame_control: fctl,
1357
0
            compression,
1358
0
            ..
1359
0
        } = writer.info;
1360
0
1361
0
        let bpp = writer.info.bpp_in_prediction();
1362
0
        let in_len = writer.info.raw_row_length() - 1;
1363
0
        let filter = writer.options.filter;
1364
0
        let adaptive_filter = writer.options.adaptive_filter;
1365
0
        let prev_buf = vec![0; in_len];
1366
0
        let curr_buf = vec![0; in_len];
1367
0
1368
0
        let mut chunk_writer = ChunkWriter::new(writer, buf_len);
1369
0
        let (line_len, to_write) = chunk_writer.next_frame_info();
1370
0
        chunk_writer.write_header()?;
1371
0
        let zlib = ZlibEncoder::new(chunk_writer, compression.to_options());
1372
0
1373
0
        Ok(StreamWriter {
1374
0
            writer: Wrapper::Zlib(zlib),
1375
0
            index: 0,
1376
0
            prev_buf,
1377
0
            curr_buf,
1378
0
            bpp,
1379
0
            filter,
1380
0
            width,
1381
0
            height,
1382
0
            adaptive_filter,
1383
0
            line_len,
1384
0
            to_write,
1385
0
            fctl,
1386
0
            compression,
1387
0
        })
1388
0
    }
1389
1390
    /// Set the used filter type for the next frame.
1391
    ///
1392
    /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
1393
    /// sample values based on the previous.
1394
    ///
1395
    /// For optimal compression ratio you should enable adaptive filtering
1396
    /// instead of setting a single filter for the entire image, see
1397
    /// [set_adaptive_filter](Self::set_adaptive_filter).
1398
0
    pub fn set_filter(&mut self, filter: FilterType) {
1399
0
        self.filter = filter;
1400
0
    }
1401
1402
    /// Set the adaptive filter type for the next frame.
1403
    ///
1404
    /// Adaptive filtering attempts to select the best filter for each line
1405
    /// based on heuristics which minimize the file size for compression rather
1406
    /// than use a single filter for the entire image.
1407
    ///
1408
    /// The default method is [`AdaptiveFilterType::NonAdaptive`].
1409
0
    pub fn set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType) {
1410
0
        self.adaptive_filter = adaptive_filter;
1411
0
    }
1412
1413
    /// Set the fraction of time the following frames are going to be displayed,
1414
    /// in seconds
1415
    ///
1416
    /// If the denominator is 0, it is to be treated as if it were 100
1417
    /// (that is, the numerator then specifies 1/100ths of a second).
1418
    /// If the value of the numerator is 0 the decoder should render the next frame
1419
    /// as quickly as possible, though viewers may impose a reasonable lower bound.
1420
    ///
1421
    /// This method will return an error if the image is not animated.
1422
0
    pub fn set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()> {
1423
0
        if let Some(ref mut fctl) = self.fctl {
1424
0
            fctl.delay_den = denominator;
1425
0
            fctl.delay_num = numerator;
1426
0
            Ok(())
1427
        } else {
1428
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1429
        }
1430
0
    }
1431
1432
    /// Set the dimension of the following frames.
1433
    ///
1434
    /// This function will return an error when:
1435
    /// - The image is not an animated;
1436
    ///
1437
    /// - The selected dimension, considering also the current frame position,
1438
    ///   goes outside the image boundaries;
1439
    ///
1440
    /// - One or both the width and height are 0;
1441
    ///
1442
0
    pub fn set_frame_dimension(&mut self, width: u32, height: u32) -> Result<()> {
1443
0
        if let Some(ref mut fctl) = self.fctl {
1444
0
            if Some(width) > self.width.checked_sub(fctl.x_offset)
1445
0
                || Some(height) > self.height.checked_sub(fctl.y_offset)
1446
            {
1447
0
                return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
1448
0
            } else if width == 0 {
1449
0
                return Err(EncodingError::Format(FormatErrorKind::ZeroWidth.into()));
1450
0
            } else if height == 0 {
1451
0
                return Err(EncodingError::Format(FormatErrorKind::ZeroHeight.into()));
1452
0
            }
1453
0
            fctl.width = width;
1454
0
            fctl.height = height;
1455
0
            Ok(())
1456
        } else {
1457
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1458
        }
1459
0
    }
1460
1461
    /// Set the position of the following frames.
1462
    ///
1463
    /// An error will be returned if:
1464
    /// - The image is not animated;
1465
    ///
1466
    /// - The selected position, considering also the current frame dimension,
1467
    ///   goes outside the image boundaries;
1468
    ///
1469
0
    pub fn set_frame_position(&mut self, x: u32, y: u32) -> Result<()> {
1470
0
        if let Some(ref mut fctl) = self.fctl {
1471
0
            if Some(x) > self.width.checked_sub(fctl.width)
1472
0
                || Some(y) > self.height.checked_sub(fctl.height)
1473
            {
1474
0
                return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
1475
0
            }
1476
0
            fctl.x_offset = x;
1477
0
            fctl.y_offset = y;
1478
0
            Ok(())
1479
        } else {
1480
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1481
        }
1482
0
    }
1483
1484
    /// Set the frame dimension to occupy all the image, starting from
1485
    /// the current position.
1486
    ///
1487
    /// To reset the frame to the full image size [`reset_frame_position`]
1488
    /// should be called first.
1489
    ///
1490
    /// This method will return an error if the image is not animated.
1491
    ///
1492
    /// [`reset_frame_position`]: Writer::reset_frame_position
1493
0
    pub fn reset_frame_dimension(&mut self) -> Result<()> {
1494
0
        if let Some(ref mut fctl) = self.fctl {
1495
0
            fctl.width = self.width - fctl.x_offset;
1496
0
            fctl.height = self.height - fctl.y_offset;
1497
0
            Ok(())
1498
        } else {
1499
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1500
        }
1501
0
    }
1502
1503
    /// Set the frame position to (0, 0).
1504
    ///
1505
    /// Equivalent to calling [`set_frame_position(0, 0)`].
1506
    ///
1507
    /// This method will return an error if the image is not animated.
1508
    ///
1509
    /// [`set_frame_position(0, 0)`]: Writer::set_frame_position
1510
0
    pub fn reset_frame_position(&mut self) -> Result<()> {
1511
0
        if let Some(ref mut fctl) = self.fctl {
1512
0
            fctl.x_offset = 0;
1513
0
            fctl.y_offset = 0;
1514
0
            Ok(())
1515
        } else {
1516
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1517
        }
1518
0
    }
1519
1520
    /// Set the blend operation for the following frames.
1521
    ///
1522
    /// The blend operation specifies whether the frame is to be alpha blended
1523
    /// into the current output buffer content, or whether it should completely
1524
    /// replace its region in the output buffer.
1525
    ///
1526
    /// See the [`BlendOp`] documentation for the possible values and their effects.
1527
    ///
1528
    /// *Note that for the first frame the two blend modes are functionally
1529
    /// equivalent due to the clearing of the output buffer at the beginning
1530
    /// of each play.*
1531
    ///
1532
    /// This method will return an error if the image is not animated.
1533
0
    pub fn set_blend_op(&mut self, op: BlendOp) -> Result<()> {
1534
0
        if let Some(ref mut fctl) = self.fctl {
1535
0
            fctl.blend_op = op;
1536
0
            Ok(())
1537
        } else {
1538
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1539
        }
1540
0
    }
1541
1542
    /// Set the dispose operation for the following frames.
1543
    ///
1544
    /// The dispose operation specifies how the output buffer should be changed
1545
    /// at the end of the delay (before rendering the next frame)
1546
    ///
1547
    /// See the [`DisposeOp`] documentation for the possible values and their effects.
1548
    ///
1549
    /// *Note that if the first frame uses [`DisposeOp::Previous`]
1550
    /// it will be treated as [`DisposeOp::Background`].*
1551
    ///
1552
    /// This method will return an error if the image is not animated.
1553
0
    pub fn set_dispose_op(&mut self, op: DisposeOp) -> Result<()> {
1554
0
        if let Some(ref mut fctl) = self.fctl {
1555
0
            fctl.dispose_op = op;
1556
0
            Ok(())
1557
        } else {
1558
0
            Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1559
        }
1560
0
    }
1561
1562
    /// Consume the stream writer with validation.
1563
    ///
1564
    /// Unlike a simple drop this ensures that the all data was written correctly. When other
1565
    /// validation options (chunk sequencing) had been turned on in the configuration of inner
1566
    /// [`Writer`], then it will also do a check on their correctness. Differently from
1567
    /// [`Writer::finish`], this just `flush`es, returns error if some data is abandoned.
1568
0
    pub fn finish(mut self) -> Result<()> {
1569
0
        if self.to_write > 0 {
1570
0
            let err = FormatErrorKind::MissingData(self.to_write).into();
1571
0
            return Err(EncodingError::Format(err));
1572
0
        }
1573
0
1574
0
        // TODO: call `writer.finish` somehow?
1575
0
        self.flush()?;
1576
1577
0
        if let Wrapper::Chunk(wrt) = self.writer.take() {
1578
0
            wrt.writer.validate_sequence_done()?;
1579
0
        }
1580
1581
0
        Ok(())
1582
0
    }
1583
1584
    /// Flushes the buffered chunk, checks if it was the last frame,
1585
    /// writes the next frame header and gets the next frame scanline size
1586
    /// and image size.
1587
    /// NOTE: This method must only be called when the writer is the variant Chunk(_)
1588
0
    fn new_frame(&mut self) -> Result<()> {
1589
0
        let wrt = match &mut self.writer {
1590
0
            Wrapper::Chunk(wrt) => wrt,
1591
            Wrapper::Unrecoverable => {
1592
0
                let err = FormatErrorKind::Unrecoverable.into();
1593
0
                return Err(EncodingError::Format(err));
1594
            }
1595
0
            Wrapper::Zlib(_) => unreachable!("never called on a half-finished frame"),
1596
0
            Wrapper::None => unreachable!(),
1597
        };
1598
0
        wrt.flush()?;
1599
0
        wrt.writer.validate_new_image()?;
1600
1601
0
        if let Some(fctl) = self.fctl {
1602
0
            wrt.set_fctl(fctl);
1603
0
        }
1604
0
        let (scansize, size) = wrt.next_frame_info();
1605
0
        self.line_len = scansize;
1606
0
        self.to_write = size;
1607
0
1608
0
        wrt.write_header()?;
1609
0
        wrt.writer.increment_images_written();
1610
0
1611
0
        // now it can be taken because the next statements cannot cause any errors
1612
0
        match self.writer.take() {
1613
0
            Wrapper::Chunk(wrt) => {
1614
0
                let encoder = ZlibEncoder::new(wrt, self.compression.to_options());
1615
0
                self.writer = Wrapper::Zlib(encoder);
1616
0
            }
1617
0
            _ => unreachable!(),
1618
        };
1619
1620
0
        Ok(())
1621
0
    }
1622
}
1623
1624
impl<'a, W: Write> Write for StreamWriter<'a, W> {
1625
0
    fn write(&mut self, mut data: &[u8]) -> io::Result<usize> {
1626
0
        if let Wrapper::Unrecoverable = self.writer {
1627
0
            let err = FormatErrorKind::Unrecoverable.into();
1628
0
            return Err(EncodingError::Format(err).into());
1629
0
        }
1630
0
1631
0
        if data.is_empty() {
1632
0
            return Ok(0);
1633
0
        }
1634
0
1635
0
        if self.to_write == 0 {
1636
0
            match self.writer.take() {
1637
0
                Wrapper::Zlib(wrt) => match wrt.finish() {
1638
0
                    Ok(chunk) => self.writer = Wrapper::Chunk(chunk),
1639
0
                    Err(err) => {
1640
0
                        self.writer = Wrapper::Unrecoverable;
1641
0
                        return Err(err);
1642
                    }
1643
                },
1644
0
                chunk @ Wrapper::Chunk(_) => self.writer = chunk,
1645
0
                Wrapper::Unrecoverable => unreachable!(),
1646
0
                Wrapper::None => unreachable!(),
1647
            };
1648
1649
            // Transition Wrapper::Chunk to Wrapper::Zlib.
1650
0
            self.new_frame()?;
1651
0
        }
1652
1653
0
        let written = data.read(&mut self.curr_buf[..self.line_len][self.index..])?;
1654
0
        self.index += written;
1655
0
        self.to_write -= written;
1656
0
1657
0
        if self.index == self.line_len {
1658
            // TODO: reuse this buffer between rows.
1659
0
            let mut filtered = vec![0; self.curr_buf.len()];
1660
0
            let filter_type = filter(
1661
0
                self.filter,
1662
0
                self.adaptive_filter,
1663
0
                self.bpp,
1664
0
                &self.prev_buf,
1665
0
                &self.curr_buf,
1666
0
                &mut filtered,
1667
0
            );
1668
            // This can't fail as the other variant is used only to allow the zlib encoder to finish
1669
0
            let wrt = match &mut self.writer {
1670
0
                Wrapper::Zlib(wrt) => wrt,
1671
0
                _ => unreachable!(),
1672
            };
1673
1674
0
            wrt.write_all(&[filter_type as u8])?;
1675
0
            wrt.write_all(&filtered)?;
1676
0
            mem::swap(&mut self.prev_buf, &mut self.curr_buf);
1677
0
            self.index = 0;
1678
0
        }
1679
1680
0
        Ok(written)
1681
0
    }
1682
1683
0
    fn flush(&mut self) -> io::Result<()> {
1684
0
        match &mut self.writer {
1685
0
            Wrapper::Zlib(wrt) => wrt.flush()?,
1686
0
            Wrapper::Chunk(wrt) => wrt.flush()?,
1687
            // This handles both the case where we entered an unrecoverable state after zlib
1688
            // decoding failure and after a panic while we had taken the chunk/zlib reader.
1689
            Wrapper::Unrecoverable | Wrapper::None => {
1690
0
                let err = FormatErrorKind::Unrecoverable.into();
1691
0
                return Err(EncodingError::Format(err).into());
1692
            }
1693
        }
1694
1695
0
        if self.index > 0 {
1696
0
            let err = FormatErrorKind::WrittenTooMuch(self.index).into();
1697
0
            return Err(EncodingError::Format(err).into());
1698
0
        }
1699
0
1700
0
        Ok(())
1701
0
    }
1702
}
1703
1704
impl<W: Write> Drop for StreamWriter<'_, W> {
1705
0
    fn drop(&mut self) {
1706
0
        let _ = self.flush();
1707
0
    }
1708
}
1709
1710
/// Mod to encapsulate the converters depending on the `deflate` crate.
1711
///
1712
/// Since this only contains trait impls, there is no need to make this public, they are simply
1713
/// available when the mod is compiled as well.
1714
impl Compression {
1715
0
    fn to_options(self) -> flate2::Compression {
1716
0
        #[allow(deprecated)]
1717
0
        match self {
1718
0
            Compression::Default => flate2::Compression::default(),
1719
0
            Compression::Fast => flate2::Compression::fast(),
1720
0
            Compression::Best => flate2::Compression::best(),
1721
            #[allow(deprecated)]
1722
0
            Compression::Huffman => flate2::Compression::none(),
1723
            #[allow(deprecated)]
1724
0
            Compression::Rle => flate2::Compression::none(),
1725
        }
1726
0
    }
1727
}
1728
1729
#[cfg(test)]
1730
mod tests {
1731
    use super::*;
1732
    use crate::Decoder;
1733
1734
    use rand::{thread_rng, Rng};
1735
    use std::cmp;
1736
    use std::fs::File;
1737
    use std::io::Cursor;
1738
1739
    #[test]
1740
    fn roundtrip() {
1741
        // More loops = more random testing, but also more test wait time
1742
        for _ in 0..10 {
1743
            for path in glob::glob("tests/pngsuite/*.png")
1744
                .unwrap()
1745
                .map(|r| r.unwrap())
1746
            {
1747
                if path.file_name().unwrap().to_str().unwrap().starts_with('x') {
1748
                    // x* files are expected to fail to decode
1749
                    continue;
1750
                }
1751
                eprintln!("{}", path.display());
1752
                // Decode image
1753
                let decoder = Decoder::new(File::open(path).unwrap());
1754
                let mut reader = decoder.read_info().unwrap();
1755
                let mut buf = vec![0; reader.output_buffer_size()];
1756
                let info = reader.next_frame(&mut buf).unwrap();
1757
                // Encode decoded image
1758
                let mut out = Vec::new();
1759
                {
1760
                    let mut wrapper = RandomChunkWriter {
1761
                        rng: thread_rng(),
1762
                        w: &mut out,
1763
                    };
1764
1765
                    let mut encoder = Encoder::new(&mut wrapper, info.width, info.height);
1766
                    encoder.set_color(info.color_type);
1767
                    encoder.set_depth(info.bit_depth);
1768
                    if let Some(palette) = &reader.info().palette {
1769
                        encoder.set_palette(palette.clone());
1770
                    }
1771
                    let mut encoder = encoder.write_header().unwrap();
1772
                    encoder.write_image_data(&buf).unwrap();
1773
                }
1774
                // Decode encoded decoded image
1775
                let decoder = Decoder::new(&*out);
1776
                let mut reader = decoder.read_info().unwrap();
1777
                let mut buf2 = vec![0; reader.output_buffer_size()];
1778
                reader.next_frame(&mut buf2).unwrap();
1779
                // check if the encoded image is ok:
1780
                assert_eq!(buf, buf2);
1781
            }
1782
        }
1783
    }
1784
1785
    #[test]
1786
    fn roundtrip_stream() {
1787
        // More loops = more random testing, but also more test wait time
1788
        for _ in 0..10 {
1789
            for path in glob::glob("tests/pngsuite/*.png")
1790
                .unwrap()
1791
                .map(|r| r.unwrap())
1792
            {
1793
                if path.file_name().unwrap().to_str().unwrap().starts_with('x') {
1794
                    // x* files are expected to fail to decode
1795
                    continue;
1796
                }
1797
                // Decode image
1798
                let decoder = Decoder::new(File::open(path).unwrap());
1799
                let mut reader = decoder.read_info().unwrap();
1800
                let mut buf = vec![0; reader.output_buffer_size()];
1801
                let info = reader.next_frame(&mut buf).unwrap();
1802
                // Encode decoded image
1803
                let mut out = Vec::new();
1804
                {
1805
                    let mut wrapper = RandomChunkWriter {
1806
                        rng: thread_rng(),
1807
                        w: &mut out,
1808
                    };
1809
1810
                    let mut encoder = Encoder::new(&mut wrapper, info.width, info.height);
1811
                    encoder.set_color(info.color_type);
1812
                    encoder.set_depth(info.bit_depth);
1813
                    if let Some(palette) = &reader.info().palette {
1814
                        encoder.set_palette(palette.clone());
1815
                    }
1816
                    let mut encoder = encoder.write_header().unwrap();
1817
                    let mut stream_writer = encoder.stream_writer().unwrap();
1818
1819
                    let mut outer_wrapper = RandomChunkWriter {
1820
                        rng: thread_rng(),
1821
                        w: &mut stream_writer,
1822
                    };
1823
1824
                    outer_wrapper.write_all(&buf).unwrap();
1825
                }
1826
                // Decode encoded decoded image
1827
                let decoder = Decoder::new(&*out);
1828
                let mut reader = decoder.read_info().unwrap();
1829
                let mut buf2 = vec![0; reader.output_buffer_size()];
1830
                reader.next_frame(&mut buf2).unwrap();
1831
                // check if the encoded image is ok:
1832
                assert_eq!(buf, buf2);
1833
            }
1834
        }
1835
    }
1836
1837
    #[test]
1838
    fn image_palette() -> Result<()> {
1839
        for &bit_depth in &[1u8, 2, 4, 8] {
1840
            // Do a reference decoding, choose a fitting palette image from pngsuite
1841
            let path = format!("tests/pngsuite/basn3p0{}.png", bit_depth);
1842
            let decoder = Decoder::new(File::open(&path).unwrap());
1843
            let mut reader = decoder.read_info().unwrap();
1844
1845
            let mut decoded_pixels = vec![0; reader.output_buffer_size()];
1846
            let info = reader.info();
1847
            assert_eq!(
1848
                info.width as usize * info.height as usize * usize::from(bit_depth),
1849
                decoded_pixels.len() * 8
1850
            );
1851
            let info = reader.next_frame(&mut decoded_pixels).unwrap();
1852
            let indexed_data = decoded_pixels;
1853
1854
            let palette = reader.info().palette.as_ref().unwrap();
1855
            let mut out = Vec::new();
1856
            {
1857
                let mut encoder = Encoder::new(&mut out, info.width, info.height);
1858
                encoder.set_depth(BitDepth::from_u8(bit_depth).unwrap());
1859
                encoder.set_color(ColorType::Indexed);
1860
                encoder.set_palette(palette.as_ref());
1861
1862
                let mut writer = encoder.write_header().unwrap();
1863
                writer.write_image_data(&indexed_data).unwrap();
1864
            }
1865
1866
            // Decode re-encoded image
1867
            let decoder = Decoder::new(&*out);
1868
            let mut reader = decoder.read_info().unwrap();
1869
            let mut redecoded = vec![0; reader.output_buffer_size()];
1870
            reader.next_frame(&mut redecoded).unwrap();
1871
            // check if the encoded image is ok:
1872
            assert_eq!(indexed_data, redecoded);
1873
        }
1874
        Ok(())
1875
    }
1876
1877
    #[test]
1878
    fn expect_error_on_wrong_image_len() -> Result<()> {
1879
        let width = 10;
1880
        let height = 10;
1881
1882
        let output = vec![0u8; 1024];
1883
        let writer = Cursor::new(output);
1884
        let mut encoder = Encoder::new(writer, width as u32, height as u32);
1885
        encoder.set_depth(BitDepth::Eight);
1886
        encoder.set_color(ColorType::Rgb);
1887
        let mut png_writer = encoder.write_header()?;
1888
1889
        let correct_image_size = width * height * 3;
1890
        let image = vec![0u8; correct_image_size + 1];
1891
        let result = png_writer.write_image_data(image.as_ref());
1892
        assert!(result.is_err());
1893
1894
        Ok(())
1895
    }
1896
1897
    #[test]
1898
    fn expect_error_on_empty_image() -> Result<()> {
1899
        let output = vec![0u8; 1024];
1900
        let mut writer = Cursor::new(output);
1901
1902
        let encoder = Encoder::new(&mut writer, 0, 0);
1903
        assert!(encoder.write_header().is_err());
1904
1905
        let encoder = Encoder::new(&mut writer, 100, 0);
1906
        assert!(encoder.write_header().is_err());
1907
1908
        let encoder = Encoder::new(&mut writer, 0, 100);
1909
        assert!(encoder.write_header().is_err());
1910
1911
        Ok(())
1912
    }
1913
1914
    #[test]
1915
    fn expect_error_on_invalid_bit_depth_color_type_combination() -> Result<()> {
1916
        let output = vec![0u8; 1024];
1917
        let mut writer = Cursor::new(output);
1918
1919
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1920
        encoder.set_depth(BitDepth::One);
1921
        encoder.set_color(ColorType::Rgb);
1922
        assert!(encoder.write_header().is_err());
1923
1924
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1925
        encoder.set_depth(BitDepth::One);
1926
        encoder.set_color(ColorType::GrayscaleAlpha);
1927
        assert!(encoder.write_header().is_err());
1928
1929
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1930
        encoder.set_depth(BitDepth::One);
1931
        encoder.set_color(ColorType::Rgba);
1932
        assert!(encoder.write_header().is_err());
1933
1934
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1935
        encoder.set_depth(BitDepth::Two);
1936
        encoder.set_color(ColorType::Rgb);
1937
        assert!(encoder.write_header().is_err());
1938
1939
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1940
        encoder.set_depth(BitDepth::Two);
1941
        encoder.set_color(ColorType::GrayscaleAlpha);
1942
        assert!(encoder.write_header().is_err());
1943
1944
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1945
        encoder.set_depth(BitDepth::Two);
1946
        encoder.set_color(ColorType::Rgba);
1947
        assert!(encoder.write_header().is_err());
1948
1949
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1950
        encoder.set_depth(BitDepth::Four);
1951
        encoder.set_color(ColorType::Rgb);
1952
        assert!(encoder.write_header().is_err());
1953
1954
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1955
        encoder.set_depth(BitDepth::Four);
1956
        encoder.set_color(ColorType::GrayscaleAlpha);
1957
        assert!(encoder.write_header().is_err());
1958
1959
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1960
        encoder.set_depth(BitDepth::Four);
1961
        encoder.set_color(ColorType::Rgba);
1962
        assert!(encoder.write_header().is_err());
1963
1964
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1965
        encoder.set_depth(BitDepth::Sixteen);
1966
        encoder.set_color(ColorType::Indexed);
1967
        assert!(encoder.write_header().is_err());
1968
1969
        Ok(())
1970
    }
1971
1972
    #[test]
1973
    fn can_write_header_with_valid_bit_depth_color_type_combination() -> Result<()> {
1974
        let output = vec![0u8; 1024];
1975
        let mut writer = Cursor::new(output);
1976
1977
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1978
        encoder.set_depth(BitDepth::One);
1979
        encoder.set_color(ColorType::Grayscale);
1980
        assert!(encoder.write_header().is_ok());
1981
1982
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1983
        encoder.set_depth(BitDepth::One);
1984
        encoder.set_color(ColorType::Indexed);
1985
        assert!(encoder.write_header().is_ok());
1986
1987
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1988
        encoder.set_depth(BitDepth::Two);
1989
        encoder.set_color(ColorType::Grayscale);
1990
        assert!(encoder.write_header().is_ok());
1991
1992
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1993
        encoder.set_depth(BitDepth::Two);
1994
        encoder.set_color(ColorType::Indexed);
1995
        assert!(encoder.write_header().is_ok());
1996
1997
        let mut encoder = Encoder::new(&mut writer, 1, 1);
1998
        encoder.set_depth(BitDepth::Four);
1999
        encoder.set_color(ColorType::Grayscale);
2000
        assert!(encoder.write_header().is_ok());
2001
2002
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2003
        encoder.set_depth(BitDepth::Four);
2004
        encoder.set_color(ColorType::Indexed);
2005
        assert!(encoder.write_header().is_ok());
2006
2007
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2008
        encoder.set_depth(BitDepth::Eight);
2009
        encoder.set_color(ColorType::Grayscale);
2010
        assert!(encoder.write_header().is_ok());
2011
2012
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2013
        encoder.set_depth(BitDepth::Eight);
2014
        encoder.set_color(ColorType::Rgb);
2015
        assert!(encoder.write_header().is_ok());
2016
2017
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2018
        encoder.set_depth(BitDepth::Eight);
2019
        encoder.set_color(ColorType::Indexed);
2020
        assert!(encoder.write_header().is_ok());
2021
2022
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2023
        encoder.set_depth(BitDepth::Eight);
2024
        encoder.set_color(ColorType::GrayscaleAlpha);
2025
        assert!(encoder.write_header().is_ok());
2026
2027
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2028
        encoder.set_depth(BitDepth::Eight);
2029
        encoder.set_color(ColorType::Rgba);
2030
        assert!(encoder.write_header().is_ok());
2031
2032
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2033
        encoder.set_depth(BitDepth::Sixteen);
2034
        encoder.set_color(ColorType::Grayscale);
2035
        assert!(encoder.write_header().is_ok());
2036
2037
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2038
        encoder.set_depth(BitDepth::Sixteen);
2039
        encoder.set_color(ColorType::Rgb);
2040
        assert!(encoder.write_header().is_ok());
2041
2042
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2043
        encoder.set_depth(BitDepth::Sixteen);
2044
        encoder.set_color(ColorType::GrayscaleAlpha);
2045
        assert!(encoder.write_header().is_ok());
2046
2047
        let mut encoder = Encoder::new(&mut writer, 1, 1);
2048
        encoder.set_depth(BitDepth::Sixteen);
2049
        encoder.set_color(ColorType::Rgba);
2050
        assert!(encoder.write_header().is_ok());
2051
2052
        Ok(())
2053
    }
2054
2055
    #[test]
2056
    fn all_filters_roundtrip() -> io::Result<()> {
2057
        let pixel: Vec<_> = (0..48).collect();
2058
2059
        let roundtrip = |filter: FilterType| -> io::Result<()> {
2060
            let mut buffer = vec![];
2061
            let mut encoder = Encoder::new(&mut buffer, 4, 4);
2062
            encoder.set_depth(BitDepth::Eight);
2063
            encoder.set_color(ColorType::Rgb);
2064
            encoder.set_filter(filter);
2065
            encoder.write_header()?.write_image_data(&pixel)?;
2066
2067
            let decoder = crate::Decoder::new(Cursor::new(buffer));
2068
            let mut reader = decoder.read_info()?;
2069
            let info = reader.info();
2070
            assert_eq!(info.width, 4);
2071
            assert_eq!(info.height, 4);
2072
            let mut dest = vec![0; pixel.len()];
2073
            reader.next_frame(&mut dest)?;
2074
            assert_eq!(dest, pixel, "Deviation with filter type {:?}", filter);
2075
2076
            Ok(())
2077
        };
2078
2079
        roundtrip(FilterType::NoFilter)?;
2080
        roundtrip(FilterType::Sub)?;
2081
        roundtrip(FilterType::Up)?;
2082
        roundtrip(FilterType::Avg)?;
2083
        roundtrip(FilterType::Paeth)?;
2084
2085
        Ok(())
2086
    }
2087
2088
    #[test]
2089
    fn some_gamma_roundtrip() -> io::Result<()> {
2090
        let pixel: Vec<_> = (0..48).collect();
2091
2092
        let roundtrip = |gamma: Option<ScaledFloat>| -> io::Result<()> {
2093
            let mut buffer = vec![];
2094
            let mut encoder = Encoder::new(&mut buffer, 4, 4);
2095
            encoder.set_depth(BitDepth::Eight);
2096
            encoder.set_color(ColorType::Rgb);
2097
            encoder.set_filter(FilterType::Avg);
2098
            if let Some(gamma) = gamma {
2099
                encoder.set_source_gamma(gamma);
2100
            }
2101
            encoder.write_header()?.write_image_data(&pixel)?;
2102
2103
            let decoder = crate::Decoder::new(Cursor::new(buffer));
2104
            let mut reader = decoder.read_info()?;
2105
            assert_eq!(
2106
                reader.info().source_gamma,
2107
                gamma,
2108
                "Deviation with gamma {:?}",
2109
                gamma
2110
            );
2111
            let mut dest = vec![0; pixel.len()];
2112
            let info = reader.next_frame(&mut dest)?;
2113
            assert_eq!(info.width, 4);
2114
            assert_eq!(info.height, 4);
2115
2116
            Ok(())
2117
        };
2118
2119
        roundtrip(None)?;
2120
        roundtrip(Some(ScaledFloat::new(0.35)))?;
2121
        roundtrip(Some(ScaledFloat::new(0.45)))?;
2122
        roundtrip(Some(ScaledFloat::new(0.55)))?;
2123
        roundtrip(Some(ScaledFloat::new(0.7)))?;
2124
        roundtrip(Some(ScaledFloat::new(1.0)))?;
2125
        roundtrip(Some(ScaledFloat::new(2.5)))?;
2126
2127
        Ok(())
2128
    }
2129
2130
    #[test]
2131
    fn write_image_chunks_beyond_first() -> Result<()> {
2132
        let width = 10;
2133
        let height = 10;
2134
2135
        let output = vec![0u8; 1024];
2136
        let writer = Cursor::new(output);
2137
2138
        // Not an animation but we should still be able to write multiple images
2139
        // See issue: <https://github.com/image-rs/image-png/issues/301>
2140
        // This is technically all valid png so there is no issue with correctness.
2141
        let mut encoder = Encoder::new(writer, width, height);
2142
        encoder.set_depth(BitDepth::Eight);
2143
        encoder.set_color(ColorType::Grayscale);
2144
        let mut png_writer = encoder.write_header()?;
2145
2146
        for _ in 0..3 {
2147
            let correct_image_size = (width * height) as usize;
2148
            let image = vec![0u8; correct_image_size];
2149
            png_writer.write_image_data(image.as_ref())?;
2150
        }
2151
2152
        Ok(())
2153
    }
2154
2155
    #[test]
2156
    fn image_validate_sequence_without_animation() -> Result<()> {
2157
        let width = 10;
2158
        let height = 10;
2159
2160
        let output = vec![0u8; 1024];
2161
        let writer = Cursor::new(output);
2162
2163
        let mut encoder = Encoder::new(writer, width, height);
2164
        encoder.set_depth(BitDepth::Eight);
2165
        encoder.set_color(ColorType::Grayscale);
2166
        encoder.validate_sequence(true);
2167
        let mut png_writer = encoder.write_header()?;
2168
2169
        let correct_image_size = (width * height) as usize;
2170
        let image = vec![0u8; correct_image_size];
2171
        png_writer.write_image_data(image.as_ref())?;
2172
2173
        assert!(png_writer.write_image_data(image.as_ref()).is_err());
2174
        Ok(())
2175
    }
2176
2177
    #[test]
2178
    fn image_validate_animation() -> Result<()> {
2179
        let width = 10;
2180
        let height = 10;
2181
2182
        let output = vec![0u8; 1024];
2183
        let writer = Cursor::new(output);
2184
        let correct_image_size = (width * height) as usize;
2185
        let image = vec![0u8; correct_image_size];
2186
2187
        let mut encoder = Encoder::new(writer, width, height);
2188
        encoder.set_depth(BitDepth::Eight);
2189
        encoder.set_color(ColorType::Grayscale);
2190
        encoder.set_animated(1, 0)?;
2191
        encoder.validate_sequence(true);
2192
        let mut png_writer = encoder.write_header()?;
2193
2194
        png_writer.write_image_data(image.as_ref())?;
2195
2196
        Ok(())
2197
    }
2198
2199
    #[test]
2200
    fn image_validate_animation2() -> Result<()> {
2201
        let width = 10;
2202
        let height = 10;
2203
2204
        let output = vec![0u8; 1024];
2205
        let writer = Cursor::new(output);
2206
        let correct_image_size = (width * height) as usize;
2207
        let image = vec![0u8; correct_image_size];
2208
2209
        let mut encoder = Encoder::new(writer, width, height);
2210
        encoder.set_depth(BitDepth::Eight);
2211
        encoder.set_color(ColorType::Grayscale);
2212
        encoder.set_animated(2, 0)?;
2213
        encoder.validate_sequence(true);
2214
        let mut png_writer = encoder.write_header()?;
2215
2216
        png_writer.write_image_data(image.as_ref())?;
2217
        png_writer.write_image_data(image.as_ref())?;
2218
        png_writer.finish()?;
2219
2220
        Ok(())
2221
    }
2222
2223
    #[test]
2224
    fn image_validate_animation_sep_def_image() -> Result<()> {
2225
        let width = 10;
2226
        let height = 10;
2227
2228
        let output = vec![0u8; 1024];
2229
        let writer = Cursor::new(output);
2230
        let correct_image_size = (width * height) as usize;
2231
        let image = vec![0u8; correct_image_size];
2232
2233
        let mut encoder = Encoder::new(writer, width, height);
2234
        encoder.set_depth(BitDepth::Eight);
2235
        encoder.set_color(ColorType::Grayscale);
2236
        encoder.set_animated(1, 0)?;
2237
        encoder.set_sep_def_img(true)?;
2238
        encoder.validate_sequence(true);
2239
        let mut png_writer = encoder.write_header()?;
2240
2241
        png_writer.write_image_data(image.as_ref())?;
2242
        png_writer.write_image_data(image.as_ref())?;
2243
        png_writer.finish()?;
2244
2245
        Ok(())
2246
    }
2247
2248
    #[test]
2249
    fn image_validate_missing_image() -> Result<()> {
2250
        let width = 10;
2251
        let height = 10;
2252
2253
        let output = vec![0u8; 1024];
2254
        let writer = Cursor::new(output);
2255
2256
        let mut encoder = Encoder::new(writer, width, height);
2257
        encoder.set_depth(BitDepth::Eight);
2258
        encoder.set_color(ColorType::Grayscale);
2259
        encoder.validate_sequence(true);
2260
        let png_writer = encoder.write_header()?;
2261
2262
        assert!(png_writer.finish().is_err());
2263
        Ok(())
2264
    }
2265
2266
    #[test]
2267
    fn image_validate_missing_animated_frame() -> Result<()> {
2268
        let width = 10;
2269
        let height = 10;
2270
2271
        let output = vec![0u8; 1024];
2272
        let writer = Cursor::new(output);
2273
        let correct_image_size = (width * height) as usize;
2274
        let image = vec![0u8; correct_image_size];
2275
2276
        let mut encoder = Encoder::new(writer, width, height);
2277
        encoder.set_depth(BitDepth::Eight);
2278
        encoder.set_color(ColorType::Grayscale);
2279
        encoder.set_animated(2, 0)?;
2280
        encoder.validate_sequence(true);
2281
        let mut png_writer = encoder.write_header()?;
2282
2283
        png_writer.write_image_data(image.as_ref())?;
2284
        assert!(png_writer.finish().is_err());
2285
2286
        Ok(())
2287
    }
2288
2289
    #[test]
2290
    fn issue_307_stream_validation() -> Result<()> {
2291
        let output = vec![0u8; 1024];
2292
        let mut cursor = Cursor::new(output);
2293
2294
        let encoder = Encoder::new(&mut cursor, 1, 1); // Create a 1-pixel image
2295
        let mut writer = encoder.write_header()?;
2296
        let mut stream = writer.stream_writer()?;
2297
2298
        let written = stream.write(&[1, 2, 3, 4])?;
2299
        assert_eq!(written, 1);
2300
        stream.finish()?;
2301
        drop(writer);
2302
2303
        {
2304
            cursor.set_position(0);
2305
            let mut decoder = Decoder::new(cursor).read_info().expect("A valid image");
2306
            let mut buffer = [0u8; 1];
2307
            decoder.next_frame(&mut buffer[..]).expect("Valid read");
2308
            assert_eq!(buffer, [1]);
2309
        }
2310
2311
        Ok(())
2312
    }
2313
2314
    #[test]
2315
    fn stream_filtering() -> Result<()> {
2316
        let output = vec![0u8; 1024];
2317
        let mut cursor = Cursor::new(output);
2318
2319
        let mut encoder = Encoder::new(&mut cursor, 8, 8);
2320
        encoder.set_color(ColorType::Rgba);
2321
        encoder.set_filter(FilterType::Paeth);
2322
        let mut writer = encoder.write_header()?;
2323
        let mut stream = writer.stream_writer()?;
2324
2325
        for _ in 0..8 {
2326
            let written = stream.write(&[1; 32])?;
2327
            assert_eq!(written, 32);
2328
        }
2329
        stream.finish()?;
2330
        drop(writer);
2331
2332
        {
2333
            cursor.set_position(0);
2334
            let mut decoder = Decoder::new(cursor).read_info().expect("A valid image");
2335
            let mut buffer = [0u8; 256];
2336
            decoder.next_frame(&mut buffer[..]).expect("Valid read");
2337
            assert_eq!(buffer, [1; 256]);
2338
        }
2339
2340
        Ok(())
2341
    }
2342
2343
    #[test]
2344
    #[cfg(all(unix, not(target_pointer_width = "32")))]
2345
    fn exper_error_on_huge_chunk() -> Result<()> {
2346
        // Okay, so we want a proper 4 GB chunk but not actually spend the memory for reserving it.
2347
        // Let's rely on overcommit? Otherwise we got the rather dumb option of mmap-ing /dev/zero.
2348
        let empty = vec![0; 1usize << 31];
2349
        let writer = Cursor::new(vec![0u8; 1024]);
2350
2351
        let mut encoder = Encoder::new(writer, 10, 10);
2352
        encoder.set_depth(BitDepth::Eight);
2353
        encoder.set_color(ColorType::Grayscale);
2354
        let mut png_writer = encoder.write_header()?;
2355
2356
        assert!(png_writer.write_chunk(chunk::fdAT, &empty).is_err());
2357
        Ok(())
2358
    }
2359
2360
    #[test]
2361
    #[cfg(all(unix, not(target_pointer_width = "32")))]
2362
    fn exper_error_on_non_u32_chunk() -> Result<()> {
2363
        // Okay, so we want a proper 4 GB chunk but not actually spend the memory for reserving it.
2364
        // Let's rely on overcommit? Otherwise we got the rather dumb option of mmap-ing /dev/zero.
2365
        let empty = vec![0; 1usize << 32];
2366
        let writer = Cursor::new(vec![0u8; 1024]);
2367
2368
        let mut encoder = Encoder::new(writer, 10, 10);
2369
        encoder.set_depth(BitDepth::Eight);
2370
        encoder.set_color(ColorType::Grayscale);
2371
        let mut png_writer = encoder.write_header()?;
2372
2373
        assert!(png_writer.write_chunk(chunk::fdAT, &empty).is_err());
2374
        Ok(())
2375
    }
2376
2377
    #[test]
2378
    fn finish_drops_inner_writer() -> Result<()> {
2379
        struct NoWriter<'flag>(&'flag mut bool);
2380
2381
        impl Write for NoWriter<'_> {
2382
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2383
                Ok(buf.len())
2384
            }
2385
            fn flush(&mut self) -> io::Result<()> {
2386
                Ok(())
2387
            }
2388
        }
2389
        impl Drop for NoWriter<'_> {
2390
            fn drop(&mut self) {
2391
                *self.0 = true;
2392
            }
2393
        }
2394
2395
        let mut flag = false;
2396
2397
        {
2398
            let mut encoder = Encoder::new(NoWriter(&mut flag), 10, 10);
2399
            encoder.set_depth(BitDepth::Eight);
2400
            encoder.set_color(ColorType::Grayscale);
2401
2402
            let mut writer = encoder.write_header()?;
2403
            writer.write_image_data(&[0; 100])?;
2404
            writer.finish()?;
2405
        }
2406
2407
        assert!(flag, "PNG finished but writer was not dropped");
2408
        Ok(())
2409
    }
2410
2411
    /// A Writer that only writes a few bytes at a time
2412
    struct RandomChunkWriter<R: Rng, W: Write> {
2413
        rng: R,
2414
        w: W,
2415
    }
2416
2417
    impl<R: Rng, W: Write> Write for RandomChunkWriter<R, W> {
2418
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2419
            // choose a random length to write
2420
            let len = cmp::min(self.rng.gen_range(1..50), buf.len());
2421
2422
            self.w.write(&buf[0..len])
2423
        }
2424
2425
        fn flush(&mut self) -> io::Result<()> {
2426
            self.w.flush()
2427
        }
2428
    }
2429
}