/rust/registry/src/index.crates.io-6f17d22bba15001f/png-0.17.16/src/common.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Common types shared between the encoder and decoder |
2 | | use crate::text_metadata::{EncodableTextChunk, ITXtChunk, TEXtChunk, ZTXtChunk}; |
3 | | use crate::{chunk, encoder}; |
4 | | use io::Write; |
5 | | use std::{borrow::Cow, convert::TryFrom, fmt, io}; |
6 | | |
7 | | /// Describes how a pixel is encoded. |
8 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
9 | | #[repr(u8)] |
10 | | pub enum ColorType { |
11 | | /// 1 grayscale sample. |
12 | | Grayscale = 0, |
13 | | /// 1 red sample, 1 green sample, 1 blue sample. |
14 | | Rgb = 2, |
15 | | /// 1 sample for the palette index. |
16 | | Indexed = 3, |
17 | | /// 1 grayscale sample, then 1 alpha sample. |
18 | | GrayscaleAlpha = 4, |
19 | | /// 1 red sample, 1 green sample, 1 blue sample, and finally, 1 alpha sample. |
20 | | Rgba = 6, |
21 | | } |
22 | | |
23 | | impl ColorType { |
24 | | /// Returns the number of samples used per pixel encoded in this way. |
25 | 65.7k | pub fn samples(self) -> usize { |
26 | 65.7k | self.samples_u8().into() |
27 | 65.7k | } |
28 | | |
29 | 78.4k | pub(crate) fn samples_u8(self) -> u8 { |
30 | | use self::ColorType::*; |
31 | 78.4k | match self { |
32 | 2.84k | Grayscale | Indexed => 1, |
33 | 13.7k | Rgb => 3, |
34 | 289 | GrayscaleAlpha => 2, |
35 | 61.5k | Rgba => 4, |
36 | | } |
37 | 78.4k | } |
38 | | |
39 | | /// u8 -> Self. Temporary solution until Rust provides a canonical one. |
40 | 4.25k | pub fn from_u8(n: u8) -> Option<ColorType> { |
41 | 4.25k | match n { |
42 | 735 | 0 => Some(ColorType::Grayscale), |
43 | 294 | 2 => Some(ColorType::Rgb), |
44 | 193 | 3 => Some(ColorType::Indexed), |
45 | 87 | 4 => Some(ColorType::GrayscaleAlpha), |
46 | 2.94k | 6 => Some(ColorType::Rgba), |
47 | 2 | _ => None, |
48 | | } |
49 | 4.25k | } |
50 | | |
51 | 12.6k | pub(crate) fn checked_raw_row_length(self, depth: BitDepth, width: u32) -> Option<usize> { |
52 | 12.6k | // No overflow can occur in 64 bits, we multiply 32-bit with 5 more bits. |
53 | 12.6k | let bits = u64::from(width) * u64::from(self.samples_u8()) * u64::from(depth.into_u8()); |
54 | 12.6k | TryFrom::try_from(1 + (bits + 7) / 8).ok() |
55 | 12.6k | } |
56 | | |
57 | 56.0k | pub(crate) fn raw_row_length_from_width(self, depth: BitDepth, width: u32) -> usize { |
58 | 56.0k | let samples = width as usize * self.samples(); |
59 | 56.0k | 1 + match depth { |
60 | 144 | BitDepth::Sixteen => samples * 2, |
61 | 55.8k | BitDepth::Eight => samples, |
62 | 57 | subbyte => { |
63 | 57 | let samples_per_byte = 8 / subbyte as usize; |
64 | 57 | let whole = samples / samples_per_byte; |
65 | 57 | let fract = usize::from(samples % samples_per_byte > 0); |
66 | 57 | whole + fract |
67 | | } |
68 | | } |
69 | 56.0k | } |
70 | | |
71 | 4.25k | pub(crate) fn is_combination_invalid(self, bit_depth: BitDepth) -> bool { |
72 | 4.25k | // Section 11.2.2 of the PNG standard disallows several combinations |
73 | 4.25k | // of bit depth and color type |
74 | 4.25k | ((bit_depth == BitDepth::One || bit_depth == BitDepth::Two || bit_depth == BitDepth::Four) |
75 | 590 | && (self == ColorType::Rgb |
76 | 590 | || self == ColorType::GrayscaleAlpha |
77 | 589 | || self == ColorType::Rgba)) |
78 | 4.24k | || (bit_depth == BitDepth::Sixteen && self == ColorType::Indexed) |
79 | 4.25k | } |
80 | | } |
81 | | |
82 | | /// Bit depth of the PNG file. |
83 | | /// Specifies the number of bits per sample. |
84 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
85 | | #[repr(u8)] |
86 | | pub enum BitDepth { |
87 | | One = 1, |
88 | | Two = 2, |
89 | | Four = 4, |
90 | | Eight = 8, |
91 | | Sixteen = 16, |
92 | | } |
93 | | |
94 | | /// Internal count of bytes per pixel. |
95 | | /// This is used for filtering which never uses sub-byte units. This essentially reduces the number |
96 | | /// of possible byte chunk lengths to a very small set of values appropriate to be defined as an |
97 | | /// enum. |
98 | | #[derive(Debug, Clone, Copy)] |
99 | | #[repr(u8)] |
100 | | pub(crate) enum BytesPerPixel { |
101 | | One = 1, |
102 | | Two = 2, |
103 | | Three = 3, |
104 | | Four = 4, |
105 | | Six = 6, |
106 | | Eight = 8, |
107 | | } |
108 | | |
109 | | impl BitDepth { |
110 | | /// u8 -> Self. Temporary solution until Rust provides a canonical one. |
111 | 44.0k | pub fn from_u8(n: u8) -> Option<BitDepth> { |
112 | 44.0k | match n { |
113 | 146 | 1 => Some(BitDepth::One), |
114 | 276 | 2 => Some(BitDepth::Two), |
115 | 174 | 4 => Some(BitDepth::Four), |
116 | 42.9k | 8 => Some(BitDepth::Eight), |
117 | 557 | 16 => Some(BitDepth::Sixteen), |
118 | 20 | _ => None, |
119 | | } |
120 | 44.0k | } |
121 | | |
122 | 12.6k | pub(crate) fn into_u8(self) -> u8 { |
123 | 12.6k | self as u8 |
124 | 12.6k | } |
125 | | } |
126 | | |
127 | | /// Pixel dimensions information |
128 | | #[derive(Clone, Copy, Debug)] |
129 | | pub struct PixelDimensions { |
130 | | /// Pixels per unit, X axis |
131 | | pub xppu: u32, |
132 | | /// Pixels per unit, Y axis |
133 | | pub yppu: u32, |
134 | | /// Either *Meter* or *Unspecified* |
135 | | pub unit: Unit, |
136 | | } |
137 | | |
138 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
139 | | #[repr(u8)] |
140 | | /// Physical unit of the pixel dimensions |
141 | | pub enum Unit { |
142 | | Unspecified = 0, |
143 | | Meter = 1, |
144 | | } |
145 | | |
146 | | impl Unit { |
147 | | /// u8 -> Self. Temporary solution until Rust provides a canonical one. |
148 | 3 | pub fn from_u8(n: u8) -> Option<Unit> { |
149 | 3 | match n { |
150 | 2 | 0 => Some(Unit::Unspecified), |
151 | 0 | 1 => Some(Unit::Meter), |
152 | 1 | _ => None, |
153 | | } |
154 | 3 | } |
155 | | } |
156 | | |
157 | | /// How to reset buffer of an animated png (APNG) at the end of a frame. |
158 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
159 | | #[repr(u8)] |
160 | | pub enum DisposeOp { |
161 | | /// Leave the buffer unchanged. |
162 | | None = 0, |
163 | | /// Clear buffer with the background color. |
164 | | Background = 1, |
165 | | /// Reset the buffer to the state before the current frame. |
166 | | Previous = 2, |
167 | | } |
168 | | |
169 | | impl DisposeOp { |
170 | | /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. |
171 | 175 | pub fn from_u8(n: u8) -> Option<DisposeOp> { |
172 | 175 | match n { |
173 | 163 | 0 => Some(DisposeOp::None), |
174 | 3 | 1 => Some(DisposeOp::Background), |
175 | 8 | 2 => Some(DisposeOp::Previous), |
176 | 1 | _ => None, |
177 | | } |
178 | 175 | } |
179 | | } |
180 | | |
181 | | impl fmt::Display for DisposeOp { |
182 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
183 | 0 | let name = match *self { |
184 | 0 | DisposeOp::None => "DISPOSE_OP_NONE", |
185 | 0 | DisposeOp::Background => "DISPOSE_OP_BACKGROUND", |
186 | 0 | DisposeOp::Previous => "DISPOSE_OP_PREVIOUS", |
187 | | }; |
188 | 0 | write!(f, "{}", name) |
189 | 0 | } |
190 | | } |
191 | | |
192 | | /// How pixels are written into the buffer. |
193 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
194 | | #[repr(u8)] |
195 | | pub enum BlendOp { |
196 | | /// Pixels overwrite the value at their position. |
197 | | Source = 0, |
198 | | /// The new pixels are blended into the current state based on alpha. |
199 | | Over = 1, |
200 | | } |
201 | | |
202 | | impl BlendOp { |
203 | | /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. |
204 | 173 | pub fn from_u8(n: u8) -> Option<BlendOp> { |
205 | 173 | match n { |
206 | 126 | 0 => Some(BlendOp::Source), |
207 | 42 | 1 => Some(BlendOp::Over), |
208 | 5 | _ => None, |
209 | | } |
210 | 173 | } |
211 | | } |
212 | | |
213 | | impl fmt::Display for BlendOp { |
214 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
215 | 0 | let name = match *self { |
216 | 0 | BlendOp::Source => "BLEND_OP_SOURCE", |
217 | 0 | BlendOp::Over => "BLEND_OP_OVER", |
218 | | }; |
219 | 0 | write!(f, "{}", name) |
220 | 0 | } |
221 | | } |
222 | | |
223 | | /// Frame control information |
224 | | #[derive(Clone, Copy, Debug)] |
225 | | pub struct FrameControl { |
226 | | /// Sequence number of the animation chunk, starting from 0 |
227 | | pub sequence_number: u32, |
228 | | /// Width of the following frame |
229 | | pub width: u32, |
230 | | /// Height of the following frame |
231 | | pub height: u32, |
232 | | /// X position at which to render the following frame |
233 | | pub x_offset: u32, |
234 | | /// Y position at which to render the following frame |
235 | | pub y_offset: u32, |
236 | | /// Frame delay fraction numerator |
237 | | pub delay_num: u16, |
238 | | /// Frame delay fraction denominator |
239 | | pub delay_den: u16, |
240 | | /// Type of frame area disposal to be done after rendering this frame |
241 | | pub dispose_op: DisposeOp, |
242 | | /// Type of frame area rendering for this frame |
243 | | pub blend_op: BlendOp, |
244 | | } |
245 | | |
246 | | impl Default for FrameControl { |
247 | 0 | fn default() -> FrameControl { |
248 | 0 | FrameControl { |
249 | 0 | sequence_number: 0, |
250 | 0 | width: 0, |
251 | 0 | height: 0, |
252 | 0 | x_offset: 0, |
253 | 0 | y_offset: 0, |
254 | 0 | delay_num: 1, |
255 | 0 | delay_den: 30, |
256 | 0 | dispose_op: DisposeOp::None, |
257 | 0 | blend_op: BlendOp::Source, |
258 | 0 | } |
259 | 0 | } |
260 | | } |
261 | | |
262 | | impl FrameControl { |
263 | 0 | pub fn set_seq_num(&mut self, s: u32) { |
264 | 0 | self.sequence_number = s; |
265 | 0 | } |
266 | | |
267 | 0 | pub fn inc_seq_num(&mut self, i: u32) { |
268 | 0 | self.sequence_number += i; |
269 | 0 | } |
270 | | |
271 | 0 | pub fn encode<W: Write>(self, w: &mut W) -> encoder::Result<()> { |
272 | 0 | let mut data = [0u8; 26]; |
273 | 0 | data[..4].copy_from_slice(&self.sequence_number.to_be_bytes()); |
274 | 0 | data[4..8].copy_from_slice(&self.width.to_be_bytes()); |
275 | 0 | data[8..12].copy_from_slice(&self.height.to_be_bytes()); |
276 | 0 | data[12..16].copy_from_slice(&self.x_offset.to_be_bytes()); |
277 | 0 | data[16..20].copy_from_slice(&self.y_offset.to_be_bytes()); |
278 | 0 | data[20..22].copy_from_slice(&self.delay_num.to_be_bytes()); |
279 | 0 | data[22..24].copy_from_slice(&self.delay_den.to_be_bytes()); |
280 | 0 | data[24] = self.dispose_op as u8; |
281 | 0 | data[25] = self.blend_op as u8; |
282 | 0 |
|
283 | 0 | encoder::write_chunk(w, chunk::fcTL, &data) |
284 | 0 | } Unexecuted instantiation: <png::common::FrameControl>::encode::<&mut alloc::vec::Vec<u8>> Unexecuted instantiation: <png::common::FrameControl>::encode::<_> Unexecuted instantiation: <png::common::FrameControl>::encode::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
285 | | } |
286 | | |
287 | | /// Animation control information |
288 | | #[derive(Clone, Copy, Debug)] |
289 | | pub struct AnimationControl { |
290 | | /// Number of frames |
291 | | pub num_frames: u32, |
292 | | /// Number of times to loop this APNG. 0 indicates infinite looping. |
293 | | pub num_plays: u32, |
294 | | } |
295 | | |
296 | | impl AnimationControl { |
297 | 0 | pub fn encode<W: Write>(self, w: &mut W) -> encoder::Result<()> { |
298 | 0 | let mut data = [0; 8]; |
299 | 0 | data[..4].copy_from_slice(&self.num_frames.to_be_bytes()); |
300 | 0 | data[4..].copy_from_slice(&self.num_plays.to_be_bytes()); |
301 | 0 | encoder::write_chunk(w, chunk::acTL, &data) |
302 | 0 | } Unexecuted instantiation: <png::common::AnimationControl>::encode::<&mut &mut alloc::vec::Vec<u8>> Unexecuted instantiation: <png::common::AnimationControl>::encode::<_> Unexecuted instantiation: <png::common::AnimationControl>::encode::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
303 | | } |
304 | | |
305 | | /// The type and strength of applied compression. |
306 | | #[derive(Debug, Clone, Copy)] |
307 | | pub enum Compression { |
308 | | /// Default level |
309 | | Default, |
310 | | /// Fast minimal compression |
311 | | Fast, |
312 | | /// Higher compression level |
313 | | /// |
314 | | /// Best in this context isn't actually the highest possible level |
315 | | /// the encoder can do, but is meant to emulate the `Best` setting in the `Flate2` |
316 | | /// library. |
317 | | Best, |
318 | | #[deprecated( |
319 | | since = "0.17.6", |
320 | | note = "use one of the other compression levels instead, such as 'fast'" |
321 | | )] |
322 | | Huffman, |
323 | | #[deprecated( |
324 | | since = "0.17.6", |
325 | | note = "use one of the other compression levels instead, such as 'fast'" |
326 | | )] |
327 | | Rle, |
328 | | } |
329 | | |
330 | | impl Default for Compression { |
331 | 0 | fn default() -> Self { |
332 | 0 | Self::Default |
333 | 0 | } |
334 | | } |
335 | | |
336 | | /// An unsigned integer scaled version of a floating point value, |
337 | | /// equivalent to an integer quotient with fixed denominator (100_000)). |
338 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
339 | | pub struct ScaledFloat(u32); |
340 | | |
341 | | impl ScaledFloat { |
342 | | const SCALING: f32 = 100_000.0; |
343 | | |
344 | | /// Gets whether the value is within the clamped range of this type. |
345 | 0 | pub fn in_range(value: f32) -> bool { |
346 | 0 | value >= 0.0 && (value * Self::SCALING).floor() <= u32::MAX as f32 |
347 | 0 | } |
348 | | |
349 | | /// Gets whether the value can be exactly converted in round-trip. |
350 | | #[allow(clippy::float_cmp)] // Stupid tool, the exact float compare is _the entire point_. |
351 | 0 | pub fn exact(value: f32) -> bool { |
352 | 0 | let there = Self::forward(value); |
353 | 0 | let back = Self::reverse(there); |
354 | 0 | value == back |
355 | 0 | } |
356 | | |
357 | 0 | fn forward(value: f32) -> u32 { |
358 | 0 | (value.max(0.0) * Self::SCALING).floor() as u32 |
359 | 0 | } |
360 | | |
361 | 0 | fn reverse(encoded: u32) -> f32 { |
362 | 0 | encoded as f32 / Self::SCALING |
363 | 0 | } |
364 | | |
365 | | /// Slightly inaccurate scaling and quantization. |
366 | | /// Clamps the value into the representable range if it is negative or too large. |
367 | 0 | pub fn new(value: f32) -> Self { |
368 | 0 | Self(Self::forward(value)) |
369 | 0 | } |
370 | | |
371 | | /// Fully accurate construction from a value scaled as per specification. |
372 | 802 | pub fn from_scaled(val: u32) -> Self { |
373 | 802 | Self(val) |
374 | 802 | } |
375 | | |
376 | | /// Get the accurate encoded value. |
377 | 0 | pub fn into_scaled(self) -> u32 { |
378 | 0 | self.0 |
379 | 0 | } |
380 | | |
381 | | /// Get the unscaled value as a floating point. |
382 | 0 | pub fn into_value(self) -> f32 { |
383 | 0 | Self::reverse(self.0) |
384 | 0 | } |
385 | | |
386 | 0 | pub(crate) fn encode_gama<W: Write>(self, w: &mut W) -> encoder::Result<()> { |
387 | 0 | encoder::write_chunk(w, chunk::gAMA, &self.into_scaled().to_be_bytes()) |
388 | 0 | } Unexecuted instantiation: <png::common::ScaledFloat>::encode_gama::<&mut &mut alloc::vec::Vec<u8>> Unexecuted instantiation: <png::common::ScaledFloat>::encode_gama::<_> Unexecuted instantiation: <png::common::ScaledFloat>::encode_gama::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
389 | | } |
390 | | |
391 | | /// Chromaticities of the color space primaries |
392 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
393 | | pub struct SourceChromaticities { |
394 | | pub white: (ScaledFloat, ScaledFloat), |
395 | | pub red: (ScaledFloat, ScaledFloat), |
396 | | pub green: (ScaledFloat, ScaledFloat), |
397 | | pub blue: (ScaledFloat, ScaledFloat), |
398 | | } |
399 | | |
400 | | impl SourceChromaticities { |
401 | 0 | pub fn new(white: (f32, f32), red: (f32, f32), green: (f32, f32), blue: (f32, f32)) -> Self { |
402 | 0 | SourceChromaticities { |
403 | 0 | white: (ScaledFloat::new(white.0), ScaledFloat::new(white.1)), |
404 | 0 | red: (ScaledFloat::new(red.0), ScaledFloat::new(red.1)), |
405 | 0 | green: (ScaledFloat::new(green.0), ScaledFloat::new(green.1)), |
406 | 0 | blue: (ScaledFloat::new(blue.0), ScaledFloat::new(blue.1)), |
407 | 0 | } |
408 | 0 | } |
409 | | |
410 | | #[rustfmt::skip] |
411 | 0 | pub fn to_be_bytes(self) -> [u8; 32] { |
412 | 0 | let white_x = self.white.0.into_scaled().to_be_bytes(); |
413 | 0 | let white_y = self.white.1.into_scaled().to_be_bytes(); |
414 | 0 | let red_x = self.red.0.into_scaled().to_be_bytes(); |
415 | 0 | let red_y = self.red.1.into_scaled().to_be_bytes(); |
416 | 0 | let green_x = self.green.0.into_scaled().to_be_bytes(); |
417 | 0 | let green_y = self.green.1.into_scaled().to_be_bytes(); |
418 | 0 | let blue_x = self.blue.0.into_scaled().to_be_bytes(); |
419 | 0 | let blue_y = self.blue.1.into_scaled().to_be_bytes(); |
420 | 0 | [ |
421 | 0 | white_x[0], white_x[1], white_x[2], white_x[3], |
422 | 0 | white_y[0], white_y[1], white_y[2], white_y[3], |
423 | 0 | red_x[0], red_x[1], red_x[2], red_x[3], |
424 | 0 | red_y[0], red_y[1], red_y[2], red_y[3], |
425 | 0 | green_x[0], green_x[1], green_x[2], green_x[3], |
426 | 0 | green_y[0], green_y[1], green_y[2], green_y[3], |
427 | 0 | blue_x[0], blue_x[1], blue_x[2], blue_x[3], |
428 | 0 | blue_y[0], blue_y[1], blue_y[2], blue_y[3], |
429 | 0 | ] |
430 | 0 | } |
431 | | |
432 | 0 | pub fn encode<W: Write>(self, w: &mut W) -> encoder::Result<()> { |
433 | 0 | encoder::write_chunk(w, chunk::cHRM, &self.to_be_bytes()) |
434 | 0 | } Unexecuted instantiation: <png::common::SourceChromaticities>::encode::<&mut &mut alloc::vec::Vec<u8>> Unexecuted instantiation: <png::common::SourceChromaticities>::encode::<_> Unexecuted instantiation: <png::common::SourceChromaticities>::encode::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
435 | | } |
436 | | |
437 | | /// The rendering intent for an sRGB image. |
438 | | /// |
439 | | /// Presence of this data also indicates that the image conforms to the sRGB color space. |
440 | | #[repr(u8)] |
441 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
442 | | pub enum SrgbRenderingIntent { |
443 | | /// For images preferring good adaptation to the output device gamut at the expense of colorimetric accuracy, such as photographs. |
444 | | Perceptual = 0, |
445 | | /// For images requiring colour appearance matching (relative to the output device white point), such as logos. |
446 | | RelativeColorimetric = 1, |
447 | | /// For images preferring preservation of saturation at the expense of hue and lightness, such as charts and graphs. |
448 | | Saturation = 2, |
449 | | /// For images requiring preservation of absolute colorimetry, such as previews of images destined for a different output device (proofs). |
450 | | AbsoluteColorimetric = 3, |
451 | | } |
452 | | |
453 | | impl SrgbRenderingIntent { |
454 | 0 | pub(crate) fn into_raw(self) -> u8 { |
455 | 0 | self as u8 |
456 | 0 | } |
457 | | |
458 | 6 | pub(crate) fn from_raw(raw: u8) -> Option<Self> { |
459 | 6 | match raw { |
460 | 2 | 0 => Some(SrgbRenderingIntent::Perceptual), |
461 | 3 | 1 => Some(SrgbRenderingIntent::RelativeColorimetric), |
462 | 0 | 2 => Some(SrgbRenderingIntent::Saturation), |
463 | 0 | 3 => Some(SrgbRenderingIntent::AbsoluteColorimetric), |
464 | 1 | _ => None, |
465 | | } |
466 | 6 | } |
467 | | |
468 | 0 | pub fn encode<W: Write>(self, w: &mut W) -> encoder::Result<()> { |
469 | 0 | encoder::write_chunk(w, chunk::sRGB, &[self.into_raw()]) |
470 | 0 | } Unexecuted instantiation: <png::common::SrgbRenderingIntent>::encode::<&mut &mut alloc::vec::Vec<u8>> Unexecuted instantiation: <png::common::SrgbRenderingIntent>::encode::<_> Unexecuted instantiation: <png::common::SrgbRenderingIntent>::encode::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
471 | | } |
472 | | |
473 | | /// Coding-independent code points (cICP) specify the color space (primaries), |
474 | | /// transfer function, matrix coefficients and scaling factor of the image using |
475 | | /// the code points specified in [ITU-T-H.273](https://www.itu.int/rec/T-REC-H.273). |
476 | | /// |
477 | | /// See https://www.w3.org/TR/png-3/#cICP-chunk for more details. |
478 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
479 | | pub struct CodingIndependentCodePoints { |
480 | | /// Id number of the color primaries defined in |
481 | | /// [ITU-T-H.273](https://www.itu.int/rec/T-REC-H.273) in "Table 2 - |
482 | | /// Interpretation of colour primaries (ColourPrimaries) value". |
483 | | pub color_primaries: u8, |
484 | | |
485 | | /// Id number of the transfer characteristics defined in |
486 | | /// [ITU-T-H.273](https://www.itu.int/rec/T-REC-H.273) in "Table 3 - |
487 | | /// Interpretation of transfer characteristics (TransferCharacteristics) |
488 | | /// value". |
489 | | pub transfer_function: u8, |
490 | | |
491 | | /// Id number of the matrix coefficients defined in |
492 | | /// [ITU-T-H.273](https://www.itu.int/rec/T-REC-H.273) in "Table 4 - |
493 | | /// Interpretation of matrix coefficients (MatrixCoefficients) value". |
494 | | /// |
495 | | /// This field is included to faithfully replicate the base |
496 | | /// [ITU-T-H.273](https://www.itu.int/rec/T-REC-H.273) specification, but matrix coefficients |
497 | | /// will always be set to 0, because RGB is currently the only supported color mode in PNG. |
498 | | pub matrix_coefficients: u8, |
499 | | |
500 | | /// Whether the image is |
501 | | /// [a full range image](https://www.w3.org/TR/png-3/#dfn-full-range-image) |
502 | | /// or |
503 | | /// [a narrow range image](https://www.w3.org/TR/png-3/#dfn-narrow-range-image). |
504 | | /// |
505 | | /// This field is included to faithfully replicate the base |
506 | | /// [ITU-T-H.273](https://www.itu.int/rec/T-REC-H.273) specification, but it has limited |
507 | | /// practical application to PNG images, because narrow-range images are [quite |
508 | | /// rare](https://github.com/w3c/png/issues/312#issuecomment-2327349614) in practice. |
509 | | pub is_video_full_range_image: bool, |
510 | | } |
511 | | |
512 | | /// Mastering Display Color Volume (mDCV) used at the point of content creation, |
513 | | /// as specified in [SMPTE-ST-2086](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8353899). |
514 | | /// |
515 | | /// See https://www.w3.org/TR/png-3/#mDCV-chunk for more details. |
516 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
517 | | pub struct MasteringDisplayColorVolume { |
518 | | /// Mastering display chromaticities. |
519 | | pub chromaticities: SourceChromaticities, |
520 | | |
521 | | /// Mastering display maximum luminance. |
522 | | /// |
523 | | /// The value is expressed in units of 0.0001 cd/m^2 - for example if this field |
524 | | /// is set to `10000000` then it indicates 1000 cd/m^2. |
525 | | pub max_luminance: u32, |
526 | | |
527 | | /// Mastering display minimum luminance. |
528 | | /// |
529 | | /// The value is expressed in units of 0.0001 cd/m^2 - for example if this field |
530 | | /// is set to `10000000` then it indicates 1000 cd/m^2. |
531 | | pub min_luminance: u32, |
532 | | } |
533 | | |
534 | | /// Content light level information of HDR content. |
535 | | /// |
536 | | /// See https://www.w3.org/TR/png-3/#cLLI-chunk for more details. |
537 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
538 | | pub struct ContentLightLevelInfo { |
539 | | /// Maximum Content Light Level indicates the maximum light level of any |
540 | | /// single pixel (in cd/m^2, also known as nits) of the entire playback |
541 | | /// sequence. |
542 | | /// |
543 | | /// The value is expressed in units of 0.0001 cd/m^2 - for example if this field |
544 | | /// is set to `10000000` then it indicates 1000 cd/m^2. |
545 | | /// |
546 | | /// A value of zero means that the value is unknown or not currently calculable. |
547 | | pub max_content_light_level: u32, |
548 | | |
549 | | /// Maximum Frame Average Light Level indicates the maximum value of the |
550 | | /// frame average light level (in cd/m^2, also known as nits) of the entire |
551 | | /// playback sequence. It is calculated by first averaging the decoded |
552 | | /// luminance values of all the pixels in each frame, and then using the |
553 | | /// value for the frame with the highest value. |
554 | | /// |
555 | | /// The value is expressed in units of 0.0001 cd/m^2 - for example if this field |
556 | | /// is set to `10000000` then it indicates 1000 cd/m^2. |
557 | | /// |
558 | | /// A value of zero means that the value is unknown or not currently calculable. |
559 | | pub max_frame_average_light_level: u32, |
560 | | } |
561 | | |
562 | | /// PNG info struct |
563 | | #[derive(Clone, Debug)] |
564 | | #[non_exhaustive] |
565 | | pub struct Info<'a> { |
566 | | pub width: u32, |
567 | | pub height: u32, |
568 | | pub bit_depth: BitDepth, |
569 | | /// How colors are stored in the image. |
570 | | pub color_type: ColorType, |
571 | | pub interlaced: bool, |
572 | | /// The image's `sBIT` chunk, if present; contains significant bits of the sample. |
573 | | pub sbit: Option<Cow<'a, [u8]>>, |
574 | | /// The image's `tRNS` chunk, if present; contains the alpha channel of the image's palette, 1 byte per entry. |
575 | | pub trns: Option<Cow<'a, [u8]>>, |
576 | | pub pixel_dims: Option<PixelDimensions>, |
577 | | /// The image's `PLTE` chunk, if present; contains the RGB channels (in that order) of the image's palettes, 3 bytes per entry (1 per channel). |
578 | | pub palette: Option<Cow<'a, [u8]>>, |
579 | | /// The contents of the image's gAMA chunk, if present. |
580 | | /// Prefer `source_gamma` to also get the derived replacement gamma from sRGB chunks. |
581 | | pub gama_chunk: Option<ScaledFloat>, |
582 | | /// The contents of the image's `cHRM` chunk, if present. |
583 | | /// Prefer `source_chromaticities` to also get the derived replacements from sRGB chunks. |
584 | | pub chrm_chunk: Option<SourceChromaticities>, |
585 | | /// The contents of the image's `bKGD` chunk, if present. |
586 | | pub bkgd: Option<Cow<'a, [u8]>>, |
587 | | |
588 | | pub frame_control: Option<FrameControl>, |
589 | | pub animation_control: Option<AnimationControl>, |
590 | | pub compression: Compression, |
591 | | /// Gamma of the source system. |
592 | | /// Set by both `gAMA` as well as to a replacement by `sRGB` chunk. |
593 | | pub source_gamma: Option<ScaledFloat>, |
594 | | /// Chromaticities of the source system. |
595 | | /// Set by both `cHRM` as well as to a replacement by `sRGB` chunk. |
596 | | pub source_chromaticities: Option<SourceChromaticities>, |
597 | | /// The rendering intent of an SRGB image. |
598 | | /// |
599 | | /// Presence of this value also indicates that the image conforms to the SRGB color space. |
600 | | pub srgb: Option<SrgbRenderingIntent>, |
601 | | /// The ICC profile for the image. |
602 | | pub icc_profile: Option<Cow<'a, [u8]>>, |
603 | | /// The coding-independent code points for video signal type identification of the image. |
604 | | pub coding_independent_code_points: Option<CodingIndependentCodePoints>, |
605 | | /// The mastering display color volume for the image. |
606 | | pub mastering_display_color_volume: Option<MasteringDisplayColorVolume>, |
607 | | /// The content light information for the image. |
608 | | pub content_light_level: Option<ContentLightLevelInfo>, |
609 | | /// The EXIF metadata for the image. |
610 | | pub exif_metadata: Option<Cow<'a, [u8]>>, |
611 | | /// tEXt field |
612 | | pub uncompressed_latin1_text: Vec<TEXtChunk>, |
613 | | /// zTXt field |
614 | | pub compressed_latin1_text: Vec<ZTXtChunk>, |
615 | | /// iTXt field |
616 | | pub utf8_text: Vec<ITXtChunk>, |
617 | | } |
618 | | |
619 | | impl Default for Info<'_> { |
620 | 4.22k | fn default() -> Info<'static> { |
621 | 4.22k | Info { |
622 | 4.22k | width: 0, |
623 | 4.22k | height: 0, |
624 | 4.22k | bit_depth: BitDepth::Eight, |
625 | 4.22k | color_type: ColorType::Grayscale, |
626 | 4.22k | interlaced: false, |
627 | 4.22k | palette: None, |
628 | 4.22k | sbit: None, |
629 | 4.22k | trns: None, |
630 | 4.22k | gama_chunk: None, |
631 | 4.22k | chrm_chunk: None, |
632 | 4.22k | bkgd: None, |
633 | 4.22k | pixel_dims: None, |
634 | 4.22k | frame_control: None, |
635 | 4.22k | animation_control: None, |
636 | 4.22k | // Default to `deflate::Compression::Fast` and `filter::FilterType::Sub` |
637 | 4.22k | // to maintain backward compatible output. |
638 | 4.22k | compression: Compression::Fast, |
639 | 4.22k | source_gamma: None, |
640 | 4.22k | source_chromaticities: None, |
641 | 4.22k | srgb: None, |
642 | 4.22k | icc_profile: None, |
643 | 4.22k | coding_independent_code_points: None, |
644 | 4.22k | mastering_display_color_volume: None, |
645 | 4.22k | content_light_level: None, |
646 | 4.22k | exif_metadata: None, |
647 | 4.22k | uncompressed_latin1_text: Vec::new(), |
648 | 4.22k | compressed_latin1_text: Vec::new(), |
649 | 4.22k | utf8_text: Vec::new(), |
650 | 4.22k | } |
651 | 4.22k | } |
652 | | } |
653 | | |
654 | | impl Info<'_> { |
655 | | /// A utility constructor for a default info with width and height. |
656 | 0 | pub fn with_size(width: u32, height: u32) -> Self { |
657 | 0 | Info { |
658 | 0 | width, |
659 | 0 | height, |
660 | 0 | ..Default::default() |
661 | 0 | } |
662 | 0 | } |
663 | | |
664 | | /// Size of the image, width then height. |
665 | 23.1k | pub fn size(&self) -> (u32, u32) { |
666 | 23.1k | (self.width, self.height) |
667 | 23.1k | } |
668 | | |
669 | | /// Returns true if the image is an APNG image. |
670 | 0 | pub fn is_animated(&self) -> bool { |
671 | 0 | self.frame_control.is_some() && self.animation_control.is_some() |
672 | 0 | } |
673 | | |
674 | | /// Returns the frame control information of the image. |
675 | 0 | pub fn animation_control(&self) -> Option<&AnimationControl> { |
676 | 0 | self.animation_control.as_ref() |
677 | 0 | } |
678 | | |
679 | | /// Returns the frame control information of the current frame |
680 | 0 | pub fn frame_control(&self) -> Option<&FrameControl> { |
681 | 0 | self.frame_control.as_ref() |
682 | 0 | } |
683 | | |
684 | | /// Returns the number of bits per pixel. |
685 | 0 | pub fn bits_per_pixel(&self) -> usize { |
686 | 0 | self.color_type.samples() * self.bit_depth as usize |
687 | 0 | } |
688 | | |
689 | | /// Returns the number of bytes per pixel. |
690 | 2.49k | pub fn bytes_per_pixel(&self) -> usize { |
691 | 2.49k | // If adjusting this for expansion or other transformation passes, remember to keep the old |
692 | 2.49k | // implementation for bpp_in_prediction, which is internal to the png specification. |
693 | 2.49k | self.color_type.samples() * ((self.bit_depth as usize + 7) >> 3) |
694 | 2.49k | } |
695 | | |
696 | | /// Return the number of bytes for this pixel used in prediction. |
697 | | /// |
698 | | /// Some filters use prediction, over the raw bytes of a scanline. Where a previous pixel is |
699 | | /// require for such forms the specification instead references previous bytes. That is, for |
700 | | /// a gray pixel of bit depth 2, the pixel used in prediction is actually 4 pixels prior. This |
701 | | /// has the consequence that the number of possible values is rather small. To make this fact |
702 | | /// more obvious in the type system and the optimizer we use an explicit enum here. |
703 | 2.49k | pub(crate) fn bpp_in_prediction(&self) -> BytesPerPixel { |
704 | 2.49k | BytesPerPixel::from_usize(self.bytes_per_pixel()) |
705 | 2.49k | } |
706 | | |
707 | | /// Returns the number of bytes needed for one deinterlaced image. |
708 | 0 | pub fn raw_bytes(&self) -> usize { |
709 | 0 | self.height as usize * self.raw_row_length() |
710 | 0 | } |
711 | | |
712 | | /// Returns the number of bytes needed for one deinterlaced row. |
713 | 0 | pub fn raw_row_length(&self) -> usize { |
714 | 0 | self.raw_row_length_from_width(self.width) |
715 | 0 | } |
716 | | |
717 | 4.22k | pub(crate) fn checked_raw_row_length(&self) -> Option<usize> { |
718 | 4.22k | self.color_type |
719 | 4.22k | .checked_raw_row_length(self.bit_depth, self.width) |
720 | 4.22k | } |
721 | | |
722 | | /// Returns the number of bytes needed for one deinterlaced row of width `width`. |
723 | 25.2k | pub fn raw_row_length_from_width(&self, width: u32) -> usize { |
724 | 25.2k | self.color_type |
725 | 25.2k | .raw_row_length_from_width(self.bit_depth, width) |
726 | 25.2k | } |
727 | | |
728 | | /// Mark the image data as conforming to the SRGB color space with the specified rendering intent. |
729 | | /// |
730 | | /// Any ICC profiles will be ignored. |
731 | | /// |
732 | | /// Source gamma and chromaticities will be written only if they're set to fallback |
733 | | /// values specified in [11.3.2.5](https://www.w3.org/TR/png-3/#sRGB-gAMA-cHRM). |
734 | 0 | pub(crate) fn set_source_srgb(&mut self, rendering_intent: SrgbRenderingIntent) { |
735 | 0 | self.srgb = Some(rendering_intent); |
736 | 0 | self.icc_profile = None; |
737 | 0 | } |
738 | | |
739 | | /// Encode this header to the writer. |
740 | | /// |
741 | | /// Note that this does _not_ include the PNG signature, it starts with the IHDR chunk and then |
742 | | /// includes other chunks that were added to the header. |
743 | | #[deprecated(note = "Use Encoder+Writer instead")] |
744 | 0 | pub fn encode<W: Write>(&self, mut w: W) -> encoder::Result<()> { |
745 | 0 | // Encode the IHDR chunk |
746 | 0 | let mut data = [0; 13]; |
747 | 0 | data[..4].copy_from_slice(&self.width.to_be_bytes()); |
748 | 0 | data[4..8].copy_from_slice(&self.height.to_be_bytes()); |
749 | 0 | data[8] = self.bit_depth as u8; |
750 | 0 | data[9] = self.color_type as u8; |
751 | 0 | data[12] = self.interlaced as u8; |
752 | 0 | encoder::write_chunk(&mut w, chunk::IHDR, &data)?; |
753 | | |
754 | | // Encode the pHYs chunk |
755 | 0 | if let Some(pd) = self.pixel_dims { |
756 | 0 | let mut phys_data = [0; 9]; |
757 | 0 | phys_data[0..4].copy_from_slice(&pd.xppu.to_be_bytes()); |
758 | 0 | phys_data[4..8].copy_from_slice(&pd.yppu.to_be_bytes()); |
759 | 0 | match pd.unit { |
760 | 0 | Unit::Meter => phys_data[8] = 1, |
761 | 0 | Unit::Unspecified => phys_data[8] = 0, |
762 | | } |
763 | 0 | encoder::write_chunk(&mut w, chunk::pHYs, &phys_data)?; |
764 | 0 | } |
765 | | |
766 | | // If specified, the sRGB information overrides the source gamma and chromaticities. |
767 | 0 | if let Some(srgb) = &self.srgb { |
768 | 0 | srgb.encode(&mut w)?; |
769 | | |
770 | | // gAMA and cHRM are optional, for backwards compatibility |
771 | 0 | let srgb_gamma = crate::srgb::substitute_gamma(); |
772 | 0 | if Some(srgb_gamma) == self.source_gamma { |
773 | 0 | srgb_gamma.encode_gama(&mut w)? |
774 | 0 | } |
775 | 0 | let srgb_chromaticities = crate::srgb::substitute_chromaticities(); |
776 | 0 | if Some(srgb_chromaticities) == self.source_chromaticities { |
777 | 0 | srgb_chromaticities.encode(&mut w)?; |
778 | 0 | } |
779 | | } else { |
780 | 0 | if let Some(gma) = self.source_gamma { |
781 | 0 | gma.encode_gama(&mut w)? |
782 | 0 | } |
783 | 0 | if let Some(chrms) = self.source_chromaticities { |
784 | 0 | chrms.encode(&mut w)?; |
785 | 0 | } |
786 | 0 | if let Some(iccp) = &self.icc_profile { |
787 | 0 | encoder::write_iccp_chunk(&mut w, "_", iccp)? |
788 | 0 | } |
789 | | } |
790 | | |
791 | 0 | if let Some(exif) = &self.exif_metadata { |
792 | 0 | encoder::write_chunk(&mut w, chunk::eXIf, exif)?; |
793 | 0 | } |
794 | | |
795 | 0 | if let Some(actl) = self.animation_control { |
796 | 0 | actl.encode(&mut w)?; |
797 | 0 | } |
798 | | |
799 | | // The position of the PLTE chunk is important, it must come before the tRNS chunk and after |
800 | | // many of the other metadata chunks. |
801 | 0 | if let Some(p) = &self.palette { |
802 | 0 | encoder::write_chunk(&mut w, chunk::PLTE, p)?; |
803 | 0 | }; |
804 | | |
805 | 0 | if let Some(t) = &self.trns { |
806 | 0 | encoder::write_chunk(&mut w, chunk::tRNS, t)?; |
807 | 0 | } |
808 | | |
809 | 0 | for text_chunk in &self.uncompressed_latin1_text { |
810 | 0 | text_chunk.encode(&mut w)?; |
811 | | } |
812 | | |
813 | 0 | for text_chunk in &self.compressed_latin1_text { |
814 | 0 | text_chunk.encode(&mut w)?; |
815 | | } |
816 | | |
817 | 0 | for text_chunk in &self.utf8_text { |
818 | 0 | text_chunk.encode(&mut w)?; |
819 | | } |
820 | | |
821 | 0 | Ok(()) |
822 | 0 | } Unexecuted instantiation: <png::common::Info>::encode::<&mut &mut alloc::vec::Vec<u8>> Unexecuted instantiation: <png::common::Info>::encode::<_> Unexecuted instantiation: <png::common::Info>::encode::<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> |
823 | | } |
824 | | |
825 | | impl BytesPerPixel { |
826 | 2.49k | pub(crate) fn from_usize(bpp: usize) -> Self { |
827 | 2.49k | match bpp { |
828 | 67 | 1 => BytesPerPixel::One, |
829 | 32 | 2 => BytesPerPixel::Two, |
830 | 180 | 3 => BytesPerPixel::Three, |
831 | 2.18k | 4 => BytesPerPixel::Four, |
832 | 10 | 6 => BytesPerPixel::Six, // Only rgb×16bit |
833 | 26 | 8 => BytesPerPixel::Eight, // Only rgba×16bit |
834 | 0 | _ => unreachable!("Not a possible byte rounded pixel width"), |
835 | | } |
836 | 2.49k | } |
837 | | |
838 | 0 | pub(crate) fn into_usize(self) -> usize { |
839 | 0 | self as usize |
840 | 0 | } |
841 | | } |
842 | | |
843 | | bitflags::bitflags! { |
844 | | /// Output transformations |
845 | | /// |
846 | | /// Many flags from libpng are not yet supported. A PR discussing/adding them would be nice. |
847 | | /// |
848 | | #[doc = " |
849 | | ```c |
850 | | /// Discard the alpha channel |
851 | | const STRIP_ALPHA = 0x0002; // read only |
852 | | /// Expand 1; 2 and 4-bit samples to bytes |
853 | | const PACKING = 0x0004; // read and write |
854 | | /// Change order of packed pixels to LSB first |
855 | | const PACKSWAP = 0x0008; // read and write |
856 | | /// Invert monochrome images |
857 | | const INVERT_MONO = 0x0020; // read and write |
858 | | /// Normalize pixels to the sBIT depth |
859 | | const SHIFT = 0x0040; // read and write |
860 | | /// Flip RGB to BGR; RGBA to BGRA |
861 | | const BGR = 0x0080; // read and write |
862 | | /// Flip RGBA to ARGB or GA to AG |
863 | | const SWAP_ALPHA = 0x0100; // read and write |
864 | | /// Byte-swap 16-bit samples |
865 | | const SWAP_ENDIAN = 0x0200; // read and write |
866 | | /// Change alpha from opacity to transparency |
867 | | const INVERT_ALPHA = 0x0400; // read and write |
868 | | const STRIP_FILLER = 0x0800; // write only |
869 | | const STRIP_FILLER_BEFORE = 0x0800; // write only |
870 | | const STRIP_FILLER_AFTER = 0x1000; // write only |
871 | | const GRAY_TO_RGB = 0x2000; // read only |
872 | | const EXPAND_16 = 0x4000; // read only |
873 | | /// Similar to STRIP_16 but in libpng considering gamma? |
874 | | /// Not entirely sure the documentation says it is more |
875 | | /// accurate but doesn't say precisely how. |
876 | | const SCALE_16 = 0x8000; // read only |
877 | | ``` |
878 | | "] |
879 | | pub struct Transformations: u32 { |
880 | | /// No transformation |
881 | | const IDENTITY = 0x00000; // read and write */ |
882 | | /// Strip 16-bit samples to 8 bits |
883 | | const STRIP_16 = 0x00001; // read only */ |
884 | | /// Expand paletted images to RGB; expand grayscale images of |
885 | | /// less than 8-bit depth to 8-bit depth; and expand tRNS chunks |
886 | | /// to alpha channels. |
887 | | const EXPAND = 0x00010; // read only */ |
888 | | /// Expand paletted images to include an alpha channel. Implies `EXPAND`. |
889 | | const ALPHA = 0x10000; // read only */ |
890 | | } |
891 | | } |
892 | | |
893 | | impl Transformations { |
894 | | /// Transform every input to 8bit grayscale or color. |
895 | | /// |
896 | | /// This sets `EXPAND` and `STRIP_16` which is similar to the default transformation used by |
897 | | /// this library prior to `0.17`. |
898 | 0 | pub fn normalize_to_color8() -> Transformations { |
899 | 0 | Transformations::EXPAND | Transformations::STRIP_16 |
900 | 0 | } |
901 | | } |
902 | | |
903 | | /// Instantiate the default transformations, the identity transform. |
904 | | impl Default for Transformations { |
905 | 0 | fn default() -> Transformations { |
906 | 0 | Transformations::IDENTITY |
907 | 0 | } |
908 | | } |
909 | | |
910 | | #[derive(Debug)] |
911 | | pub struct ParameterError { |
912 | | inner: ParameterErrorKind, |
913 | | } |
914 | | |
915 | | #[derive(Debug)] |
916 | | pub(crate) enum ParameterErrorKind { |
917 | | /// A provided buffer must be have the exact size to hold the image data. Where the buffer can |
918 | | /// be allocated by the caller, they must ensure that it has a minimum size as hinted previously. |
919 | | /// Even though the size is calculated from image data, this does counts as a parameter error |
920 | | /// because they must react to a value produced by this library, which can have been subjected |
921 | | /// to limits. |
922 | | ImageBufferSize { expected: usize, actual: usize }, |
923 | | /// A bit like return `None` from an iterator. |
924 | | /// We use it to differentiate between failing to seek to the next image in a sequence and the |
925 | | /// absence of a next image. This is an error of the caller because they should have checked |
926 | | /// the number of images by inspecting the header data returned when opening the image. This |
927 | | /// library will perform the checks necessary to ensure that data was accurate or error with a |
928 | | /// format error otherwise. |
929 | | PolledAfterEndOfImage, |
930 | | /// Attempt to continue decoding after a fatal, non-resumable error was reported (e.g. after |
931 | | /// [`DecodingError::Format`]). The only case when it is possible to resume after an error |
932 | | /// is an `UnexpectedEof` scenario - see [`DecodingError::IoError`]. |
933 | | PolledAfterFatalError, |
934 | | } |
935 | | |
936 | | impl From<ParameterErrorKind> for ParameterError { |
937 | 0 | fn from(inner: ParameterErrorKind) -> Self { |
938 | 0 | ParameterError { inner } |
939 | 0 | } |
940 | | } |
941 | | |
942 | | impl fmt::Display for ParameterError { |
943 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
944 | | use ParameterErrorKind::*; |
945 | 0 | match self.inner { |
946 | 0 | ImageBufferSize { expected, actual } => { |
947 | 0 | write!(fmt, "wrong data size, expected {} got {}", expected, actual) |
948 | | } |
949 | 0 | PolledAfterEndOfImage => write!(fmt, "End of image has been reached"), |
950 | | PolledAfterFatalError => { |
951 | 0 | write!(fmt, "A fatal decoding error has been encounted earlier") |
952 | | } |
953 | | } |
954 | 0 | } |
955 | | } |