fast image operations
-rw-r--r--Cargo.toml11
-rw-r--r--README.md9
-rw-r--r--benches/3_8x8.imgbuf (renamed from benches/3_4x4.imgbuf)0
-rw-r--r--benches/3x3_at_out.imgbuf1
-rw-r--r--benches/4_160x160.imgbuf (renamed from test_data/4_180x180.imgbuf)bin102400 -> 102400 bytes
-rw-r--r--benches/4_8x8.imgbuf (renamed from benches/4_4x4.imgbuf)0
-rw-r--r--benches/4x3_at_out.imgbuf1
-rw-r--r--benches/4x4_at_out.imgbuf1
-rw-r--r--benches/affine_transformations.rs23
-rw-r--r--benches/overlays.rs83
-rw-r--r--src/affine.rs149
-rw-r--r--src/builder.rs98
-rw-r--r--src/cat.pngbin0 -> 2533832 bytes
-rw-r--r--src/drawing/box.rs65
-rw-r--r--src/drawing/line.rs174
-rw-r--r--src/drawing/mod.rs4
-rw-r--r--src/drawing/tri.rs45
-rw-r--r--src/lib.rs246
-rw-r--r--src/overlay.rs82
-rw-r--r--src/scale.rs41
-rw-r--r--src/small_cat.pngbin0 -> 77497 bytes
21 files changed, 802 insertions, 231 deletions
diff --git a/Cargo.toml b/Cargo.toml
index ab92c06..d1554b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,24 +1,27 @@
[package]
name = "fimg"
-version = "0.1.0"
+version = "0.4.1"
authors = ["bend-n <[email protected]>"]
license = "MIT"
edition = "2021"
description = "fast image operations"
repository = "https://github.com/bend-n/fimg"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+exclude = ["src/cat.png", "src/small_cat.png", "benches/"]
[dependencies]
png = { version = "0.17", features = ["unstable"], optional = true }
[dev-dependencies]
-criterion = "0.5"
+iai = { version = "0.1.1", features = [], git = "https://github.com/bend-n/iai/" }
[[bench]]
name = "overlays"
harness = false
+[[bench]]
+name = "affine_transformations"
+harness = false
+
[features]
save = ["png"]
default = ["save"]
diff --git a/README.md b/README.md
index f77c5cc..8e36c96 100644
--- a/README.md
+++ b/README.md
@@ -6,4 +6,11 @@ quick simple image operations
- [x] overlay
- [x] rotation
-- [x] flipping \ No newline at end of file
+- [x] flipping
+- [x] nearest neighbor scaling
+- [x] triangle drawing
+- [x] simple line drawing
+- [x] box drawing
+- [ ] thick box drawing
+- [ ] thick line drawing
+- [ ] polygon drawing
diff --git a/benches/3_4x4.imgbuf b/benches/3_8x8.imgbuf
index f3a8624..f3a8624 100644
--- a/benches/3_4x4.imgbuf
+++ b/benches/3_8x8.imgbuf
diff --git a/benches/3x3_at_out.imgbuf b/benches/3x3_at_out.imgbuf
deleted file mode 100644
index 21d0141..0000000
--- a/benches/3x3_at_out.imgbuf
+++ /dev/null
@@ -1 +0,0 @@
-Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ� \ No newline at end of file
diff --git a/test_data/4_180x180.imgbuf b/benches/4_160x160.imgbuf
index 58aabd0..58aabd0 100644
--- a/test_data/4_180x180.imgbuf
+++ b/benches/4_160x160.imgbuf
Binary files differ
diff --git a/benches/4_4x4.imgbuf b/benches/4_8x8.imgbuf
index bc6cdf8..bc6cdf8 100644
--- a/benches/4_4x4.imgbuf
+++ b/benches/4_8x8.imgbuf
diff --git a/benches/4x3_at_out.imgbuf b/benches/4x3_at_out.imgbuf
deleted file mode 100644
index d5d8851..0000000
--- a/benches/4x3_at_out.imgbuf
+++ /dev/null
@@ -1 +0,0 @@
-������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ \ No newline at end of file
diff --git a/benches/4x4_at_out.imgbuf b/benches/4x4_at_out.imgbuf
deleted file mode 100644
index 4dedb62..0000000
--- a/benches/4x4_at_out.imgbuf
+++ /dev/null
@@ -1 +0,0 @@
-���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \ No newline at end of file
diff --git a/benches/affine_transformations.rs b/benches/affine_transformations.rs
new file mode 100644
index 0000000..b74d9ba
--- /dev/null
+++ b/benches/affine_transformations.rs
@@ -0,0 +1,23 @@
+use fimg::*;
+
+macro_rules! bench {
+ (fn $name: ident() { run $fn: ident() }) => {
+ fn $name() {
+ let mut img: Image<_, 4> =
+ Image::build(160, 160).buf(include_bytes!("4_160x160.imgbuf").to_vec());
+ for _ in 0..256 {
+ #[allow(unused_unsafe)]
+ unsafe {
+ img.$fn()
+ };
+ }
+ }
+ };
+}
+
+bench!(fn flip_h() { run flip_h() });
+bench!(fn flip_v() { run flip_v() });
+bench!(fn rotate_90() { run rot_90() });
+bench!(fn rotate_180() { run rot_180() });
+bench!(fn rotate_270() { run rot_270() });
+iai::main!(flip_h, flip_v, rotate_90, rotate_180, rotate_270);
diff --git a/benches/overlays.rs b/benches/overlays.rs
index 2236905..46e10f6 100644
--- a/benches/overlays.rs
+++ b/benches/overlays.rs
@@ -1,65 +1,32 @@
-use criterion::{criterion_group, criterion_main, Criterion};
use fimg::*;
-pub fn criterion_benchmark(bench: &mut Criterion) {
- let mut group = bench.benchmark_group("overlays");
- {
- let mut a: Image<_, 3> = Image::alloc(64, 64);
- let b = Image::<&[u8], 3>::new(
- 4.try_into().unwrap(),
- 4.try_into().unwrap(),
- *&include_bytes!("3_4x4.imgbuf"),
- );
- group.bench_function("overlay 3x3 offset", |bench| {
- bench.iter(|| unsafe {
- for x in 0..16 {
- for y in 0..16 {
- a.as_mut().overlay_at(&b, x * 4, y * 4);
- }
- }
- });
- });
- assert_eq!(a.as_ref().buffer, include_bytes!("3x3_at_out.imgbuf"));
+fn overlay_3on3at() {
+ let mut a: Image<_, 3> = Image::alloc(128, 128);
+ let b: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("3_8x8.imgbuf"));
+ for x in 0..16 {
+ for y in 0..16 {
+ unsafe { a.as_mut().overlay_at(&b, x * 8, y * 8) };
+ }
}
- {
- let mut a: Image<_, 3> = Image::alloc(64, 64);
- let b = Image::<&[u8], 4>::new(
- 4.try_into().unwrap(),
- 4.try_into().unwrap(),
- *&include_bytes!("4_4x4.imgbuf"),
- );
- group.bench_function("overlay 4x3 offset", |bench| {
- bench.iter(|| unsafe {
- for x in 0..16 {
- for y in 0..16 {
- a.as_mut().overlay_at(&b, x * 4, y * 4);
- }
- }
- });
- });
+}
- assert_eq!(a.as_ref().buffer, include_bytes!("4x3_at_out.imgbuf"));
- }
- {
- let mut a: Image<_, 4> = Image::alloc(64, 64);
- let b = Image::<&[u8], 4>::new(
- 4.try_into().unwrap(),
- 4.try_into().unwrap(),
- *&include_bytes!("4_4x4.imgbuf"),
- );
- group.bench_function("overlay 4x4 offset", |bench| {
- bench.iter(|| unsafe {
- for x in 0..16 {
- for y in 0..16 {
- a.as_mut().overlay_at(&b, x * 4, y * 4);
- }
- }
- });
- });
- assert_eq!(a.as_ref().buffer, include_bytes!("4x4_at_out.imgbuf"));
+fn overlay_4on3at() {
+ let mut a: Image<_, 3> = Image::alloc(128, 128);
+ let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
+ for x in 0..16 {
+ for y in 0..16 {
+ unsafe { a.as_mut().overlay_at(&b, x * 8, y * 8) };
+ }
}
- group.finish();
}
-criterion_group!(benches, criterion_benchmark);
-criterion_main!(benches);
+fn overlay_4on4at() {
+ let mut a: Image<_, 4> = Image::alloc(128, 128);
+ let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
+ for x in 0..16 {
+ for y in 0..16 {
+ unsafe { a.as_mut().overlay_at(&b, x * 8, y * 8) };
+ }
+ }
+}
+iai::main!(overlay_3on3at, overlay_4on3at, overlay_4on4at);
diff --git a/src/affine.rs b/src/affine.rs
index 393b571..362a746 100644
--- a/src/affine.rs
+++ b/src/affine.rs
@@ -1,87 +1,92 @@
-use crate::{FromRefMut, Image};
-
-pub trait Rotations {
- /// Rotate a image 180 degrees clockwise.
- fn rot_180(&mut self);
- /// Rotate a image 90 degrees clockwise.
- /// # Safety
- ///
- /// UB if the image is not square
- unsafe fn rot_90(&mut self);
- /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise.
- /// # Safety
- ///
- /// UB if the image is not square
- unsafe fn rot_270(&mut self);
-}
-
-pub trait Flips {
- /// Flip a image vertically.
- fn flip_v(&mut self);
+//! Manages the affine image transformations.
+use crate::Image;
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
/// Flip a image horizontally.
- fn flip_h(&mut self);
-}
-
-impl<const CHANNELS: usize> Flips for Image<Vec<u8>, CHANNELS> {
- fn flip_h(&mut self) {
+ pub fn flip_h(&mut self) {
self.as_mut().flip_h();
}
- fn flip_v(&mut self) {
+ /// Flip a image vertically.
+ pub fn flip_v(&mut self) {
self.as_mut().flip_v();
}
}
-impl<const CHANNELS: usize> Flips for Image<&mut [u8], CHANNELS> {
- fn flip_v(&mut self) {
+impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Flip a image vertically.
+ pub fn flip_v(&mut self) {
for y in 0..self.height() / 2 {
for x in 0..self.width() {
let y2 = self.height() - y - 1;
+ #[allow(clippy::multiple_unsafe_ops_per_block)]
// SAFETY: within bounds
- let p2 = unsafe { self.pixel(x, y2) };
- let p = unsafe { self.pixel(x, y) };
- unsafe { self.set_pixel(x, y2, p) };
- unsafe { self.set_pixel(x, y, p2) };
+ unsafe {
+ let p2 = self.pixel(x, y2);
+ let p = self.pixel(x, y);
+ self.set_pixel(x, y2, p);
+ self.set_pixel(x, y, p2);
+ }
}
}
}
- fn flip_h(&mut self) {
+ /// Flip a image horizontally.
+ pub fn flip_h(&mut self) {
for y in 0..self.height() {
for x in 0..self.width() / 2 {
let x2 = self.width() - x - 1;
- let p2 = unsafe { self.pixel(x2, y) };
- let p = unsafe { self.pixel(x, y) };
- unsafe { self.set_pixel(x2, y, p) };
- unsafe { self.set_pixel(x, y, p2) };
+ #[allow(clippy::multiple_unsafe_ops_per_block)]
+ // SAFETY: bounded
+ unsafe {
+ let p2 = self.pixel(x2, y);
+ let p = self.pixel(x, y);
+ self.set_pixel(x2, y, p);
+ self.set_pixel(x, y, p2);
+ }
}
}
}
}
-impl<const CHANNELS: usize> Rotations for Image<Vec<u8>, CHANNELS> {
- fn rot_180(&mut self) {
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
+ /// Rotate a image 180 degrees clockwise.
+ pub fn rot_180(&mut self) {
self.as_mut().rot_180();
}
- unsafe fn rot_90(&mut self) {
+ /// Rotate a image 90 degrees clockwise.
+ /// # Safety
+ ///
+ /// UB if the image is not square
+ pub unsafe fn rot_90(&mut self) {
+ // SAFETY: make sure to keep the safety docs linked
unsafe { self.as_mut().rot_90() }
}
- unsafe fn rot_270(&mut self) {
+ /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise.
+ /// # Safety
+ ///
+ /// UB if the image is not square
+ pub unsafe fn rot_270(&mut self) {
+ // SAFETY: idk this is just a convenience impl
unsafe { self.as_mut().rot_270() }
}
}
-impl<const CHANNELS: usize> Rotations for Image<&mut [u8], CHANNELS> {
- fn rot_180(&mut self) {
+impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Rotate a image 180 degrees clockwise.
+ pub fn rot_180(&mut self) {
for y in 0..self.height() / 2 {
for x in 0..self.width() {
+ // SAFETY: x, y come from the loop, must be ok
let p = unsafe { self.pixel(x, y) };
let x2 = self.width() - x - 1;
let y2 = self.height() - y - 1;
+ // SAFETY: values are good
let p2 = unsafe { self.pixel(x2, y2) };
+ // SAFETY: swapping would be cool, alas.
unsafe { self.set_pixel(x, y, p2) };
+ // SAFETY: although maybe i can cast it to a `[[u8; CHANNELS]]` and swap that 🤔
unsafe { self.set_pixel(x2, y2, p) };
}
}
@@ -90,26 +95,38 @@ impl<const CHANNELS: usize> Rotations for Image<&mut [u8], CHANNELS> {
let middle = self.height() / 2;
for x in 0..self.width() / 2 {
- let p = unsafe { self.pixel(x, middle) };
let x2 = self.width() - x - 1;
- let p2 = unsafe { self.pixel(x2, middle) };
- unsafe { self.set_pixel(x, middle, p2) };
- unsafe { self.set_pixel(x2, middle, p) };
+ #[allow(clippy::multiple_unsafe_ops_per_block)]
+ // SAFETY: its just doing the swappy
+ unsafe {
+ let p = self.pixel(x, middle);
+ let p2 = self.pixel(x2, middle);
+ self.set_pixel(x, middle, p2);
+ self.set_pixel(x2, middle, p);
+ }
}
}
}
+ /// Rotate a image 90 degrees clockwise.
+ /// # Safety
+ ///
+ /// UB if the image is not square
#[inline]
- unsafe fn rot_90(&mut self) {
+ pub unsafe fn rot_90(&mut self) {
// This is done by first flipping
self.flip_v();
- // Then transposing the image, to save allocations.
+ // Then transposing the image, as to not allocate.
// SAFETY: caller ensures square
unsafe { transpose(self) };
}
+ /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise.
+ /// # Safety
+ ///
+ /// UB if the image is not square
#[inline]
- unsafe fn rot_270(&mut self) {
+ pub unsafe fn rot_270(&mut self) {
self.flip_h();
// SAFETY: caller ensures squareness
unsafe { transpose(self) };
@@ -219,35 +236,3 @@ mod tests {
);
}
}
-
-#[cfg(test)]
-mod bench {
- use super::*;
- extern crate test;
- use crate::Image;
- use test::Bencher;
-
- macro_rules! bench {
- (fn $name: ident() { run $fn: ident() }) => {
- #[bench]
- fn $name(b: &mut Bencher) {
- let mut img: Image<_, 4> = Image::new(
- 64.try_into().unwrap(),
- 64.try_into().unwrap(),
- include_bytes!("../test_data/4_180x180.imgbuf").to_vec(),
- );
- b.iter(|| {
- for _ in 0..256 {
- img.flip_h();
- }
- });
- }
- };
- }
-
- bench!(fn flip_h() { run flip_h() });
- bench!(fn flip_v() { run flip_v() });
- bench!(fn rotate_90() { run rot_90() });
- bench!(fn rotate_180() { run rot_180() });
- bench!(fn rotate_270() { run rot_270() });
-}
diff --git a/src/builder.rs b/src/builder.rs
new file mode 100644
index 0000000..be5a837
--- /dev/null
+++ b/src/builder.rs
@@ -0,0 +1,98 @@
+//! safe builder for the image
+//!
+//! does not let you do funny things
+use std::marker::PhantomData;
+
+use crate::Image;
+
+impl<B: buf::Buffer, const C: usize> Image<B, C> {
+ /// creates a builder
+ pub const fn build(w: u32, h: u32) -> Builder<B, C> {
+ Builder::new(w, h)
+ }
+}
+
+/// Safe [Image] builder.
+pub struct Builder<B, const C: usize> {
+ /// the width in a zeroable type. zeroable so as to make the check in [`buf`] easier.
+ width: u32,
+ /// the height in a zeroable type.
+ height: u32,
+ #[allow(clippy::missing_docs_in_private_items)]
+ _buffer: PhantomData<B>,
+}
+impl<B: buf::Buffer, const C: usize> Builder<B, C> {
+ /// create new builder
+ pub const fn new(w: u32, h: u32) -> Self {
+ Self {
+ width: w,
+ height: h,
+ _buffer: PhantomData,
+ }
+ }
+
+ /// apply a buffer, and build
+ #[track_caller]
+ pub fn buf(self, buffer: B) -> Image<B, C> {
+ let len = C as u32 * self.width * self.height;
+ assert!(
+ buffer.len() as u32 == len,
+ "invalid buffer size (expected {len}, got {})",
+ buffer.len()
+ );
+ Image {
+ buffer,
+ width: self.width.try_into().expect("passed zero width to builder"),
+ height: self
+ .height
+ .try_into()
+ .expect("passed zero height to builder"),
+ }
+ }
+}
+
+impl<const C: usize> Builder<Vec<u8>, C> {
+ /// allocate this image
+ pub fn alloc(self) -> Image<Vec<u8>, C> {
+ Image::alloc(self.width, self.height)
+ }
+}
+
+/// seals the [`Buffer`] trait
+mod buf {
+ /// A valid buffer for use in the builder
+ pub trait Buffer {
+ #[doc(hidden)]
+ fn len(&self) -> usize;
+ }
+ impl<T> Buffer for Vec<T> {
+ fn len(&self) -> usize {
+ self.len()
+ }
+ }
+ impl<T> Buffer for &[T] {
+ fn len(&self) -> usize {
+ <[T]>::len(self)
+ }
+ }
+ impl<T> Buffer for &mut [T] {
+ fn len(&self) -> usize {
+ <[T]>::len(self)
+ }
+ }
+ impl<T, const N: usize> Buffer for [T; N] {
+ fn len(&self) -> usize {
+ N
+ }
+ }
+ impl<T, const N: usize> Buffer for &[T; N] {
+ fn len(&self) -> usize {
+ N
+ }
+ }
+ impl<T, const N: usize> Buffer for &mut [T; N] {
+ fn len(&self) -> usize {
+ N
+ }
+ }
+}
diff --git a/src/cat.png b/src/cat.png
new file mode 100644
index 0000000..361804d
--- /dev/null
+++ b/src/cat.png
Binary files differ
diff --git a/src/drawing/box.rs b/src/drawing/box.rs
new file mode 100644
index 0000000..15f183f
--- /dev/null
+++ b/src/drawing/box.rs
@@ -0,0 +1,65 @@
+//! `Box<cat>`
+use crate::Image;
+
+impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Draw a bordered box
+ ///
+ /// # Safety
+ ///
+ /// UB if the box is out of bounds
+ /// ```
+ /// # use fimg::Image;
+ /// let mut b = Image::alloc(10, 9);
+ /// unsafe { b.as_mut().r#box((1, 1), 7, 6, [255]) };
+ /// # assert_eq!(b.buffer(), b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
+ /// ```
+ pub unsafe fn r#box(
+ &mut self,
+ (x1, y1): (u32, u32),
+ width: u32,
+ height: u32,
+ c: [u8; CHANNELS],
+ ) {
+ // skip sides, leave that to second loop
+ for x in x1 + 1..width + x1 {
+ // top line
+ // SAFETY: responsibility is on caller
+ unsafe { self.set_pixel(x, x1, c) };
+ // bottom line
+ // SAFETY: shift responsibility
+ unsafe { self.set_pixel(x, x1 + height, c) };
+ }
+ for y in y1..=height + y1 {
+ // SAFETY: >> responsibility
+ unsafe { self.set_pixel(y1, y, c) };
+ // SAFETY: << responsibility
+ unsafe { self.set_pixel(y1 + width, y, c) };
+ }
+ }
+
+ /// Draw a *filled* box.
+ ///
+ /// # Safety
+ ///
+ /// UB if box is out of bounds
+ /// ```
+ /// # use fimg::Image;
+ /// let mut b = Image::alloc(10, 9);
+ /// unsafe { b.as_mut().filled_box((1, 1), 7, 6, [255]) };
+ /// # assert_eq!(b.buffer(), b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
+ /// ```
+ pub unsafe fn filled_box(
+ &mut self,
+ (x1, y1): (u32, u32),
+ width: u32,
+ height: u32,
+ c: [u8; CHANNELS],
+ ) {
+ for x in x1..=width + x1 {
+ for y in y1..=height + y1 {
+ // SAFETY: fill it
+ unsafe { self.set_pixel(x, y, c) };
+ }
+ }
+ }
+}
diff --git a/src/drawing/line.rs b/src/drawing/line.rs
new file mode 100644
index 0000000..c48f923
--- /dev/null
+++ b/src/drawing/line.rs
@@ -0,0 +1,174 @@
+//! adds a `line` function to Image
+#![allow(clippy::missing_docs_in_private_items)]
+use crate::Image;
+use std::iter::Iterator;
+
+/// taken from https://github.com/mbr/bresenham-rs/
+pub struct Bresenham {
+ x: i32,
+ y: i32,
+ dx: i32,
+ dy: i32,
+ x1: i32,
+ diff: i32,
+ octant: Octant,
+}
+
+#[derive(Copy, Clone)]
+struct Octant(u8);
+
+impl Octant {
+ #[inline]
+ const fn from_points(start: (i32, i32), end: (i32, i32)) -> Octant {
+ let mut dx = end.0 - start.0;
+ let mut dy = end.1 - start.1;
+
+ let mut octant = 0;
+
+ if dy < 0 {
+ dx = -dx;
+ dy = -dy;
+ octant += 4;
+ }
+
+ if dx < 0 {
+ let tmp = dx;
+ dx = dy;
+ dy = -tmp;
+ octant += 2
+ }
+
+ if dx < dy {
+ octant += 1
+ }
+
+ Octant(octant)
+ }
+
+ #[inline]
+ const fn to_octant0(self, p: (i32, i32)) -> (i32, i32) {
+ match self.0 {
+ 0 => (p.0, p.1),
+ 1 => (p.1, p.0),
+ 2 => (p.1, -p.0),
+ 3 => (-p.0, p.1),
+ 4 => (-p.0, -p.1),
+ 5 => (-p.1, -p.0),
+ 6 => (-p.1, p.0),
+ 7 => (p.0, -p.1),
+ _ => unreachable!(),
+ }
+ }
+
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_octant0(self, p: (i32, i32)) -> (i32, i32) {
+ match self.0 {
+ 0 => (p.0, p.1),
+ 1 => (p.1, p.0),
+ 2 => (-p.1, p.0),
+ 3 => (-p.0, p.1),
+ 4 => (-p.0, -p.1),
+ 5 => (-p.1, -p.0),
+ 6 => (p.1, -p.0),
+ 7 => (p.0, -p.1),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl Bresenham {
+ /// Creates a new iterator. Yields intermediate points between `start`
+ /// and `end`. Includes `start` and `end`.
+ #[inline]
+ pub const fn new(start: (i32, i32), end: (i32, i32)) -> Bresenham {
+ let octant = Octant::from_points(start, end);
+
+ let start = octant.to_octant0(start);
+ let end = octant.to_octant0(end);
+
+ let dx = end.0 - start.0;
+ let dy = end.1 - start.1;
+
+ Bresenham {
+ x: start.0,
+ y: start.1,
+ dy,
+ dx,
+ x1: end.0,
+ diff: dy - dx,
+ octant,
+ }
+ }
+}
+
+impl Iterator for Bresenham {
+ type Item = (i32, i32);
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.x > self.x1 {
+ return None;
+ }
+
+ let p = (self.x, self.y);
+
+ if self.diff >= 0 {
+ self.y += 1;
+ self.diff -= self.dx;
+ }
+
+ self.diff += self.dy;
+
+ // loop inc
+ self.x += 1;
+
+ Some(self.octant.from_octant0(p))
+ }
+}
+
+impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Draw a line from point a to point b
+ ///
+ /// Points not in bounds will not be included.
+ ///
+ /// Uses [bresenshams](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm) line algorithm.
+ pub fn line(&mut self, a: (i32, i32), b: (i32, i32), color: [u8; CHANNELS]) {
+ for (x, y) in Bresenham::new(a, b).map(|(x, y)| (x as u32, y as u32)) {
+ if x < self.width() && y < self.height() {
+ // SAFETY: bound are checked ^
+ unsafe { self.set_pixel(x, y, color) };
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn bresenham() {
+ macro_rules! test_bresenham {
+ ($a:expr, $b:expr => [$(($x:expr, $y:expr)),+]) => {{
+ let mut bi = Bresenham::new($a, $b);
+ $(assert_eq!(bi.next(), Some(($x, $y)));)+
+ assert_eq!(bi.next(), None);
+ }}
+ }
+ test_bresenham!((6, 4), (0, 1) => [(6, 4), (5, 4), (4, 3), (3, 3), (2, 2), (1, 2), (0, 1)]);
+ test_bresenham!((2, 3), (2, 6) => [(2, 3), (2, 4), (2, 5), (2, 6)]);
+ test_bresenham!((2, 3), (5, 3) => [(2, 3), (3, 3), (4, 3), (5, 3)]);
+ test_bresenham!((0, 1), (6, 4) => [(0, 1), (1, 1), (2, 2), (3, 2), (4, 3), (5, 3), (6, 4)]);
+ }
+
+ #[test]
+ fn line() {
+ let mut a = Image::build(5, 5).alloc();
+ a.as_mut().line((0, 1), (6, 4), [255]);
+ assert_eq!(
+ a.buffer,
+ b"\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00"
+ )
+ }
+}
diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs
new file mode 100644
index 0000000..6ffdf23
--- /dev/null
+++ b/src/drawing/mod.rs
@@ -0,0 +1,4 @@
+//! contains drawing operations, like {line, box, triangle} drawing
+mod r#box;
+mod line;
+mod tri;
diff --git a/src/drawing/tri.rs b/src/drawing/tri.rs
new file mode 100644
index 0000000..3cc390b
--- /dev/null
+++ b/src/drawing/tri.rs
@@ -0,0 +1,45 @@
+//! trongle drawing
+use crate::Image;
+
+impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Draw a (filled) triangle
+ ///
+ /// # Safety
+ ///
+ /// UB if any point is out of bounds
+ /// ```
+ /// # use fimg::*;
+ /// let mut a = Image::alloc(10, 10);
+ /// // draw a triangle from point a v point b v point c v
+ /// // with color white
+ /// unsafe { a.as_mut().tri((3.0, 2.0), (8.0, 7.0), (1.0, 8.0), [255]) };
+ /// # assert_eq!(a.buffer(), b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
+ /// ```
+ pub unsafe fn tri(
+ &mut self,
+ (x1, y1): (f32, f32),
+ (x2, y2): (f32, f32),
+ (x3, y3): (f32, f32),
+ c: [u8; CHANNELS],
+ ) {
+ // TODO optimize
+ for y in y1.min(y2).min(y3) as u32..y1.max(y2).max(y3) as u32 {
+ for x in x1.min(x2).min(x3) as u32..x1.max(x2).max(x3) as u32 {
+ let s = (x1 - x3) * (y as f32 - y3) - (y1 - y2) * (x as f32 - x3);
+ let t = (x2 - x1) * (y as f32 - y1) - (y2 - y1) * (x as f32 - x1);
+
+ if (s < 0.0) != (t < 0.0) && s != 0.0 && t != 0.0 {
+ continue;
+ }
+
+ let d = (x3 - x2) * (y as f32 - y2) - (y3 - y2) * (x as f32 - x2);
+ if d == 0.0 || (d < 0.0) == (s + t <= 0.0) {
+ // SAFETY:
+ // caller gurantees triangle is in bounds, this loops over the
+ // bounding box of the triangle, therefore this is fine.
+ unsafe { self.set_pixel(x, y, c) };
+ }
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index fda1cb2..9de0643 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,37 +1,42 @@
+//! # fimg
+//!
+//! Provides fast image operations, such as rotation, flipping, and overlaying.
#![feature(
slice_swap_unchecked,
+ generic_const_exprs,
slice_as_chunks,
unchecked_math,
portable_simd,
+ const_option,
array_chunks,
test
)]
#![warn(
+ clippy::missing_docs_in_private_items,
clippy::multiple_unsafe_ops_per_block,
+ clippy::undocumented_unsafe_blocks,
clippy::missing_const_for_fn,
clippy::missing_safety_doc,
unsafe_op_in_unsafe_fn,
clippy::dbg_macro,
- clippy::perf
+ missing_docs
)]
-#![allow(clippy::zero_prefixed_literal)]
+#![allow(clippy::zero_prefixed_literal, incomplete_features)]
use std::{num::NonZeroU32, slice::SliceIndex};
mod affine;
+pub mod builder;
+mod drawing;
mod overlay;
-pub use affine::{Flips, Rotations};
+pub mod scale;
pub use overlay::{Overlay, OverlayAt};
-pub trait RepeatNew {
- type Output;
- /// Repeat self till it fills a new image of size x, y
- /// # Safety
- ///
- /// UB if self's width is not a multiple of x, or self's height is not a multiple of y
- unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output;
-}
-
+/// like assert!(), but causes undefined behaviour at runtime when the condition is not met.
+///
+/// # Safety
+///
+/// UB if condition is false.
macro_rules! assert_unchecked {
($cond:expr) => {{
if !$cond {
@@ -46,9 +51,12 @@ macro_rules! assert_unchecked {
}
use assert_unchecked;
-impl RepeatNew for Image<&[u8], 3> {
- type Output = Image<Vec<u8>, 3>;
- unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output {
+impl Image<&[u8], 3> {
+ /// Repeat self till it fills a new image of size x, y
+ /// # Safety
+ ///
+ /// UB if self's width is not a multiple of x, or self's height is not a multiple of y
+ pub unsafe fn repeated(&self, x: u32, y: u32) -> Image<Vec<u8>, 3> {
let mut img = Image::alloc(x, y); // could probably optimize this a ton but eh
for x in 0..(x / self.width()) {
for y in 0..(y / self.height()) {
@@ -61,54 +69,96 @@ impl RepeatNew for Image<&[u8], 3> {
}
}
+/// calculates a column major index, with unchecked math
#[inline]
unsafe fn really_unsafe_index(x: u32, y: u32, w: u32) -> usize {
// y * w + x
+ // SAFETY: FIXME make safe math
let tmp = unsafe { (y as usize).unchecked_mul(w as usize) };
+ // SAFETY: FIXME make safe math
unsafe { tmp.unchecked_add(x as usize) }
}
+/// A image with a variable number of channels, and a nonzero size.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Image<T, const CHANNELS: usize> {
- pub buffer: T,
- pub width: NonZeroU32,
- pub height: NonZeroU32,
-}
-
-impl<const CHANNELS: usize> Default for Image<&'static [u8], CHANNELS> {
- fn default() -> Self {
- Self {
- buffer: &[0; CHANNELS],
- width: NonZeroU32::new(1).unwrap(),
- height: NonZeroU32::new(1).unwrap(),
- }
- }
+ /// column order 2d slice/vec
+ buffer: T,
+ /// image horizontal size
+ width: NonZeroU32,
+ /// image vertical size
+ height: NonZeroU32,
}
impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
#[inline]
+ /// get the height as a [`u32`]
pub fn height(&self) -> u32 {
self.height.into()
}
#[inline]
+ /// get the width as a [`u32`]
pub fn width(&self) -> u32 {
self.width.into()
}
#[inline]
- pub const fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self {
- Image {
+ /// create a new image
+ ///
+ /// # Safety
+ ///
+ /// does not check that buffer.len() == w * h * C
+ ///
+ /// using this with invalid values may result in future UB
+ pub const unsafe fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self {
+ Self {
buffer,
width,
height,
}
}
+
+ /// consumes the image, returning the image buffer
+ pub fn take_buffer(self) -> T {
+ self.buffer
+ }
+
+ /// returns a immutable reference to the backing buffer
+ pub const fn buffer(&self) -> &T {
+ &self.buffer
+ }
+
+ /// returns a mutable(!) reference to the backing buffer
+ ///
+ /// # Safety
+ ///
+ /// please do not change buffer size.
+ pub unsafe fn buffer_mut(&mut self) -> &mut T {
+ &mut self.buffer
+ }
+}
+
+impl<const CHANNELS: usize, T: Clone> Image<&[T], CHANNELS> {
+ /// Allocate a new `Image<Vec<T>>` from this imageref.
+ pub fn to_owned(&self) -> Image<Vec<T>, CHANNELS> {
+ // SAFETY: we have been constructed already, so must be valid
+ unsafe { Image::new(self.width, self.height, self.buffer.to_vec()) }
+ }
+}
+
+impl<const CHANNELS: usize, T: Clone> Image<&mut [T], CHANNELS> {
+ /// Allocate a new `Image<Vec<T>>` from this mutable imageref.
+ pub fn to_owned(&self) -> Image<Vec<T>, CHANNELS> {
+ // SAFETY: we have been constructed already, so must be valid
+ unsafe { Image::new(self.width, self.height, self.buffer.to_vec()) }
+ }
}
impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
#[inline]
#[must_use]
+ /// Copy this ref image
pub const fn copy(&self) -> Self {
Self {
width: self.width,
@@ -116,6 +166,28 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
buffer: self.buffer,
}
}
+
+ /// Create a new immutable image of width x, y.
+ ///
+ /// # Panics
+ ///
+ /// if width || height == 0
+ ///
+ /// ```
+ /// # use fimg::Image;
+ /// let img = Image::make::<5, 5>();
+ /// # let img: Image<_, 4> = img;
+ /// ```
+ pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS>
+ where
+ [(); CHANNELS * WIDTH as usize * HEIGHT as usize]: Sized,
+ {
+ Image {
+ width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"),
+ height: NonZeroU32::new(HEIGHT).expect("passed zero height to builder"),
+ buffer: &[0; CHANNELS * WIDTH as usize * HEIGHT as usize],
+ }
+ }
}
impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
@@ -127,9 +199,12 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
unsafe fn slice(&self, x: u32, y: u32) -> impl SliceIndex<[u8], Output = [u8]> {
debug_assert!(x < self.width(), "x out of bounds");
debug_assert!(y < self.height(), "y out of bounds");
+ // SAFETY: me when uncheck math: 😧
let index = unsafe { really_unsafe_index(x, y, self.width()) };
+ // SAFETY: 🧐 is unsound? 😖
let index = unsafe { index.unchecked_mul(CHANNELS) };
debug_assert!(self.buffer.len() > index);
+ // SAFETY: as long as the buffer isnt wrong, this is 😄
index..unsafe { index.unchecked_add(CHANNELS) }
}
@@ -150,8 +225,11 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
/// - UB if buffer is too small
#[inline]
pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] {
+ // SAFETY: we have been told x, y is in bounds
let idx = unsafe { self.slice(x, y) };
+ // SAFETY: slice always returns a valid index
let ptr = unsafe { self.buffer.get_unchecked(idx).as_ptr().cast() };
+ // SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience.
unsafe { *ptr }
}
}
@@ -164,7 +242,9 @@ impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
/// - UB if buffer is too small
#[inline]
pub unsafe fn pixel_mut(&mut self, x: u32, y: u32) -> &mut [u8] {
+ // SAFETY: we have been told x, y is in bounds.
let idx = unsafe { self.slice(x, y) };
+ // SAFETY: slice should always return a valid index
unsafe { self.buffer.get_unchecked_mut(idx) }
}
@@ -192,37 +272,39 @@ impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
}
}
-pub trait FromRef<const CHANNELS: usize> {
- /// Reference the buffer
- fn as_ref(&self) -> Image<&[u8], CHANNELS>;
-}
-
-pub trait FromRefMut<const CHANNELS: usize> {
- /// Reference the buffer, mutably
- fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS>;
-}
-
-impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<&mut [u8], CHANNELS> {
- fn as_ref(&self) -> Image<&[u8], CHANNELS> {
- Image::new(self.width, self.height, self.buffer)
+impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Downcast the mutable reference
+ pub fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+ // SAFETY: we got constructed okay, parameters must be valid
+ unsafe { Image::new(self.width, self.height, self.buffer) }
}
-}
-impl<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<&mut [u8], CHANNELS> {
- fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
- Image::new(self.width, self.height, self.buffer)
+ /// Copy this ref image
+ pub fn copy(&mut self) -> Image<&mut [u8], CHANNELS> {
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ unsafe {
+ Image::new(self.width, self.height, self.buffer)
+ }
}
}
-impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<Vec<u8>, CHANNELS> {
- fn as_ref(&self) -> Image<&[u8], CHANNELS> {
- Image::new(self.width, self.height, &self.buffer)
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
+ /// Create a reference to this owned image
+ pub fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ unsafe {
+ Image::new(self.width, self.height, &self.buffer)
+ }
}
}
-impl<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<Vec<u8>, CHANNELS> {
- fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
- Image::new(self.width, self.height, &mut self.buffer)
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
+ /// Create a mutable reference to this owned image
+ pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ unsafe {
+ Image::new(self.width, self.height, &mut self.buffer)
+ }
}
}
@@ -234,15 +316,27 @@ impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
/// if width || height == 0
#[must_use]
pub fn alloc(width: u32, height: u32) -> Self {
- Image {
+ Self {
width: width.try_into().unwrap(),
height: height.try_into().unwrap(),
buffer: vec![0; CHANNELS * width as usize * height as usize],
}
}
}
+
+/// helper macro for defining the save() method.
macro_rules! save {
($channels:literal == $clr:ident ($clrhuman:literal)) => {
+ impl Image<Vec<u8>, $channels> {
+ #[cfg(feature = "save")]
+ #[doc = "Save this "]
+ #[doc = $clrhuman]
+ #[doc = " image."]
+ pub fn save(&self, f: impl AsRef<std::path::Path>) {
+ self.as_ref().save(f)
+ }
+ }
+
impl Image<&[u8], $channels> {
#[cfg(feature = "save")]
#[doc = "Save this "]
@@ -268,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!(4 == Rgba("RGBA"));
save!(2 == GrayscaleAlpha("YA"));
@@ -275,14 +392,19 @@ save!(1 == Grayscale("Y"));
#[cfg(test)]
macro_rules! img {
- [[$($v:literal),+] [$($v2:literal),+]] => {{
- let from: Image<Vec<u8>, 1> = Image::new(
- 2.try_into().unwrap(),
- 2.try_into().unwrap(),
- vec![$($v,)+ $($v2,)+]
- );
- from
- }}
+ [[$($v:literal),+] [$($v2:literal),+]] => {
+ Image::<Vec<u8>, 1>::build(2,2).buf(vec![$($v,)+ $($v2,)+])
+ }
}
#[cfg(test)]
use img;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ #[test]
+ fn repeat() {
+ let x: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("../benches/3_8x8.imgbuf"));
+ unsafe { x.repeated(128, 128) }; // repeat 16 times
+ }
+}
diff --git a/src/overlay.rs b/src/overlay.rs
index d1211a9..3dbc45e 100644
--- a/src/overlay.rs
+++ b/src/overlay.rs
@@ -1,8 +1,10 @@
+//! Handles image overlay
use super::{assert_unchecked, really_unsafe_index, Image};
use std::simd::SimdInt;
use std::simd::SimdPartialOrd;
use std::simd::{simd_swizzle, Simd};
+/// Trait for layering a image ontop of another, with a offset to the second image.
pub trait OverlayAt<W> {
/// Overlay with => self at coordinates x, y, without blending
/// # Safety
@@ -10,7 +12,8 @@ pub trait OverlayAt<W> {
/// UB if x, y is out of bounds
unsafe fn overlay_at(&mut self, with: &W, x: u32, y: u32) -> &mut Self;
}
-
+/// Trait for layering images ontop of each other.
+/// Think `magick a b -layers flatten a`
pub trait Overlay<W> {
/// Overlay with => self (does not blend)
/// # Safety
@@ -20,15 +23,20 @@ pub trait Overlay<W> {
}
#[inline]
+/// SIMD accelerated rgba => rgb overlay.
+///
+/// See [blit](https://en.wikipedia.org/wiki/Bit_blit)
+///
+/// # Safety
+/// - UB if rgb.len() % 3 != 0
+/// - UB if rgba.len() % 4 != 0
unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
- const LAST4: Simd<u8, 16> = Simd::from_array([
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
- ]);
-
let mut srci = 0;
let mut dsti = 0;
while dsti + 16 <= rgb.len() {
+ // SAFETY: i think it ok
let old: Simd<u8, 16> = Simd::from_slice(unsafe { rgb.get_unchecked(dsti..dsti + 16) });
+ // SAFETY: definetly ok
let new: Simd<u8, 16> = Simd::from_slice(unsafe { rgba.get_unchecked(srci..srci + 16) });
let threshold = new.simd_ge(Simd::splat(128)).to_int().cast::<u8>();
@@ -36,10 +44,13 @@ unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
threshold,
[3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0]
);
- mask &= LAST4;
+ mask &= Simd::from_array([
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
+ ]);
let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]);
let blended = (new_rgb & mask) | (old & !mask);
+ // SAFETY: 4 * 4 == 16, so in bounds
blended.copy_to_slice(unsafe { rgb.get_unchecked_mut(dsti..dsti + 16) });
srci += 16;
@@ -47,10 +58,13 @@ unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
}
while dsti + 3 <= rgb.len() {
+ // SAFETY: caller gurantees slice is big enough
if unsafe { *rgba.get_unchecked(srci + 3) } >= 128 {
- let src = unsafe { rgba.get_unchecked(srci..srci + 3) };
- let end = unsafe { rgb.get_unchecked_mut(dsti..dsti + 3) };
- unsafe { std::ptr::copy_nonoverlapping(src.as_ptr(), end.as_mut_ptr(), 3) };
+ // SAFETY: slice is big enough!
+ let src = unsafe { rgba.get_unchecked(srci..=srci + 2) };
+ // SAFETY: i hear it bound
+ let end = unsafe { rgb.get_unchecked_mut(dsti..=dsti + 2) };
+ end.copy_from_slice(src);
}
srci += 4;
@@ -65,16 +79,9 @@ impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 4> {
debug_assert!(self.height() == with.height());
for (i, other_pixels) in with.chunked().enumerate() {
if other_pixels[3] >= 128 {
- let idx_begin = unsafe { i.unchecked_mul(4) };
- let idx_end = unsafe { idx_begin.unchecked_add(4) };
- let own_pixels = unsafe { self.buffer.get_unchecked_mut(idx_begin..idx_end) };
- unsafe {
- std::ptr::copy_nonoverlapping(
- other_pixels.as_ptr(),
- own_pixels.as_mut_ptr(),
- 4,
- );
- };
+ // SAFETY: outside are bounds of index from slice
+ let own_pixels = unsafe { self.buffer.get_unchecked_mut(i * 4..i * 4 + 4) };
+ own_pixels.copy_from_slice(other_pixels);
}
}
self
@@ -84,9 +91,9 @@ impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 4> {
impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 3> {
#[inline]
unsafe fn overlay_at(&mut self, with: &Image<&[u8], 4>, x: u32, y: u32) -> &mut Self {
- // SAFETY: caller upholds these
+ // SAFETY: caller upholds this
unsafe { assert_unchecked!(x + with.width() <= self.width()) };
- unsafe { assert_unchecked!(y + with.height() <= self.height()) };
+ debug_assert!(y + with.height() <= self.height());
for j in 0..with.height() {
let i_x = j as usize * with.width() as usize * 4
..(j as usize + 1) * with.width() as usize * 4;
@@ -95,8 +102,11 @@ impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 3> {
+ x as usize
+ with.width() as usize)
* 3;
+ // SAFETY: index is in bounds
let rgb = unsafe { self.buffer.get_unchecked_mut(o_x) };
+ // SAFETY: bounds are outside index
let rgba = unsafe { with.buffer.get_unchecked(i_x) };
+ // SAFETY: arguments are 🟢
unsafe { blit(rgb, rgba) }
}
self
@@ -104,8 +114,16 @@ impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 3> {
}
impl OverlayAt<Image<&[u8], 3>> for Image<&mut [u8], 3> {
+ /// Overlay a RGB image(with) => self at coordinates x, y.
+ /// As this is a `RGBxRGB` operation, blending is unnecessary,
+ /// and this is simply a copy.
+ ///
+ /// # Safety
+ ///
+ /// UB if x, y is out of bounds
#[inline]
unsafe fn overlay_at(&mut self, with: &Image<&[u8], 3>, x: u32, y: u32) -> &mut Self {
+ /// helper macro for defining rgb=>rgb overlays. allows unrolling
macro_rules! o3x3 {
($n:expr) => {{
for j in 0..($n as usize) {
@@ -113,7 +131,12 @@ impl OverlayAt<Image<&[u8], 3>> for Image<&mut [u8], 3> {
let o_x = ((j + y as usize) * self.width() as usize + x as usize) * 3
..((j + y as usize) * self.width() as usize + x as usize + ($n as usize))
* 3;
+ // <= because ".." range
+ debug_assert!(o_x.end <= self.buffer().len());
+ debug_assert!(i_x.end <= with.buffer().len());
+ // SAFETY: bounds are ✅
let a = unsafe { self.buffer.get_unchecked_mut(o_x) };
+ // SAFETY: we are in ⬜!
let b = unsafe { with.buffer.get_unchecked(i_x) };
a.copy_from_slice(b);
}
@@ -139,11 +162,13 @@ impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 3> {
.chunks_exact(with.width() as usize * 4)
.enumerate()
{
+ // SAFETY: all the bounds are good
let rgb = unsafe {
self.buffer.get_unchecked_mut(
i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3,
)
};
+ // SAFETY: we have the rgb and rgba arguments right
unsafe { blit(rgb, chunk) };
}
self
@@ -152,15 +177,30 @@ impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 3> {
impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 4> {
#[inline]
+ /// Overlay with => self at coordinates x, y, without blending
+ ///
+ /// # Safety
+ /// - UB if x, y is out of bounds
+ /// - UB if x + with.width() > [`u32::MAX`]
+ /// - UB if y + with.height() > [`u32::MAX`]
unsafe fn overlay_at(&mut self, with: &Image<&[u8], 4>, x: u32, y: u32) -> &mut Self {
for j in 0..with.height() {
for i in 0..with.width() {
+ // SAFETY: i, j is in bounds.
let index = unsafe { really_unsafe_index(i, j, with.width()) };
+ // SAFETY: using .pixel() results in horrible asm (+5k ns/iter)
let their_px = unsafe { with.buffer.get_unchecked(index * 4..index * 4 + 4) };
+ // SAFETY: must be sized right
if unsafe { *their_px.get_unchecked(3) } >= 128 {
+ // SAFETY:
+ // they said it cant go over.
+ // i dont know why, but this has performance importance™
let x = unsafe { i.unchecked_add(x) };
+ // SAFETY: caller gurantees this cannot overflow.
let y = unsafe { j.unchecked_add(y) };
+ // SAFETY: compute the offset index.
let index = unsafe { really_unsafe_index(x, y, self.width()) };
+ // SAFETY: if everything else goes well, this is fine
let our_px = unsafe { self.buffer.get_unchecked_mut(index * 4..index * 4 + 4) };
our_px.copy_from_slice(their_px);
}
diff --git a/src/scale.rs b/src/scale.rs
new file mode 100644
index 0000000..0ba614b
--- /dev/null
+++ b/src/scale.rs
@@ -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
+ );
+}
diff --git a/src/small_cat.png b/src/small_cat.png
new file mode 100644
index 0000000..ec6e5bf
--- /dev/null
+++ b/src/small_cat.png
Binary files differ