/src/image-png/src/decoder/interlace_info.rs
Line | Count | Source |
1 | | use std::ops::Range; |
2 | | |
3 | | use crate::adam7::{Adam7Info, Adam7Iterator}; |
4 | | |
5 | | /// Describes which interlacing algorithm applies to a decoded row. |
6 | | /// |
7 | | /// PNG (2003) specifies two interlace modes, but reserves future extensions. |
8 | | /// |
9 | | /// See also [Reader.next_interlaced_row](crate::Reader::next_interlaced_row). |
10 | | #[derive(Clone, Copy, Debug)] |
11 | | pub enum InterlaceInfo { |
12 | | /// The `null` method means no interlacing. |
13 | | Null(NullInfo), |
14 | | /// [The `Adam7` algorithm](https://en.wikipedia.org/wiki/Adam7_algorithm) derives its name |
15 | | /// from doing 7 passes over the image, only decoding a subset of all pixels in each pass. |
16 | | /// The following table shows pictorially what parts of each 8x8 area of the image is found in |
17 | | /// each pass: |
18 | | /// |
19 | | /// ```txt |
20 | | /// 1 6 4 6 2 6 4 6 |
21 | | /// 7 7 7 7 7 7 7 7 |
22 | | /// 5 6 5 6 5 6 5 6 |
23 | | /// 7 7 7 7 7 7 7 7 |
24 | | /// 3 6 4 6 3 6 4 6 |
25 | | /// 7 7 7 7 7 7 7 7 |
26 | | /// 5 6 5 6 5 6 5 6 |
27 | | /// 7 7 7 7 7 7 7 7 |
28 | | /// ``` |
29 | | Adam7(Adam7Info), |
30 | | } |
31 | | |
32 | | #[derive(Clone, Copy, Debug)] |
33 | | pub struct NullInfo { |
34 | | line: u32, |
35 | | } |
36 | | |
37 | | impl InterlaceInfo { |
38 | 69.2M | pub(crate) fn line_number(&self) -> u32 { |
39 | 69.2M | match self { |
40 | 3.54M | InterlaceInfo::Null(NullInfo { line }) => *line, |
41 | 65.6M | InterlaceInfo::Adam7(Adam7Info { line, .. }) => *line, |
42 | | } |
43 | 69.2M | } |
44 | | |
45 | 61.0M | pub(crate) fn get_adam7_info(&self) -> Option<&Adam7Info> { |
46 | 61.0M | match self { |
47 | 0 | InterlaceInfo::Null(_) => None, |
48 | 61.0M | InterlaceInfo::Adam7(adam7info) => Some(adam7info), |
49 | | } |
50 | 61.0M | } |
51 | | } |
52 | | |
53 | | pub(crate) struct InterlaceInfoIter(IterImpl); |
54 | | |
55 | | impl InterlaceInfoIter { |
56 | 32.0k | pub fn empty() -> Self { |
57 | 32.0k | Self(IterImpl::None(0..0)) |
58 | 32.0k | } |
59 | | |
60 | 23.7k | pub fn new(width: u32, height: u32, interlaced: bool) -> Self { |
61 | 23.7k | if interlaced { |
62 | 8.48k | Self(IterImpl::Adam7(Adam7Iterator::new(width, height))) |
63 | | } else { |
64 | 15.2k | Self(IterImpl::None(0..height)) |
65 | | } |
66 | 23.7k | } |
67 | | } |
68 | | |
69 | | impl Iterator for InterlaceInfoIter { |
70 | | type Item = InterlaceInfo; |
71 | | |
72 | 230M | fn next(&mut self) -> Option<InterlaceInfo> { |
73 | 230M | match self.0 { |
74 | 61.0M | IterImpl::Adam7(ref mut adam7) => Some(InterlaceInfo::Adam7(adam7.next()?)), |
75 | 169M | IterImpl::None(ref mut height) => Some(InterlaceInfo::Null(NullInfo { |
76 | 169M | line: height.next()?, |
77 | | })), |
78 | | } |
79 | 230M | } |
80 | | } |
81 | | |
82 | | enum IterImpl { |
83 | | None(Range<u32>), |
84 | | Adam7(Adam7Iterator), |
85 | | } |
86 | | |
87 | | #[cfg(test)] |
88 | | mod test { |
89 | | use super::*; |
90 | | |
91 | | #[test] |
92 | | fn null() { |
93 | | assert_eq!( |
94 | | InterlaceInfoIter::new(8, 8, false) |
95 | | .map(|info| info.line_number()) |
96 | | .collect::<Vec<_>>(), |
97 | | vec![0, 1, 2, 3, 4, 5, 6, 7], |
98 | | ); |
99 | | } |
100 | | |
101 | | #[test] |
102 | | fn adam7() { |
103 | | assert_eq!( |
104 | | InterlaceInfoIter::new(8, 8, true) |
105 | | .map(|info| info.line_number()) |
106 | | .collect::<Vec<_>>(), |
107 | | vec![ |
108 | | 0, // pass 1 |
109 | | 0, // pass 2 |
110 | | 0, // pass 3 |
111 | | 0, 1, // pass 4 |
112 | | 0, 1, // pass 5 |
113 | | 0, 1, 2, 3, // pass 6 |
114 | | 0, 1, 2, 3, // pass 7 |
115 | | ], |
116 | | ); |
117 | | } |
118 | | |
119 | | #[test] |
120 | | fn empty() { |
121 | | assert_eq!( |
122 | | InterlaceInfoIter::empty() |
123 | | .map(|info| info.line_number()) |
124 | | .collect::<Vec<_>>(), |
125 | | vec![], |
126 | | ); |
127 | | } |
128 | | } |