Coverage Report

Created: 2025-07-12 07:18

/src/image/src/codecs/farbfeld.rs
Line
Count
Source (jump to first uncovered line)
1
//! Decoding of farbfeld images
2
//!
3
//! farbfeld is a lossless image format which is easy to parse, pipe and compress.
4
//!
5
//! It has the following format:
6
//!
7
//! | Bytes  | Description                                             |
8
//! |--------|---------------------------------------------------------|
9
//! | 8      | "farbfeld" magic value                                  |
10
//! | 4      | 32-Bit BE unsigned integer (width)                      |
11
//! | 4      | 32-Bit BE unsigned integer (height)                     |
12
//! | [2222] | 4⋅16-Bit BE unsigned integers [RGBA] / pixel, row-major |
13
//!
14
//! The RGB-data should be sRGB for best interoperability and not alpha-premultiplied.
15
//!
16
//! # Related Links
17
//! * <https://tools.suckless.org/farbfeld/> - the farbfeld specification
18
19
use std::io::{self, Read, Seek, SeekFrom, Write};
20
21
use crate::color::ExtendedColorType;
22
use crate::error::{
23
    DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
24
};
25
use crate::io::free_functions::load_rect;
26
use crate::{ColorType, ImageDecoder, ImageDecoderRect, ImageEncoder, ImageFormat};
27
28
/// farbfeld Reader
29
pub struct FarbfeldReader<R: Read> {
30
    width: u32,
31
    height: u32,
32
    inner: R,
33
    /// Relative to the start of the pixel data
34
    current_offset: u64,
35
    cached_byte: Option<u8>,
36
}
37
38
impl<R: Read> FarbfeldReader<R> {
39
2
    fn new(mut buffered_read: R) -> ImageResult<FarbfeldReader<R>> {
40
4
        fn read_dimm<R: Read>(from: &mut R) -> ImageResult<u32> {
41
4
            let mut buf = [0u8; 4];
42
4
            from.read_exact(&mut buf).map_err(|err| {
43
0
                ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err))
44
4
            })?;
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<_>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>::{closure#0}
45
4
            Ok(u32::from_be_bytes(buf))
46
4
        }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<_>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
<image::codecs::farbfeld::FarbfeldReader<_>>::new::read_dimm::<std::io::cursor::Cursor<&[u8]>>
Line
Count
Source
40
4
        fn read_dimm<R: Read>(from: &mut R) -> ImageResult<u32> {
41
4
            let mut buf = [0u8; 4];
42
4
            from.read_exact(&mut buf).map_err(|err| {
43
                ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err))
44
4
            })?;
45
4
            Ok(u32::from_be_bytes(buf))
46
4
        }
47
48
2
        let mut magic = [0u8; 8];
49
2
        buffered_read.read_exact(&mut magic).map_err(|err| {
50
0
            ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err))
51
2
        })?;
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}
52
2
        if &magic != b"farbfeld" {
53
0
            return Err(ImageError::Decoding(DecodingError::new(
54
0
                ImageFormat::Farbfeld.into(),
55
0
                format!("Invalid magic: {magic:02x?}"),
56
0
            )));
57
2
        }
58
59
2
        let reader = FarbfeldReader {
60
2
            width: read_dimm(&mut buffered_read)?,
61
2
            height: read_dimm(&mut buffered_read)?,
62
2
            inner: buffered_read,
63
2
            current_offset: 0,
64
2
            cached_byte: None,
65
2
        };
66
2
67
2
        if crate::utils::check_dimension_overflow(
68
2
            reader.width,
69
2
            reader.height,
70
2
            // ExtendedColorType is always rgba16
71
2
            8,
72
2
        ) {
73
0
            return Err(ImageError::Unsupported(
74
0
                UnsupportedError::from_format_and_kind(
75
0
                    ImageFormat::Farbfeld.into(),
76
0
                    UnsupportedErrorKind::GenericFeature(format!(
77
0
                        "Image dimensions ({}x{}) are too large",
78
0
                        reader.width, reader.height
79
0
                    )),
80
0
                ),
81
0
            ));
82
2
        }
83
2
84
2
        Ok(reader)
85
2
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
<image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>>>::new
Line
Count
Source
39
2
    fn new(mut buffered_read: R) -> ImageResult<FarbfeldReader<R>> {
40
        fn read_dimm<R: Read>(from: &mut R) -> ImageResult<u32> {
41
            let mut buf = [0u8; 4];
42
            from.read_exact(&mut buf).map_err(|err| {
43
                ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err))
44
            })?;
45
            Ok(u32::from_be_bytes(buf))
46
        }
47
48
2
        let mut magic = [0u8; 8];
49
2
        buffered_read.read_exact(&mut magic).map_err(|err| {
50
            ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err))
51
2
        })?;
52
2
        if &magic != b"farbfeld" {
53
0
            return Err(ImageError::Decoding(DecodingError::new(
54
0
                ImageFormat::Farbfeld.into(),
55
0
                format!("Invalid magic: {magic:02x?}"),
56
0
            )));
57
2
        }
58
59
2
        let reader = FarbfeldReader {
60
2
            width: read_dimm(&mut buffered_read)?,
61
2
            height: read_dimm(&mut buffered_read)?,
62
2
            inner: buffered_read,
63
2
            current_offset: 0,
64
2
            cached_byte: None,
65
2
        };
66
2
67
2
        if crate::utils::check_dimension_overflow(
68
2
            reader.width,
69
2
            reader.height,
70
2
            // ExtendedColorType is always rgba16
71
2
            8,
72
2
        ) {
73
0
            return Err(ImageError::Unsupported(
74
0
                UnsupportedError::from_format_and_kind(
75
0
                    ImageFormat::Farbfeld.into(),
76
0
                    UnsupportedErrorKind::GenericFeature(format!(
77
0
                        "Image dimensions ({}x{}) are too large",
78
0
                        reader.width, reader.height
79
0
                    )),
80
0
                ),
81
0
            ));
82
2
        }
83
2
84
2
        Ok(reader)
85
2
    }
86
}
87
88
impl<R: Read> Read for FarbfeldReader<R> {
89
1
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
90
1
        let mut bytes_written = 0;
91
1
        if let Some(byte) = self.cached_byte.take() {
92
0
            buf[0] = byte;
93
0
            buf = &mut buf[1..];
94
0
            bytes_written = 1;
95
0
            self.current_offset += 1;
96
1
        }
97
98
1
        if buf.len() == 1 {
99
0
            buf[0] = cache_byte(&mut self.inner, &mut self.cached_byte)?;
100
0
            bytes_written += 1;
101
0
            self.current_offset += 1;
102
        } else {
103
129
            for channel_out in buf.chunks_exact_mut(2) {
104
129
                consume_channel(&mut self.inner, channel_out)?;
105
128
                bytes_written += 2;
106
128
                self.current_offset += 2;
107
            }
108
        }
109
110
0
        Ok(bytes_written)
111
1
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<_> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
<image::codecs::farbfeld::FarbfeldReader<std::io::cursor::Cursor<&[u8]>> as std::io::Read>::read
Line
Count
Source
89
1
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
90
1
        let mut bytes_written = 0;
91
1
        if let Some(byte) = self.cached_byte.take() {
92
0
            buf[0] = byte;
93
0
            buf = &mut buf[1..];
94
0
            bytes_written = 1;
95
0
            self.current_offset += 1;
96
1
        }
97
98
1
        if buf.len() == 1 {
99
0
            buf[0] = cache_byte(&mut self.inner, &mut self.cached_byte)?;
100
0
            bytes_written += 1;
101
0
            self.current_offset += 1;
102
        } else {
103
129
            for channel_out in buf.chunks_exact_mut(2) {
104
129
                consume_channel(&mut self.inner, channel_out)?;
105
128
                bytes_written += 2;
106
128
                self.current_offset += 2;
107
            }
108
        }
109
110
0
        Ok(bytes_written)
111
1
    }
112
}
113
114
impl<R: Read + Seek> Seek for FarbfeldReader<R> {
115
0
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
116
        fn parse_offset(original_offset: u64, end_offset: u64, pos: SeekFrom) -> Option<i64> {
117
            match pos {
118
                SeekFrom::Start(off) => i64::try_from(off)
119
                    .ok()?
120
                    .checked_sub(i64::try_from(original_offset).ok()?),
121
                SeekFrom::End(off) => {
122
                    if off < i64::try_from(end_offset).unwrap_or(i64::MAX) {
123
                        None
124
                    } else {
125
                        Some(i64::try_from(end_offset.checked_sub(original_offset)?).ok()? + off)
126
                    }
127
                }
128
                SeekFrom::Current(off) => {
129
                    if off < i64::try_from(original_offset).unwrap_or(i64::MAX) {
130
                        None
131
                    } else {
132
                        Some(off)
133
                    }
134
                }
135
            }
136
        }
137
138
0
        let original_offset = self.current_offset;
139
0
        let end_offset = u64::from(self.width) * u64::from(self.height) * 2;
140
0
        let offset_from_current =
141
0
            parse_offset(original_offset, end_offset, pos).ok_or_else(|| {
142
0
                io::Error::new(
143
0
                    io::ErrorKind::InvalidInput,
144
0
                    "invalid seek to a negative or overflowing position",
145
0
                )
146
0
            })?;
147
148
        // TODO: convert to seek_relative() once that gets stabilised
149
0
        self.inner.seek(SeekFrom::Current(offset_from_current))?;
150
0
        self.current_offset = if offset_from_current < 0 {
151
0
            original_offset.checked_sub(offset_from_current.wrapping_neg() as u64)
152
        } else {
153
0
            original_offset.checked_add(offset_from_current as u64)
154
        }
155
0
        .expect("This should've been checked above");
156
0
157
0
        if self.current_offset < end_offset && self.current_offset % 2 == 1 {
158
0
            let curr = self.inner.seek(SeekFrom::Current(-1))?;
159
0
            cache_byte(&mut self.inner, &mut self.cached_byte)?;
160
0
            self.inner.seek(SeekFrom::Start(curr))?;
161
0
        } else {
162
0
            self.cached_byte = None;
163
0
        }
164
165
0
        Ok(original_offset)
166
0
    }
167
}
168
169
129
fn consume_channel<R: Read>(from: &mut R, mut to: &mut [u8]) -> io::Result<()> {
170
129
    let mut ibuf = [0u8; 2];
171
129
    from.read_exact(&mut ibuf)?;
172
128
    to.write_all(&u16::from_be_bytes(ibuf).to_ne_bytes())?;
173
174
128
    Ok(())
175
129
}
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<_>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
image::codecs::farbfeld::consume_channel::<std::io::cursor::Cursor<&[u8]>>
Line
Count
Source
169
129
fn consume_channel<R: Read>(from: &mut R, mut to: &mut [u8]) -> io::Result<()> {
170
129
    let mut ibuf = [0u8; 2];
171
129
    from.read_exact(&mut ibuf)?;
172
128
    to.write_all(&u16::from_be_bytes(ibuf).to_ne_bytes())?;
173
174
128
    Ok(())
175
129
}
176
177
0
fn cache_byte<R: Read>(from: &mut R, cached_byte: &mut Option<u8>) -> io::Result<u8> {
178
0
    let mut obuf = [0u8; 2];
179
0
    consume_channel(from, &mut obuf)?;
180
0
    *cached_byte = Some(obuf[1]);
181
0
    Ok(obuf[0])
182
0
}
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<_>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
Unexecuted instantiation: image::codecs::farbfeld::cache_byte::<std::io::cursor::Cursor<&[u8]>>
183
184
/// farbfeld decoder
185
pub struct FarbfeldDecoder<R: Read> {
186
    reader: FarbfeldReader<R>,
187
}
188
189
impl<R: Read> FarbfeldDecoder<R> {
190
    /// Creates a new decoder that decodes from the stream ```r```
191
2
    pub fn new(buffered_read: R) -> ImageResult<FarbfeldDecoder<R>> {
192
2
        Ok(FarbfeldDecoder {
193
2
            reader: FarbfeldReader::new(buffered_read)?,
194
        })
195
2
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<_>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>>>::new
Line
Count
Source
191
2
    pub fn new(buffered_read: R) -> ImageResult<FarbfeldDecoder<R>> {
192
2
        Ok(FarbfeldDecoder {
193
2
            reader: FarbfeldReader::new(buffered_read)?,
194
        })
195
2
    }
196
}
197
198
impl<R: Read> ImageDecoder for FarbfeldDecoder<R> {
199
6
    fn dimensions(&self) -> (u32, u32) {
200
6
        (self.reader.width, self.reader.height)
201
6
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<_> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions
Line
Count
Source
199
6
    fn dimensions(&self) -> (u32, u32) {
200
6
        (self.reader.width, self.reader.height)
201
6
    }
202
203
5
    fn color_type(&self) -> ColorType {
204
5
        ColorType::Rgba16
205
5
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<_> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type
Line
Count
Source
203
5
    fn color_type(&self) -> ColorType {
204
5
        ColorType::Rgba16
205
5
    }
206
207
1
    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
208
1
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
209
1
        self.reader.read_exact(buf)?;
210
0
        Ok(())
211
1
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<_> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image
Line
Count
Source
207
1
    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
208
1
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
209
1
        self.reader.read_exact(buf)?;
210
0
        Ok(())
211
1
    }
212
213
1
    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
214
1
        (*self).read_image(buf)
215
1
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<_> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed
Line
Count
Source
213
1
    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
214
1
        (*self).read_image(buf)
215
1
    }
216
}
217
218
impl<R: Read + Seek> ImageDecoderRect for FarbfeldDecoder<R> {
219
0
    fn read_rect(
220
0
        &mut self,
221
0
        x: u32,
222
0
        y: u32,
223
0
        width: u32,
224
0
        height: u32,
225
0
        buf: &mut [u8],
226
0
        row_pitch: usize,
227
0
    ) -> ImageResult<()> {
228
        // A "scanline" (defined as "shortest non-caching read" in the doc) is just one channel in this case
229
230
0
        let start = self.reader.stream_position()?;
231
0
        load_rect(
232
0
            x,
233
0
            y,
234
0
            width,
235
0
            height,
236
0
            buf,
237
0
            row_pitch,
238
0
            self,
239
0
            2,
240
0
            |s, scanline| s.reader.seek(SeekFrom::Start(scanline * 2)).map(|_| ()),
241
0
            |s, buf| s.reader.read_exact(buf),
242
0
        )?;
243
0
        self.reader.seek(SeekFrom::Start(start))?;
244
0
        Ok(())
245
0
    }
246
}
247
248
/// farbfeld encoder
249
pub struct FarbfeldEncoder<W: Write> {
250
    w: W,
251
}
252
253
impl<W: Write> FarbfeldEncoder<W> {
254
    /// Create a new encoder that writes its output to ```w```. The writer should be buffered.
255
0
    pub fn new(buffered_writer: W) -> FarbfeldEncoder<W> {
256
0
        FarbfeldEncoder { w: buffered_writer }
257
0
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<_>>::new
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
258
259
    /// Encodes the image `data` (native endian) that has dimensions `width` and `height`.
260
    ///
261
    /// # Panics
262
    ///
263
    /// Panics if `width * height * 8 != data.len()`.
264
    #[track_caller]
265
0
    pub fn encode(self, data: &[u8], width: u32, height: u32) -> ImageResult<()> {
266
0
        let expected_buffer_len = (u64::from(width) * u64::from(height)).saturating_mul(8);
267
0
        assert_eq!(
268
0
            expected_buffer_len,
269
0
            data.len() as u64,
270
0
            "Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
271
0
            data.len(),
272
        );
273
0
        self.encode_impl(data, width, height)?;
274
0
        Ok(())
275
0
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<_>>::encode
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode
276
277
0
    fn encode_impl(mut self, data: &[u8], width: u32, height: u32) -> io::Result<()> {
278
0
        self.w.write_all(b"farbfeld")?;
279
280
0
        self.w.write_all(&width.to_be_bytes())?;
281
0
        self.w.write_all(&height.to_be_bytes())?;
282
283
0
        for channel in data.chunks_exact(2) {
284
0
            self.w
285
0
                .write_all(&u16::from_ne_bytes(channel.try_into().unwrap()).to_be_bytes())?;
286
        }
287
288
0
        Ok(())
289
0
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<_>>::encode_impl
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::encode_impl
290
}
291
292
impl<W: Write> ImageEncoder for FarbfeldEncoder<W> {
293
    #[track_caller]
294
0
    fn write_image(
295
0
        self,
296
0
        buf: &[u8],
297
0
        width: u32,
298
0
        height: u32,
299
0
        color_type: ExtendedColorType,
300
0
    ) -> ImageResult<()> {
301
0
        if color_type != ExtendedColorType::Rgba16 {
302
0
            return Err(ImageError::Unsupported(
303
0
                UnsupportedError::from_format_and_kind(
304
0
                    ImageFormat::Farbfeld.into(),
305
0
                    UnsupportedErrorKind::Color(color_type),
306
0
                ),
307
0
            ));
308
0
        }
309
0
310
0
        self.encode(buf, width, height)
311
0
    }
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<_> as image::io::encoder::ImageEncoder>::write_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::write_image
312
}
313
314
#[cfg(test)]
315
mod tests {
316
    use crate::codecs::farbfeld::FarbfeldDecoder;
317
    use crate::ImageDecoderRect;
318
    use byteorder_lite::{ByteOrder, NativeEndian};
319
    use std::io::{Cursor, Seek, SeekFrom};
320
321
    static RECTANGLE_IN: &[u8] =     b"farbfeld\
322
                                       \x00\x00\x00\x02\x00\x00\x00\x03\
323
                                       \xFF\x01\xFE\x02\xFD\x03\xFC\x04\xFB\x05\xFA\x06\xF9\x07\xF8\x08\
324
                                       \xF7\x09\xF6\x0A\xF5\x0B\xF4\x0C\xF3\x0D\xF2\x0E\xF1\x0F\xF0\x10\
325
                                       \xEF\x11\xEE\x12\xED\x13\xEC\x14\xEB\x15\xEA\x16\xE9\x17\xE8\x18";
326
327
    #[test]
328
    fn read_rect_1x2() {
329
        static RECTANGLE_OUT: &[u16] = &[
330
            0xF30D, 0xF20E, 0xF10F, 0xF010, 0xEB15, 0xEA16, 0xE917, 0xE818,
331
        ];
332
333
        read_rect(1, 1, 1, 2, RECTANGLE_OUT);
334
    }
335
336
    #[test]
337
    fn read_rect_2x2() {
338
        static RECTANGLE_OUT: &[u16] = &[
339
            0xFF01, 0xFE02, 0xFD03, 0xFC04, 0xFB05, 0xFA06, 0xF907, 0xF808, 0xF709, 0xF60A, 0xF50B,
340
            0xF40C, 0xF30D, 0xF20E, 0xF10F, 0xF010,
341
        ];
342
343
        read_rect(0, 0, 2, 2, RECTANGLE_OUT);
344
    }
345
346
    #[test]
347
    fn read_rect_2x1() {
348
        static RECTANGLE_OUT: &[u16] = &[
349
            0xEF11, 0xEE12, 0xED13, 0xEC14, 0xEB15, 0xEA16, 0xE917, 0xE818,
350
        ];
351
352
        read_rect(0, 2, 2, 1, RECTANGLE_OUT);
353
    }
354
355
    #[test]
356
    fn read_rect_2x3() {
357
        static RECTANGLE_OUT: &[u16] = &[
358
            0xFF01, 0xFE02, 0xFD03, 0xFC04, 0xFB05, 0xFA06, 0xF907, 0xF808, 0xF709, 0xF60A, 0xF50B,
359
            0xF40C, 0xF30D, 0xF20E, 0xF10F, 0xF010, 0xEF11, 0xEE12, 0xED13, 0xEC14, 0xEB15, 0xEA16,
360
            0xE917, 0xE818,
361
        ];
362
363
        read_rect(0, 0, 2, 3, RECTANGLE_OUT);
364
    }
365
366
    #[test]
367
    fn read_rect_in_stream() {
368
        static RECTANGLE_OUT: &[u16] = &[0xEF11, 0xEE12, 0xED13, 0xEC14];
369
370
        let mut input = vec![];
371
        input.extend_from_slice(b"This is a 31-byte-long prologue");
372
        input.extend_from_slice(RECTANGLE_IN);
373
        let mut input_cur = Cursor::new(input);
374
        input_cur.seek(SeekFrom::Start(31)).unwrap();
375
376
        let mut out_buf = [0u8; 64];
377
        FarbfeldDecoder::new(input_cur)
378
            .unwrap()
379
            .read_rect(0, 2, 1, 1, &mut out_buf, 8)
380
            .unwrap();
381
        let exp = degenerate_pixels(RECTANGLE_OUT);
382
        assert_eq!(&out_buf[..exp.len()], &exp[..]);
383
    }
384
385
    #[test]
386
    fn dimension_overflow() {
387
        let header = b"farbfeld\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
388
389
        assert!(FarbfeldDecoder::new(Cursor::new(header)).is_err());
390
    }
391
392
    fn read_rect(x: u32, y: u32, width: u32, height: u32, exp_wide: &[u16]) {
393
        let mut out_buf = [0u8; 64];
394
        FarbfeldDecoder::new(Cursor::new(RECTANGLE_IN))
395
            .unwrap()
396
            .read_rect(x, y, width, height, &mut out_buf, width as usize * 8)
397
            .unwrap();
398
        let exp = degenerate_pixels(exp_wide);
399
        assert_eq!(&out_buf[..exp.len()], &exp[..]);
400
    }
401
402
    fn degenerate_pixels(exp_wide: &[u16]) -> Vec<u8> {
403
        let mut exp = vec![0u8; exp_wide.len() * 2];
404
        NativeEndian::write_u16_into(exp_wide, &mut exp);
405
        exp
406
    }
407
}