mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 10:28:21 -06:00
add image scaling
This commit is contained in:
parent
5c00d7449f
commit
94d9d60f03
|
@ -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
BIN
src/cat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
|
@ -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> {
|
||||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -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
41
src/scale.rs
Normal 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
BIN
src/small_cat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
Loading…
Reference in a new issue