gistools/parsers/image/
decoder.rs

1#[cfg(feature = "std")]
2use super::ImageData;
3#[cfg(feature = "std")]
4use crate::parsers::Buffer;
5#[cfg(feature = "std")]
6use image::ImageReader;
7#[cfg(feature = "std")]
8use std::io::Cursor;
9
10/// Image Decoder Options
11#[derive(Debug, Default, Clone)]
12pub struct DecodeOptions {
13    /// The x position to start at
14    pub x: Option<u32>,
15    /// The y position to start at
16    pub y: Option<u32>,
17    /// The width to read in
18    pub width: Option<u32>,
19    /// The height to read in
20    pub height: Option<u32>,
21    /// The modulo to use. For example you may have a 514x514 image, but you want to use 512x512 [Default=1]
22    pub modulo: Option<u32>,
23}
24
25/// Decode any image
26///
27/// ## Parameters
28/// - `buffer`: the input buffer
29/// - `options`: the decode options
30///
31/// ## Returns
32/// the raw decoded buffer
33#[cfg(feature = "std")]
34pub fn image_decoder(
35    buffer: &Buffer,
36    options: Option<DecodeOptions>,
37) -> Result<ImageData, image::ImageError> {
38    use image::GenericImageView;
39
40    let img = ImageReader::new(Cursor::new(buffer.buf())).with_guessed_format()?.decode()?;
41
42    let (img_width, img_height) = img.dimensions();
43    let opts = options.unwrap_or_default();
44
45    let modulo = opts.modulo.unwrap_or(1);
46    let diff = img_width % modulo;
47
48    let (x, y, width, height) = if diff != 0 {
49        let shift = diff / 2;
50        (shift, shift, img_width - diff, img_width - diff)
51    } else {
52        (
53            opts.x.unwrap_or(0),
54            opts.y.unwrap_or(0),
55            opts.width.unwrap_or(img_width),
56            opts.height.unwrap_or(img_height),
57        )
58    };
59
60    let sub_image = img.view(x, y, width, height).to_image();
61
62    Ok(ImageData {
63        width: width as usize,
64        height: height as usize,
65        data: sub_image.into_raw().into(),
66    })
67}
68
69/// Image decoder
70///
71/// ## Parameters
72/// - `buffer`: the input buffer
73/// - `options`: user defined options
74///
75/// ## Returns
76/// the decoded buffer
77#[cfg(feature = "std")]
78pub fn image_decoder_buffer(buffer: &Buffer, options: Option<DecodeOptions>) -> Buffer {
79    image_decoder(buffer, options).unwrap().data
80}