glycin-utils 5.0.0-alpha

Sandboxed image decoding
Documentation
use std::io::{Cursor, Read, Seek};

use glycin_common::MemoryFormatInfo;
use gufo_common::math::{Checked, checked};

use super::{EditingFrame, Error};
use crate::FungibleMemory;
use crate::editing::orientation::BasicFrame;

pub fn clip(
    mut frame: EditingFrame<FungibleMemory>,
    (x, y, width, height): (u32, u32, u32, u32),
) -> Result<EditingFrame<FungibleMemory>, Error> {
    let pixel_size = frame.memory_format.n_bytes().u32();

    checked![pixel_size, x, y];

    let max_width = (frame.width - x).check()?;
    let max_height = (frame.height - y).check()?;

    let width = u32::min(width, max_width);
    let height = u32::min(height, max_height);

    let new_stride = (width * pixel_size).check()?;
    let size = (Checked::new(height as usize) * new_stride as usize).check()?;
    let mut new = Vec::with_capacity(size);

    let stride = frame.stride as i64;
    let x_ = (x.i64() * pixel_size.i64()).check()?;
    let width_ = width as i64 * pixel_size.i64();

    checked![stride];

    let mut cur = Cursor::new(&**frame.texture());
    let mut row = vec![0; (width as usize * pixel_size.usize()).check()?];

    cur.seek_relative((y.i64() * stride).check()?)?;

    for _ in 0..height {
        cur.seek_relative(x_)?;
        cur.read_exact(&mut row)?;
        new.extend_from_slice(&row);
        cur.seek_relative((stride - x_ - width_).check()?)?;
    }

    frame.width = width;
    frame.height = height;
    frame.stride = new_stride;

    frame.set_texture(FungibleMemory::from_vec(new));

    Ok(frame)
}