Coverage Report

Created: 2025-12-31 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}