made quantize generic for Image
This commit is contained in:
parent
8287731952
commit
e792087ebc
3 changed files with 271 additions and 33 deletions
217
Cargo.lock
generated
217
Cargo.lock
generated
|
|
@ -2,6 +2,12 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e"
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
|
|
@ -50,6 +56,15 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "conv"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||
dependencies = [
|
||||
"custom_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.0"
|
||||
|
|
@ -103,6 +118,12 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "custom_derive"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.8.6"
|
||||
|
|
@ -119,6 +140,17 @@ version = "1.6.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.11.3"
|
||||
|
|
@ -157,6 +189,32 @@ dependencies = [
|
|||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imageproc"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7923654f3ce7cb6849d5dc9e544aaeab49c508a90b56c721b046e7234c74ab53"
|
||||
dependencies = [
|
||||
"conv",
|
||||
"image",
|
||||
"itertools",
|
||||
"num 0.3.1",
|
||||
"rand",
|
||||
"rand_distr",
|
||||
"rayon",
|
||||
"rulinalg",
|
||||
"rusttype",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.1.22"
|
||||
|
|
@ -178,6 +236,15 @@ version = "0.2.112"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
|
||||
[[package]]
|
||||
name = "matrixmultiply"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcad67dcec2d58ff56f6292582377e6921afdf3bfbd533e26fb8900ae575e002"
|
||||
dependencies = [
|
||||
"rawpointer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
|
|
@ -206,6 +273,51 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
|
|
@ -234,6 +346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
|
@ -262,6 +375,16 @@ name = "octo"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"imageproc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3"
|
||||
dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -276,6 +399,68 @@ dependencies = [
|
|||
"miniz_oxide 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_distr"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rawpointer"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.5.1"
|
||||
|
|
@ -301,6 +486,26 @@ dependencies = [
|
|||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rulinalg"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04ada202c9685e1d72a7420c578e92b358dbf807d3dfabb676a3dab9cc3bb12f"
|
||||
dependencies = [
|
||||
"matrixmultiply",
|
||||
"num 0.1.42",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusttype"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped_threadpool"
|
||||
version = "0.1.9"
|
||||
|
|
@ -324,6 +529,18 @@ dependencies = [
|
|||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.5"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
image="0.23.14"
|
||||
imageproc="0.22.0"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
76
src/lib.rs
76
src/lib.rs
|
|
@ -1,10 +1,14 @@
|
|||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use image::{Rgba, RgbaImage};
|
||||
use image::{GenericImageView, Pixel, Rgba, RgbaImage};
|
||||
use imageproc::definitions::Image;
|
||||
|
||||
const MAX_LEVEL: usize = 5;
|
||||
|
||||
pub fn quantize(image: &RgbaImage, num_colors:usize) -> RgbaImage{
|
||||
pub fn quantize<P>(image: &Image<P>, num_colors: usize) -> RgbaImage
|
||||
where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
let mut quantizer = OctTreeQuantizer::new(num_colors);
|
||||
quantizer.quantize(image)
|
||||
}
|
||||
|
|
@ -33,10 +37,14 @@ impl OctTreeQuantizer {
|
|||
new_quantizer
|
||||
}
|
||||
|
||||
pub fn quantize(&mut self, image: &RgbaImage) -> RgbaImage {
|
||||
pub fn quantize<P>(&mut self, image: &Image<P>) -> RgbaImage
|
||||
where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
for y in 0..image.height() {
|
||||
for x in 0..image.width() {
|
||||
self.insert_color(image.get_pixel(x, y), Rc::clone(&self.root));
|
||||
let p = image.get_pixel(x, y);
|
||||
self.insert_color(p, Rc::clone(&self.root));
|
||||
|
||||
if self.colors > self.reduce_colors {
|
||||
self.reduce_tree(self.reduce_colors);
|
||||
|
|
@ -52,8 +60,9 @@ impl OctTreeQuantizer {
|
|||
let mut out = RgbaImage::new(image.width(), image.height());
|
||||
for y in 0..image.height() {
|
||||
for x in 0..image.width() {
|
||||
let pixel = image.get_pixel(x, y);
|
||||
if let Some(index) = self.get_index_for_color(pixel, &self.root) {
|
||||
unsafe { //safe because bounds are checked
|
||||
let pixel = image.unsafe_get_pixel(x, y);
|
||||
if let Some(index) = self.get_index_for_color(&pixel, &self.root) {
|
||||
let color = table.get(index).unwrap();
|
||||
if let Some(color) = color {
|
||||
out.put_pixel(x, y, *color);
|
||||
|
|
@ -61,20 +70,23 @@ impl OctTreeQuantizer {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn get_index_for_color(
|
||||
&self,
|
||||
color: &Rgba<u8>,
|
||||
node: &Rc<RefCell<OctTreeNode>>,
|
||||
) -> Option<usize> {
|
||||
fn get_index_for_color(
|
||||
fn get_index_for_color<P>(&self, color: &P, node: &Rc<RefCell<OctTreeNode>>) -> Option<usize>
|
||||
where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
fn get_index_for_color<P>(
|
||||
quantizer: &OctTreeQuantizer,
|
||||
color: &Rgba<u8>,
|
||||
color: &P,
|
||||
level: usize,
|
||||
node: &Rc<RefCell<OctTreeNode>>,
|
||||
) -> Option<usize> {
|
||||
) -> Option<usize>
|
||||
where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
if level > MAX_LEVEL {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -147,14 +159,19 @@ impl OctTreeQuantizer {
|
|||
table
|
||||
}
|
||||
|
||||
fn insert_color(&mut self, rgb: &Rgba<u8>, node: Rc<RefCell<OctTreeNode>>) {
|
||||
fn insert_color<P>(&mut self, rgb: &P, node: Rc<RefCell<OctTreeNode>>)
|
||||
where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
//nested function that is called recursively
|
||||
fn insert_color(
|
||||
fn insert_color<P>(
|
||||
quantizer: &mut OctTreeQuantizer,
|
||||
color: &Rgba<u8>,
|
||||
color: &P,
|
||||
level: usize,
|
||||
node: Rc<RefCell<OctTreeNode>>,
|
||||
) {
|
||||
) where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
if level > MAX_LEVEL {
|
||||
return;
|
||||
}
|
||||
|
|
@ -169,9 +186,9 @@ impl OctTreeQuantizer {
|
|||
if level == MAX_LEVEL {
|
||||
child.is_leaf = true;
|
||||
child.count = 1;
|
||||
child.total_red = color[0] as u32;
|
||||
child.total_green = color[1] as u32;
|
||||
child.total_blue = color[2] as u32;
|
||||
child.total_red = color.channels()[0] as u32;
|
||||
child.total_green = color.channels()[1] as u32;
|
||||
child.total_blue = color.channels()[2] as u32;
|
||||
child.level = level;
|
||||
quantizer.colors += 1;
|
||||
}
|
||||
|
|
@ -212,9 +229,9 @@ impl OctTreeQuantizer {
|
|||
.unwrap()
|
||||
.borrow_mut();
|
||||
child.count += 1;
|
||||
child.total_red += color[0] as u32;
|
||||
child.total_green += color[1] as u32;
|
||||
child.total_blue += color[2] as u32;
|
||||
child.total_red += color.channels()[0] as u32;
|
||||
child.total_green += color.channels()[1] as u32;
|
||||
child.total_blue += color.channels()[2] as u32;
|
||||
return;
|
||||
} else {
|
||||
insert_color(
|
||||
|
|
@ -325,17 +342,20 @@ impl OctTreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_bitmask(color: &Rgba<u8>, level: &usize) -> usize {
|
||||
fn get_bitmask<P>(color: &P, level: &usize) -> usize
|
||||
where
|
||||
P: Pixel<Subpixel = u8> + 'static,
|
||||
{
|
||||
let bit = 0x80 >> level;
|
||||
|
||||
let mut index = 0;
|
||||
if (color[0] & bit) != 0 {
|
||||
if (color.channels()[0] & bit) != 0 {
|
||||
index += 4;
|
||||
}
|
||||
if (color[1] & bit) != 0 {
|
||||
if (color.channels()[1] & bit) != 0 {
|
||||
index += 2;
|
||||
}
|
||||
if (color[2] & bit) != 0 {
|
||||
if (color.channels()[2] & bit) != 0 {
|
||||
index += 1;
|
||||
}
|
||||
index
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue