add image scaling

This commit is contained in:
bendn 2023-09-21 10:35:58 +07:00
parent 5c00d7449f
commit 94d9d60f03
No known key found for this signature in database
GPG key ID: 0D9D3A2A3B2A93D6
6 changed files with 68 additions and 2 deletions

View file

@ -1,11 +1,12 @@
[package] [package]
name = "fimg" name = "fimg"
version = "0.4.0" version = "0.4.1"
authors = ["bend-n <bend.n@outlook.com>"] authors = ["bend-n <bend.n@outlook.com>"]
license = "MIT" license = "MIT"
edition = "2021" edition = "2021"
description = "fast image operations" description = "fast image operations"
repository = "https://github.com/bend-n/fimg" repository = "https://github.com/bend-n/fimg"
exclude = ["src/cat.png", "src/small_cat.png", "benches/"]
[dependencies] [dependencies]
png = { version = "0.17", features = ["unstable"], optional = true } png = { version = "0.17", features = ["unstable"], optional = true }

BIN
src/cat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View file

@ -1,4 +1,4 @@
//! Box<cat> //! `Box<cat>`
use crate::Image; use crate::Image;
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> { impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {

View file

@ -29,6 +29,7 @@ mod affine;
pub mod builder; pub mod builder;
mod drawing; mod drawing;
mod overlay; mod overlay;
pub mod scale;
pub use overlay::{Overlay, OverlayAt}; pub use overlay::{Overlay, OverlayAt};
/// like assert!(), but causes undefined behaviour at runtime when the condition is not met. /// like assert!(), but causes undefined behaviour at runtime when the condition is not met.
@ -361,6 +362,29 @@ macro_rules! save {
}; };
} }
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
#[cfg(feature = "save")]
/// Open a PNG image
pub fn open(f: impl AsRef<std::path::Path>) -> Self {
let p = std::fs::File::open(f).unwrap();
let r = std::io::BufReader::new(p);
let dec = png::Decoder::new(r);
let mut reader = dec.read_info().unwrap();
let mut buf = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut buf).unwrap();
use png::ColorType::*;
match info.color_type {
Indexed | Grayscale => {
assert_eq!(CHANNELS, 1, "indexed | grayscale requires one channel")
}
Rgb => assert_eq!(CHANNELS, 3, "rgb requires three channels"),
Rgba => assert_eq!(CHANNELS, 4, "rgba requires four channels"),
GrayscaleAlpha => assert_eq!(CHANNELS, 2, "ya requires two channels"),
}
Self::build(info.width, info.height).buf(buf)
}
}
save!(3 == Rgb("RGB")); save!(3 == Rgb("RGB"));
save!(4 == Rgba("RGBA")); save!(4 == Rgba("RGBA"));
save!(2 == GrayscaleAlpha("YA")); save!(2 == GrayscaleAlpha("YA"));

41
src/scale.rs Normal file
View file

@ -0,0 +1,41 @@
//! holds scaling operations, at current only the Nearest Neighbor
use crate::Image;
/// [Nearest Neighbor](https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation) image scaling algorithm implementation.
/// Use [`Nearest::scale`].
pub struct Nearest;
impl Nearest {
/// Resize a image.
/// # Safety
///
/// `image` must be as big or bigger than `width`, `height.
pub unsafe fn scale<const N: usize>(
image: Image<&[u8], N>,
width: u32,
height: u32,
) -> Image<Vec<u8>, N> {
let x_scale = image.width() as f32 / width as f32;
let y_scale = image.height() as f32 / height as f32;
let mut out = Image::alloc(width, height);
for y in 0..height {
for x in 0..width {
let x1 = ((x as f32 + 0.5) * x_scale).floor() as u32;
let y1 = ((y as f32 + 0.5) * y_scale).floor() as u32;
// SAFETY: i asked the caller to make sure its ok
let px = unsafe { image.pixel(x1, y1) };
// SAFETY: were looping over the width and height of out. its ok.
unsafe { out.set_pixel(x, y, px) };
}
}
out
}
}
#[test]
fn test_nearest() {
let i = Image::<_, 3>::open("src/cat.png");
assert_eq!(
unsafe { Nearest::scale(i.as_ref(), 268, 178) }.buffer,
Image::<_, 3>::open("src/small_cat.png").buffer
);
}

BIN
src/small_cat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB