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