diff options
Diffstat (limited to 'vendor/image/src/codecs/farbfeld.rs')
-rw-r--r-- | vendor/image/src/codecs/farbfeld.rs | 400 |
1 files changed, 0 insertions, 400 deletions
diff --git a/vendor/image/src/codecs/farbfeld.rs b/vendor/image/src/codecs/farbfeld.rs deleted file mode 100644 index b543ade..0000000 --- a/vendor/image/src/codecs/farbfeld.rs +++ /dev/null @@ -1,400 +0,0 @@ -//! Decoding of farbfeld images -//! -//! farbfeld is a lossless image format which is easy to parse, pipe and compress. -//! -//! It has the following format: -//! -//! | Bytes | Description | -//! |--------|---------------------------------------------------------| -//! | 8 | "farbfeld" magic value | -//! | 4 | 32-Bit BE unsigned integer (width) | -//! | 4 | 32-Bit BE unsigned integer (height) | -//! | [2222] | 4⋅16-Bit BE unsigned integers [RGBA] / pixel, row-major | -//! -//! The RGB-data should be sRGB for best interoperability and not alpha-premultiplied. -//! -//! # Related Links -//! * <https://tools.suckless.org/farbfeld/> - the farbfeld specification - -use std::convert::TryFrom; -use std::i64; -use std::io::{self, Read, Seek, SeekFrom, Write}; - -use byteorder::{BigEndian, ByteOrder, NativeEndian}; - -use crate::color::ColorType; -use crate::error::{ - DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind, -}; -use crate::image::{self, ImageDecoder, ImageDecoderRect, ImageEncoder, ImageFormat, Progress}; - -/// farbfeld Reader -pub struct FarbfeldReader<R: Read> { - width: u32, - height: u32, - inner: R, - /// Relative to the start of the pixel data - current_offset: u64, - cached_byte: Option<u8>, -} - -impl<R: Read> FarbfeldReader<R> { - fn new(mut buffered_read: R) -> ImageResult<FarbfeldReader<R>> { - fn read_dimm<R: Read>(from: &mut R) -> ImageResult<u32> { - let mut buf = [0u8; 4]; - from.read_exact(&mut buf).map_err(|err| { - ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err)) - })?; - Ok(BigEndian::read_u32(&buf)) - } - - let mut magic = [0u8; 8]; - buffered_read.read_exact(&mut magic).map_err(|err| { - ImageError::Decoding(DecodingError::new(ImageFormat::Farbfeld.into(), err)) - })?; - if &magic != b"farbfeld" { - return Err(ImageError::Decoding(DecodingError::new( - ImageFormat::Farbfeld.into(), - format!("Invalid magic: {:02x?}", magic), - ))); - } - - let reader = FarbfeldReader { - width: read_dimm(&mut buffered_read)?, - height: read_dimm(&mut buffered_read)?, - inner: buffered_read, - current_offset: 0, - cached_byte: None, - }; - - if crate::utils::check_dimension_overflow( - reader.width, - reader.height, - // ColorType is always rgba16 - ColorType::Rgba16.bytes_per_pixel(), - ) { - return Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Farbfeld.into(), - UnsupportedErrorKind::GenericFeature(format!( - "Image dimensions ({}x{}) are too large", - reader.width, reader.height - )), - ), - )); - } - - Ok(reader) - } -} - -impl<R: Read> Read for FarbfeldReader<R> { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> { - let mut bytes_written = 0; - if let Some(byte) = self.cached_byte.take() { - buf[0] = byte; - buf = &mut buf[1..]; - bytes_written = 1; - self.current_offset += 1; - } - - if buf.len() == 1 { - buf[0] = cache_byte(&mut self.inner, &mut self.cached_byte)?; - bytes_written += 1; - self.current_offset += 1; - } else { - for channel_out in buf.chunks_exact_mut(2) { - consume_channel(&mut self.inner, channel_out)?; - bytes_written += 2; - self.current_offset += 2; - } - } - - Ok(bytes_written) - } -} - -impl<R: Read + Seek> Seek for FarbfeldReader<R> { - fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { - fn parse_offset(original_offset: u64, end_offset: u64, pos: SeekFrom) -> Option<i64> { - match pos { - SeekFrom::Start(off) => i64::try_from(off) - .ok()? - .checked_sub(i64::try_from(original_offset).ok()?), - SeekFrom::End(off) => { - if off < i64::try_from(end_offset).unwrap_or(i64::MAX) { - None - } else { - Some(i64::try_from(end_offset.checked_sub(original_offset)?).ok()? + off) - } - } - SeekFrom::Current(off) => { - if off < i64::try_from(original_offset).unwrap_or(i64::MAX) { - None - } else { - Some(off) - } - } - } - } - - let original_offset = self.current_offset; - let end_offset = self.width as u64 * self.height as u64 * 2; - let offset_from_current = - parse_offset(original_offset, end_offset, pos).ok_or_else(|| { - io::Error::new( - io::ErrorKind::InvalidInput, - "invalid seek to a negative or overflowing position", - ) - })?; - - // TODO: convert to seek_relative() once that gets stabilised - self.inner.seek(SeekFrom::Current(offset_from_current))?; - self.current_offset = if offset_from_current < 0 { - original_offset.checked_sub(offset_from_current.wrapping_neg() as u64) - } else { - original_offset.checked_add(offset_from_current as u64) - } - .expect("This should've been checked above"); - - if self.current_offset < end_offset && self.current_offset % 2 == 1 { - let curr = self.inner.seek(SeekFrom::Current(-1))?; - cache_byte(&mut self.inner, &mut self.cached_byte)?; - self.inner.seek(SeekFrom::Start(curr))?; - } else { - self.cached_byte = None; - } - - Ok(original_offset) - } -} - -fn consume_channel<R: Read>(from: &mut R, to: &mut [u8]) -> io::Result<()> { - let mut ibuf = [0u8; 2]; - from.read_exact(&mut ibuf)?; - NativeEndian::write_u16(to, BigEndian::read_u16(&ibuf)); - Ok(()) -} - -fn cache_byte<R: Read>(from: &mut R, cached_byte: &mut Option<u8>) -> io::Result<u8> { - let mut obuf = [0u8; 2]; - consume_channel(from, &mut obuf)?; - *cached_byte = Some(obuf[1]); - Ok(obuf[0]) -} - -/// farbfeld decoder -pub struct FarbfeldDecoder<R: Read> { - reader: FarbfeldReader<R>, -} - -impl<R: Read> FarbfeldDecoder<R> { - /// Creates a new decoder that decodes from the stream ```r``` - pub fn new(buffered_read: R) -> ImageResult<FarbfeldDecoder<R>> { - Ok(FarbfeldDecoder { - reader: FarbfeldReader::new(buffered_read)?, - }) - } -} - -impl<'a, R: 'a + Read> ImageDecoder<'a> for FarbfeldDecoder<R> { - type Reader = FarbfeldReader<R>; - - fn dimensions(&self) -> (u32, u32) { - (self.reader.width, self.reader.height) - } - - fn color_type(&self) -> ColorType { - ColorType::Rgba16 - } - - fn into_reader(self) -> ImageResult<Self::Reader> { - Ok(self.reader) - } - - fn scanline_bytes(&self) -> u64 { - 2 - } -} - -impl<'a, R: 'a + Read + Seek> ImageDecoderRect<'a> for FarbfeldDecoder<R> { - fn read_rect_with_progress<F: Fn(Progress)>( - &mut self, - x: u32, - y: u32, - width: u32, - height: u32, - buf: &mut [u8], - progress_callback: F, - ) -> ImageResult<()> { - // A "scanline" (defined as "shortest non-caching read" in the doc) is just one channel in this case - - let start = self.reader.stream_position()?; - image::load_rect( - x, - y, - width, - height, - buf, - progress_callback, - self, - |s, scanline| s.reader.seek(SeekFrom::Start(scanline * 2)).map(|_| ()), - |s, buf| s.reader.read_exact(buf), - )?; - self.reader.seek(SeekFrom::Start(start))?; - Ok(()) - } -} - -/// farbfeld encoder -pub struct FarbfeldEncoder<W: Write> { - w: W, -} - -impl<W: Write> FarbfeldEncoder<W> { - /// Create a new encoder that writes its output to ```w```. The writer should be buffered. - pub fn new(buffered_writer: W) -> FarbfeldEncoder<W> { - FarbfeldEncoder { w: buffered_writer } - } - - /// Encodes the image ```data``` (native endian) - /// that has dimensions ```width``` and ```height``` - pub fn encode(self, data: &[u8], width: u32, height: u32) -> ImageResult<()> { - self.encode_impl(data, width, height)?; - Ok(()) - } - - fn encode_impl(mut self, data: &[u8], width: u32, height: u32) -> io::Result<()> { - self.w.write_all(b"farbfeld")?; - - let mut buf = [0u8; 4]; - BigEndian::write_u32(&mut buf, width); - self.w.write_all(&buf)?; - - BigEndian::write_u32(&mut buf, height); - self.w.write_all(&buf)?; - - for channel in data.chunks_exact(2) { - BigEndian::write_u16(&mut buf, NativeEndian::read_u16(channel)); - self.w.write_all(&buf[..2])?; - } - - Ok(()) - } -} - -impl<W: Write> ImageEncoder for FarbfeldEncoder<W> { - fn write_image( - self, - buf: &[u8], - width: u32, - height: u32, - color_type: ColorType, - ) -> ImageResult<()> { - if color_type != ColorType::Rgba16 { - return Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Farbfeld.into(), - UnsupportedErrorKind::Color(color_type.into()), - ), - )); - } - - self.encode(buf, width, height) - } -} - -#[cfg(test)] -mod tests { - use crate::codecs::farbfeld::FarbfeldDecoder; - use crate::ImageDecoderRect; - use byteorder::{ByteOrder, NativeEndian}; - use std::io::{Cursor, Seek, SeekFrom}; - - static RECTANGLE_IN: &[u8] = b"farbfeld\ - \x00\x00\x00\x02\x00\x00\x00\x03\ - \xFF\x01\xFE\x02\xFD\x03\xFC\x04\xFB\x05\xFA\x06\xF9\x07\xF8\x08\ - \xF7\x09\xF6\x0A\xF5\x0B\xF4\x0C\xF3\x0D\xF2\x0E\xF1\x0F\xF0\x10\ - \xEF\x11\xEE\x12\xED\x13\xEC\x14\xEB\x15\xEA\x16\xE9\x17\xE8\x18"; - - #[test] - fn read_rect_1x2() { - static RECTANGLE_OUT: &[u16] = &[ - 0xF30D, 0xF20E, 0xF10F, 0xF010, 0xEB15, 0xEA16, 0xE917, 0xE818, - ]; - - read_rect(1, 1, 1, 2, RECTANGLE_OUT); - } - - #[test] - fn read_rect_2x2() { - static RECTANGLE_OUT: &[u16] = &[ - 0xFF01, 0xFE02, 0xFD03, 0xFC04, 0xFB05, 0xFA06, 0xF907, 0xF808, 0xF709, 0xF60A, 0xF50B, - 0xF40C, 0xF30D, 0xF20E, 0xF10F, 0xF010, - ]; - - read_rect(0, 0, 2, 2, RECTANGLE_OUT); - } - - #[test] - fn read_rect_2x1() { - static RECTANGLE_OUT: &[u16] = &[ - 0xEF11, 0xEE12, 0xED13, 0xEC14, 0xEB15, 0xEA16, 0xE917, 0xE818, - ]; - - read_rect(0, 2, 2, 1, RECTANGLE_OUT); - } - - #[test] - fn read_rect_2x3() { - static RECTANGLE_OUT: &[u16] = &[ - 0xFF01, 0xFE02, 0xFD03, 0xFC04, 0xFB05, 0xFA06, 0xF907, 0xF808, 0xF709, 0xF60A, 0xF50B, - 0xF40C, 0xF30D, 0xF20E, 0xF10F, 0xF010, 0xEF11, 0xEE12, 0xED13, 0xEC14, 0xEB15, 0xEA16, - 0xE917, 0xE818, - ]; - - read_rect(0, 0, 2, 3, RECTANGLE_OUT); - } - - #[test] - fn read_rect_in_stream() { - static RECTANGLE_OUT: &[u16] = &[0xEF11, 0xEE12, 0xED13, 0xEC14]; - - let mut input = vec![]; - input.extend_from_slice(b"This is a 31-byte-long prologue"); - input.extend_from_slice(RECTANGLE_IN); - let mut input_cur = Cursor::new(input); - input_cur.seek(SeekFrom::Start(31)).unwrap(); - - let mut out_buf = [0u8; 64]; - FarbfeldDecoder::new(input_cur) - .unwrap() - .read_rect(0, 2, 1, 1, &mut out_buf) - .unwrap(); - let exp = degenerate_pixels(RECTANGLE_OUT); - assert_eq!(&out_buf[..exp.len()], &exp[..]); - } - - #[test] - fn dimension_overflow() { - let header = b"farbfeld\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; - - assert!(FarbfeldDecoder::new(Cursor::new(header)).is_err()); - } - - fn read_rect(x: u32, y: u32, width: u32, height: u32, exp_wide: &[u16]) { - let mut out_buf = [0u8; 64]; - FarbfeldDecoder::new(Cursor::new(RECTANGLE_IN)) - .unwrap() - .read_rect(x, y, width, height, &mut out_buf) - .unwrap(); - let exp = degenerate_pixels(exp_wide); - assert_eq!(&out_buf[..exp.len()], &exp[..]); - } - - fn degenerate_pixels(exp_wide: &[u16]) -> Vec<u8> { - let mut exp = vec![0u8; exp_wide.len() * 2]; - NativeEndian::write_u16_into(exp_wide, &mut exp); - exp - } -} |