Import loop9 0.1.3 upstream upstream/0.1.3
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 6 Apr 2023 07:21:14 +0000 (16:21 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 6 Apr 2023 07:21:14 +0000 (16:21 +0900)
.cargo_vcs_info.json [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Cargo.toml.orig [new file with mode: 0644]
README.md [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]

diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644 (file)
index 0000000..1540f85
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "7211660b2c3eed51c35ee5513648ea837b7ba48b"
+  }
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..9a85aba
--- /dev/null
@@ -0,0 +1,27 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "loop9"
+version = "0.1.3"
+authors = ["Kornel <kornel@geekhood.net>"]
+description = "Tiny helper function to visit every pixel in the image together with its neighboring pixels. Duplicates pixels on the edges."
+homepage = "https://lib.rs/loop9"
+readme = "README.md"
+keywords = ["convolve", "blur", "iterate"]
+categories = ["graphics"]
+license = "MIT"
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+[dependencies.imgref]
+version = "1.7.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644 (file)
index 0000000..bcefdf5
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+authors = ["Kornel <kornel@geekhood.net>"]
+description = "Tiny helper function to visit every pixel in the image together with its neighboring pixels. Duplicates pixels on the edges."
+license = "MIT"
+name = "loop9"
+readme = "README.md"
+version = "0.1.3"
+edition = "2018"
+homepage = "https://lib.rs/loop9"
+categories = ["graphics"]
+keywords = ["convolve", "blur", "iterate"]
+
+[dependencies]
+imgref = "1.7.0"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..fa0cd40
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# 9 neighboring pixels iterator
+
+Tiny helper function to visit every pixel in the image together with its neighboring pixels. Duplicates pixels on the edges.
+
+Ideal for implementing small image convolutions like blur, sharpening or edge detection.
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..2353c48
--- /dev/null
@@ -0,0 +1,147 @@
+use core::ops::Deref;
+use imgref::*;
+
+/// Previous, current, and next pixel or row
+#[derive(Copy,Clone,Debug,Eq,PartialEq)]
+#[repr(C)]
+pub struct Triple<T> {
+    pub prev: T,
+    pub curr: T,
+    pub next: T,
+}
+
+impl<T> Triple<T> {
+    #[inline(always)]
+    pub fn new(prev: T, curr: T, next: T) -> Self {
+        Triple {prev, curr, next}
+    }
+}
+
+impl<T> AsRef<[T]> for Triple<T> {
+    #[inline(always)]
+    fn as_ref(&self) -> &[T] {
+        unsafe {
+            std::slice::from_raw_parts(&self.prev as *const T, 3)
+        }
+    }
+}
+
+impl<T> Deref for Triple<T> {
+    type Target = [T];
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        self.as_ref()
+    }
+}
+
+impl<T: Copy> Triple<T> {
+    /// Add next item, and shift others (prev is gone, prev = current)
+    /// If item is None, it'll copy the last one instead.
+    #[inline(always)]
+    pub fn advance(self, next: Option<T>) -> Self {
+        let next = if let Some(next) = next {next} else {self.next};
+        Triple {
+            prev: self.curr,
+            curr: self.next,
+            next,
+        }
+    }
+}
+
+/// Loop over 9 neighboring pixels in the image described by `ImgRef` (`Img.as_ref()`)
+///
+/// The callback is: (x, y, previous_row, current_row, next_row)
+#[inline(always)]
+pub fn loop9_img<Pixel, Callback>(img: ImgRef<'_, Pixel>, cb: Callback)
+    where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>)
+{
+    loop9(img, 0, 0, img.width(), img.height(), cb)
+}
+
+/// Loop over 9 neighboring pixels in the left/top/width/height fragment of the image described by `ImgRef` (`Img.as_ref()`)
+///
+/// The callback is: (x, y, previous_row, current_row, next_row)
+#[inline]
+pub fn loop9<Pixel, Callback>(img: ImgRef<'_, Pixel>, left: usize, top: usize, width: usize, height: usize, mut cb: Callback)
+    where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>)
+{
+    let max_width = img.width();
+    let max_height = img.height();
+    let stride = img.stride();
+    let data = img.buf().as_ref();
+    let t = top * stride;
+    let mut row = Triple {
+        prev: &data[t..t+max_width],
+        curr: &data[t..t+max_width],
+        next: &data[t..t+max_width],
+    };
+    for y in top..top+height {
+        row = row.advance(if y+1 < max_height {let t=(y+1)*stride; Some(&data[t..t+max_width])} else {None});
+        let mut tp;
+        let mut tn = row.prev[left];
+        let mut tc = row.prev[left.saturating_sub(1)];
+        let mut mp;
+        let mut mn = row.curr[left];
+        let mut mc = row.curr[left.saturating_sub(1)];
+        let mut bp;
+        let mut bn = row.next[left];
+        let mut bc = row.next[left.saturating_sub(1)];
+        for x in left..left+width {
+            tp = tc;
+            tc = tn;
+            tn = if x+1 < max_width {row.prev[x+1]} else {tc};
+            mp = mc;
+            mc = mn;
+            mn = if x+1 < max_width {row.curr[x+1]} else {mc};
+            bp = bc;
+            bc = bn;
+            bn = if x+1 < max_width {row.next[x+1]} else {bc};
+            cb(x-left,y-top,Triple::new(tp,tc,tn),Triple::new(mp,mc,mn),Triple::new(bp,bc,bn));
+        }
+    }
+}
+
+
+#[test]
+fn test_loop9() {
+    let src = vec![
+         1, 2, 3, 4,
+         5, 6, 7, 8,
+         9,10,11,12,
+        13,14,15,16,
+    ];
+    let img = Img::new(src.clone(), 4, 4);
+    assert_eq!(4, img.width());
+    assert_eq!(4, img.stride());
+    assert_eq!(4, img.height());
+
+    let check = |l,t,w,h,exp|{
+        let mut res = Vec::new();
+        loop9(img.as_ref(), l,t,w,h, |_x,_y,_top,mid,_bot| res.push(mid.curr));
+        assert_eq!(exp, res);
+    };
+
+    check(0,0,4,4, src);
+
+    check(0,0,4,1, vec![1, 2, 3, 4]);
+
+    check(0,3,4,1, vec![13,14,15,16]);
+
+    check(0,0,3,3, vec![
+         1, 2, 3,
+         5, 6, 7,
+         9,10,11,
+    ]);
+
+    check(0,0,1,1,vec![1]);
+    check(1,0,1,1,vec![2]);
+    check(2,0,1,1,vec![3]);
+    check(3,0,1,1,vec![4]);
+
+    check(1,0,3,4,vec![
+         2, 3, 4,
+         6, 7, 8,
+        10,11,12,
+        14,15,16,
+    ]);
+}