initial commit
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules/
|
||||||
|
target/
|
||||||
|
pkg/
|
||||||
|
.DS_Store
|
||||||
7
README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
_Spiegel_ image filter project (WIP)
|
||||||
|
|
||||||
|
- rust
|
||||||
|
- wasm
|
||||||
|
|
||||||
|
sample output
|
||||||
|

|
||||||
BIN
dist/11dc9380193954aac8c4.module.wasm
vendored
Normal file
BIN
dist/630027c604733df47374e4f5adb1b7c5.jpg
vendored
Normal file
|
After Width: | Height: | Size: 349 KiB |
BIN
dist/66d531fb4651c57454ae.module.wasm
vendored
Normal file
1
dist/796.bundle.js
vendored
Normal file
BIN
dist/93be161a4640fe100e05af248fa4c52e.png
vendored
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
dist/95cc0985b7bd6242de9b9665261616a3.jpg
vendored
Normal file
|
After Width: | Height: | Size: 192 KiB |
523
dist/bundle.js
vendored
Normal file
42
dist/crate_pkg_photon_rs_js.bundle.js
vendored
Normal file
42
dist/crate_pkg_spiegel_client_js.bundle.js
vendored
Normal file
BIN
dist/df3fbe72e3ad368ae5bf.module.wasm
vendored
Normal file
BIN
dist/ea872833a419652a23b47d50be7fe0ef.jpg
vendored
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
dist/f49f7893ad0a3ad10176.module.wasm
vendored
Normal file
29
dist/index.html
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||||
|
<title>Spiegel</title>
|
||||||
|
<script defer src="bundle.js"></script></head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="default">
|
||||||
|
<div class="main">
|
||||||
|
<label>
|
||||||
|
<h2>Blur factor</h2< /label>
|
||||||
|
<div class="slidecontainer">
|
||||||
|
<input type="range" id="slider" value="0" min="0" max="100" class="slider" />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<div class="main_content">
|
||||||
|
<div class="content" id="images">
|
||||||
|
<div id="image_container"></div>
|
||||||
|
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
30
index.html
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||||
|
<title>Spiegel</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="main">
|
||||||
|
<label>
|
||||||
|
<h2>Blur factor</h2>
|
||||||
|
<h4 id="msg">(blurring can take up to 15 seconds, please be patient)</h4>
|
||||||
|
</label>
|
||||||
|
<div class="slidecontainer">
|
||||||
|
<input type="range" id="slider" value="0" min="0" max="100" class="slider" />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<div class="main_content">
|
||||||
|
<div id="progress"></div>
|
||||||
|
<div class="content" id="images">
|
||||||
|
<div id="image_container"></div>
|
||||||
|
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
6753
package-lock.json
generated
Normal file
25
package.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"author": "Silvia O'Dwyer <silviaodwyerdev@gmail.com>",
|
||||||
|
"name": "photon-wasm",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"repository": "https://github.com/silvia-odwyer/photon",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server",
|
||||||
|
"build": "webpack"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"create-rust-webpack": ".bin/create-rust-webpack.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@wasm-tool/wasm-pack-plugin": "0.1.6",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"css-loader": "^6.10.0",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"html-webpack-plugin": "^5.6.0",
|
||||||
|
"style-loader": "^3.3.4",
|
||||||
|
"webpack": "^5.91.0",
|
||||||
|
"webpack-cli": "^5.1.4",
|
||||||
|
"webpack-dev-server": "^5.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
1353
server/Cargo.lock
generated
Normal file
20
server/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "spiegel-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = { version = "0.7" }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
tokio = { version = "1.36", features = ["full"] }
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
image = "0.24.1"
|
||||||
|
anyhow = "1.0"
|
||||||
|
include_dir = "0.7.3"
|
||||||
|
tokio-util = { version = "0.7", features = ["io"] }
|
||||||
|
tower = { version = "0.4", features = ["util"] }
|
||||||
|
tower-http = { version = "0.5.0", features = ["fs", "trace"] }
|
||||||
74
server/src/lib.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use include_dir::{include_dir, Dir, DirEntry};
|
||||||
|
|
||||||
|
static SAMPLES: OnceLock<Vec<ColorSample>> = OnceLock::new();
|
||||||
|
static SAMPLES_DIR: Dir = include_dir!("src/samples");
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
SAMPLES.get_or_init(|| {
|
||||||
|
println!("reading image samples");
|
||||||
|
read_color_samples().unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_closest_color<'a>(color: &String) -> &'a ColorSample {
|
||||||
|
let color_samples = SAMPLES.get().unwrap();
|
||||||
|
let mut closest = None;
|
||||||
|
let mut min_diff: f32 = 4294967295.0; //0xFFFFFFFF
|
||||||
|
for sample in color_samples {
|
||||||
|
let diff = get_distance(sample.r, sample.g, sample.b, color);
|
||||||
|
if diff < min_diff {
|
||||||
|
closest = Some(sample);
|
||||||
|
min_diff = diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closest.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns squared euclidian color distance
|
||||||
|
/// as if colors were points in 3d space
|
||||||
|
fn get_distance(r1: u8, g1: u8, b1: u8, rgb: &String) -> f32 {
|
||||||
|
let r2 = u8::from_str_radix(&rgb[0..2], 16).unwrap();
|
||||||
|
let g2 = u8::from_str_radix(&rgb[2..4], 16).unwrap();
|
||||||
|
let b2 = u8::from_str_radix(&rgb[4..6], 16).unwrap();
|
||||||
|
let red_dif = r1 as f32 - r2 as f32;
|
||||||
|
let green_dif = g1 as f32 - g2 as f32;
|
||||||
|
let blue_dif = b1 as f32 - b2 as f32;
|
||||||
|
return red_dif * red_dif + green_dif * green_dif + blue_dif * blue_dif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read all sample jpegs into memory
|
||||||
|
pub fn read_color_samples() -> anyhow::Result<Vec<ColorSample>> {
|
||||||
|
let mut color_samples: Vec<ColorSample> = Vec::new();
|
||||||
|
|
||||||
|
for entry in SAMPLES_DIR.entries() {
|
||||||
|
if let DirEntry::File(f) = entry {
|
||||||
|
let sample_image = f.contents();
|
||||||
|
|
||||||
|
let filename = entry.path().file_name().unwrap().to_str().unwrap();
|
||||||
|
let hex_r = &filename[0..2];
|
||||||
|
let hex_g = &filename[2..4];
|
||||||
|
let hex_b = &filename[4..6];
|
||||||
|
color_samples.push(ColorSample {
|
||||||
|
filename: filename.into(),
|
||||||
|
r: u8::from_str_radix(&hex_r, 16)?,
|
||||||
|
g: u8::from_str_radix(&hex_g, 16)?,
|
||||||
|
b: u8::from_str_radix(&hex_b, 16)?,
|
||||||
|
image: sample_image,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Done reading image samples");
|
||||||
|
Ok(color_samples)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ColorSample {
|
||||||
|
pub filename: String,
|
||||||
|
pub r: u8,
|
||||||
|
pub g: u8,
|
||||||
|
pub b: u8,
|
||||||
|
pub image: &'static [u8],
|
||||||
|
}
|
||||||
32
server/src/main.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
use axum::extract::Path;
|
||||||
|
use axum::http::{header, StatusCode};
|
||||||
|
use axum::response::IntoResponse;
|
||||||
|
use axum::{routing::get, Router};
|
||||||
|
use spiegel_server::{get_closest_color, init};
|
||||||
|
|
||||||
|
/// serves images from memory
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
init();
|
||||||
|
let app = Router::new().route("/color/:rgb_hex", get(fetch_nearest_color));
|
||||||
|
|
||||||
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
|
axum::serve(listener, app).await.unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_nearest_color(
|
||||||
|
Path(rgb_hex): Path<String>,
|
||||||
|
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
||||||
|
if rgb_hex.len() != 6 {
|
||||||
|
return Err((
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"input should be color hex, eg AA11CC".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let closest = get_closest_color(&rgb_hex);
|
||||||
|
|
||||||
|
let headers = [(header::CONTENT_TYPE, "image/jpeg")];
|
||||||
|
Ok((headers, closest.image))
|
||||||
|
}
|
||||||
BIN
server/src/samples/12110f.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
server/src/samples/131211.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
server/src/samples/21201b.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
server/src/samples/21201d.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
server/src/samples/212213.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
server/src/samples/22211b.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
server/src/samples/23221d.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/23221f.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
server/src/samples/24231d.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/252520.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
server/src/samples/262527.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
server/src/samples/262628.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
server/src/samples/272826.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/291f19.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/292927.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
server/src/samples/292a29.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
server/src/samples/2a2a28.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
server/src/samples/2a3960.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
server/src/samples/2b3a5f.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
server/src/samples/2c2c24.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/2c3b64.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
server/src/samples/2c3c40.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
server/src/samples/2e2d26.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
server/src/samples/2e2d28.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/30301c.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
server/src/samples/303030.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
server/src/samples/303131.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
server/src/samples/303632.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
server/src/samples/31302b.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
server/src/samples/313131.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
server/src/samples/32373a.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
server/src/samples/32373b.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
server/src/samples/333a73.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
server/src/samples/334840.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/343a6f.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
server/src/samples/343b73.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
server/src/samples/344845.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/353420.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
server/src/samples/35342f.jpg
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
server/src/samples/353a39.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
server/src/samples/353b43.jpg
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
server/src/samples/363531.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
server/src/samples/363c71.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
server/src/samples/36414c.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/364968.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/373530.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/373a54.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/373b46.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
server/src/samples/373d2f.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/373d47.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/373d71.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
server/src/samples/382f1f.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/383732.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
server/src/samples/383831.jpg
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
server/src/samples/383832.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/383a46.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
server/src/samples/383c4f.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/383d48.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/384142.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/38495a.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/384b51.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
server/src/samples/393b39.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/394235.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
server/src/samples/3a4042.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
server/src/samples/3a4242.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
server/src/samples/3b4435.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
server/src/samples/3b4a6b.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/3b4f6b.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/3c3b34.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
server/src/samples/3c4d5f.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
server/src/samples/3d342a.jpg
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
server/src/samples/3d4343.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
server/src/samples/3d4a63.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/3e3524.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/3e3830.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
server/src/samples/3e3e32.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
server/src/samples/3e3e4a.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
server/src/samples/3e3f27.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |