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 | pub(crate) fn line_number(&self) -> u32 { |
39 | match self { |
40 | InterlaceInfo::Null(NullInfo { line: &u32 }) => *line, |
41 | InterlaceInfo::Adam7(Adam7Info { line: &u32, .. }) => *line, |
42 | } |
43 | } |
44 | |
45 | pub(crate) fn get_adam7_info(&self) -> Option<&Adam7Info> { |
46 | match self { |
47 | InterlaceInfo::Null(_) => None, |
48 | InterlaceInfo::Adam7(adam7info: &Adam7Info) => Some(adam7info), |
49 | } |
50 | } |
51 | } |
52 | |
53 | pub(crate) struct InterlaceInfoIter(IterImpl); |
54 | |
55 | impl InterlaceInfoIter { |
56 | pub fn empty() -> Self { |
57 | Self(IterImpl::None(0..0)) |
58 | } |
59 | |
60 | pub fn new(width: u32, height: u32, interlaced: bool) -> Self { |
61 | if interlaced { |
62 | Self(IterImpl::Adam7(Adam7Iterator::new(width, height))) |
63 | } else { |
64 | Self(IterImpl::None(0..height)) |
65 | } |
66 | } |
67 | } |
68 | |
69 | impl Iterator for InterlaceInfoIter { |
70 | type Item = InterlaceInfo; |
71 | |
72 | fn next(&mut self) -> Option<InterlaceInfo> { |
73 | match self.0 { |
74 | IterImpl::Adam7(ref mut adam7: &mut Adam7Iterator) => Some(InterlaceInfo::Adam7(adam7.next()?)), |
75 | IterImpl::None(ref mut height: &mut Range) => Some(InterlaceInfo::Null(NullInfo { |
76 | line: height.next()?, |
77 | })), |
78 | } |
79 | } |
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 | } |
129 | |