diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..42cb7d7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +image-processor/target/ +image-processor/pkg/ +.DS_Store +.idea/ +*.iml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f73b391 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# Stage 1: Build +FROM rust:1.86-bookworm AS builder + +# Install Node.js +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs + +# Install wasm-pack +RUN curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + +# Add wasm target +RUN rustup target add wasm32-unknown-unknown + +WORKDIR /app + +# Cache npm dependencies +COPY package*.json ./ +RUN npm ci + +# Cache Rust dependencies +COPY image-processor/Cargo.toml image-processor/Cargo.lock* ./image-processor/ +RUN mkdir -p image-processor/src && echo "pub fn main(){}" > image-processor/src/lib.rs \ + && cd image-processor && cargo fetch + +# Copy full source and build +COPY . . +RUN npm run build + +# Stage 2: Serve +FROM nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html + +EXPOSE 80 diff --git a/README.md b/README.md index 3f59e42..ab89136 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ Live demo at https://shautvast.github.io/spiegel-demo/ -* Sorry for the poor performance, especially on larger images. -* It uses the median image filter from image.rs. That in itself can be pretty slow. -(Although the implementation uses a _sliding window histogram_, which I think is pretty nifty). -* And on top of that, I created this custom flood fill algorithm, -that instead of filling it with with a single color, looks up a sample from the -Spiegel book (that has a corresponding color) and takes the pixels from that. +- Sorry for the poor performance, especially on larger images. +- It uses the median image filter from image.rs. That in itself can be pretty slow. + (Although the implementation uses a _sliding window histogram_, which I think is pretty nifty). +- And on top of that, I created this custom flood fill algorithm, + that instead of filling it with with a single color, looks up a sample from the + Spiegel book (that has a corresponding color) and takes the pixels from that. sample output -![sample](https://github.com/shautvast/spiegel-web/blob/main/unsplash.png) +![sample](unsplash.png) diff --git a/image-processor/Cargo.lock b/image-processor/Cargo.lock index 6df4ce9..e407977 100644 --- a/image-processor/Cargo.lock +++ b/image-processor/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ab_glyph" @@ -24,12 +24,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "aligned-vec" version = "0.5.0" @@ -71,7 +65,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.117", ] [[package]] @@ -99,7 +93,7 @@ dependencies = [ "arrayvec", "log", "nom", - "num-rational 0.4.1", + "num-rational", "serde", "v_frame", ] @@ -113,12 +107,6 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base64" version = "0.13.1" @@ -188,7 +176,7 @@ version = "8.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996" dependencies = [ - "semver 1.0.22", + "semver", "serde", "toml 0.5.11", "url", @@ -242,12 +230,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - [[package]] name = "conv" version = "0.3.3" @@ -313,21 +295,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" [[package]] -name = "deflate" -version = "0.8.6" +name = "deranged" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "adler32", - "byteorder", + "powerfmt", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "either" version = "1.6.1" @@ -350,7 +325,7 @@ dependencies = [ "flume", "half", "lebe", - "miniz_oxide 0.7.2", + "miniz_oxide", "rayon-core", "smallvec", "zune-inflate", @@ -381,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", - "miniz_oxide 0.7.2", + "miniz_oxide", ] [[package]] @@ -426,16 +401,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gif" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "gif" version = "0.13.1" @@ -486,21 +451,18 @@ dependencies = [ [[package]] name = "image" -version = "0.23.14" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" dependencies = [ "bytemuck", "byteorder", "color_quant", - "gif 0.11.4", - "jpeg-decoder 0.1.22", - "num-iter", - "num-rational 0.3.2", + "gif", + "jpeg-decoder", "num-traits", - "png 0.16.8", - "scoped_threadpool", - "tiff 0.6.1", + "png", + "tiff", ] [[package]] @@ -513,15 +475,15 @@ dependencies = [ "byteorder", "color_quant", "exr", - "gif 0.13.1", + "gif", "image-webp", "num-traits", - "png 0.17.13", + "png", "qoi", "ravif", "rayon", "rgb", - "tiff 0.9.1", + "tiff", "zune-core", "zune-jpeg", ] @@ -538,17 +500,18 @@ dependencies = [ [[package]] name = "imageproc" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7923654f3ce7cb6849d5dc9e544aaeab49c508a90b56c721b046e7234c74ab53" +checksum = "b6aee993351d466301a29655d628bfc6f5a35a0d062b6160ca0808f425805fd7" dependencies = [ + "approx", "conv", - "image 0.23.14", - "itertools 0.9.0", - "num 0.3.1", + "image 0.24.9", + "itertools 0.10.5", + "nalgebra 0.30.1", + "num", "rand 0.7.3", "rand_distr 0.2.2", - "rulinalg", "rusttype", ] @@ -564,8 +527,8 @@ dependencies = [ "getrandom 0.2.14", "image 0.25.1", "itertools 0.12.1", - "nalgebra", - "num 0.4.1", + "nalgebra 0.32.5", + "num", "rand 0.8.5", "rand_distr 0.4.3", "rayon", @@ -606,6 +569,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -614,16 +586,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", -] - -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", + "syn 2.0.117", ] [[package]] @@ -644,12 +607,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - [[package]] name = "jobserver" version = "0.1.28" @@ -659,12 +616,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" - [[package]] name = "jpeg-decoder" version = "0.3.1" @@ -673,10 +624,11 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "797146bb2677299a1eb6b7b50a890f4c361b29ef967addf5b2fa45dae1bb6d7d" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -749,15 +701,6 @@ dependencies = [ "imgref", ] -[[package]] -name = "matrixmultiply" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcad67dcec2d58ff56f6292582377e6921afdf3bfbd533e26fb8900ae575e002" -dependencies = [ - "rawpointer 0.1.0", -] - [[package]] name = "matrixmultiply" version = "0.3.8" @@ -765,7 +708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" dependencies = [ "autocfg", - "rawpointer 0.2.1", + "rawpointer", ] [[package]] @@ -799,25 +742,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.7.2" @@ -828,6 +752,21 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "nalgebra" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb2d0de08694bed883320212c18ee3008576bfe8c306f4c3c4a58b4876998be" +dependencies = [ + "approx", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba 0.7.3", + "typenum", +] + [[package]] name = "nalgebra" version = "0.32.5" @@ -835,11 +774,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef" dependencies = [ "approx", - "matrixmultiply 0.3.8", - "num-complex 0.4.5", - "num-rational 0.4.1", + "matrixmultiply", + "num-complex", + "num-rational", "num-traits", - "simba", + "simba 0.8.1", "typenum", ] @@ -878,53 +817,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" -[[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 0.3.3", - "num-complex 0.3.1", - "num-integer", - "num-iter", - "num-rational 0.3.2", - "num-traits", -] - [[package]] name = "num" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ - "num-bigint 0.4.4", - "num-complex 0.4.5", + "num-bigint", + "num-complex", "num-integer", "num-iter", - "num-rational 0.4.1", - "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-rational", "num-traits", ] @@ -939,15 +842,6 @@ dependencies = [ "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-complex" version = "0.4.5" @@ -957,6 +851,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-derive" version = "0.3.3" @@ -976,7 +876,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.117", ] [[package]] @@ -999,18 +899,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg", - "num-bigint 0.3.3", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.1" @@ -1018,7 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", ] @@ -1129,7 +1017,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.117", ] [[package]] @@ -1143,13 +1031,15 @@ dependencies = [ [[package]] name = "photon-rs" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548735d70c7d5278fd486e94beb00cef2ecb678b8c471dbf2f3493d331412e37" +checksum = "06e9b6d764d6656aba14f5ae43fbf48ce98ff1b1a6beb4d2e801eb0729f88773" dependencies = [ "base64", - "image 0.23.14", - "imageproc 0.22.0", + "console_error_panic_hook", + "image 0.24.9", + "imageproc 0.23.0", + "instant", "js-sys", "node-sys", "palette", @@ -1169,18 +1059,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "png" -version = "0.16.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" -dependencies = [ - "bitflags", - "crc32fast", - "deflate", - "miniz_oxide 0.3.7", -] - [[package]] name = "png" version = "0.17.13" @@ -1191,26 +1069,26 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.2", + "miniz_oxide", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1231,7 +1109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.117", ] [[package]] @@ -1376,7 +1254,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rust_hawktracer", - "rustc_version 0.4.0", + "rustc_version", "simd_helpers", "system-deps", "thiserror", @@ -1434,12 +1312,6 @@ dependencies = [ "rgb", ] -[[package]] -name = "rawpointer" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" - [[package]] name = "rawpointer" version = "0.2.1" @@ -1475,16 +1347,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "rulinalg" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ada202c9685e1d72a7420c578e92b358dbf807d3dfabb676a3dab9cc3bb12f" -dependencies = [ - "matrixmultiply 0.1.15", - "num 0.1.42", -] - [[package]] name = "rust_hawktracer" version = "0.7.0" @@ -1507,22 +1369,13 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb626abdbed5e93f031baae60d72032f56bc964e11ac2ff65f2ba3ed98d6d3e1" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.22", + "semver", ] [[package]] @@ -1536,10 +1389,10 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.17" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "safe_arch" @@ -1550,27 +1403,12 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "scoped_threadpool" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.22" @@ -1581,40 +1419,33 @@ dependencies = [ ] [[package]] -name = "semver-parser" -version = "0.7.0" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] [[package]] -name = "serde" -version = "1.0.197" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", -] - -[[package]] -name = "serde_json" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" -dependencies = [ - "itoa", - "ryu", - "serde", + "syn 2.0.117", ] [[package]] @@ -1627,20 +1458,18 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.6.1" +name = "simba" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176" dependencies = [ - "sha1_smol", + "approx", + "num-complex", + "num-traits", + "paste", + "wide", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "simba" version = "0.8.1" @@ -1648,7 +1477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" dependencies = [ "approx", - "num-complex 0.4.5", + "num-complex", "num-traits", "paste", "wide", @@ -1706,64 +1535,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "syn" version = "1.0.109" @@ -1777,9 +1548,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1822,18 +1593,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", -] - -[[package]] -name = "tiff" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" -dependencies = [ - "jpeg-decoder 0.1.22", - "miniz_oxide 0.4.4", - "weezl", + "syn 2.0.117", ] [[package]] @@ -1843,47 +1603,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" dependencies = [ "flate2", - "jpeg-decoder 0.3.1", + "jpeg-decoder", "weezl", ] [[package]] name = "time" -version = "0.2.27" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi", + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", ] [[package]] -name = "time-macros" -version = "0.1.1" +name = "time-core" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.109", -] +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "tinyvec" @@ -2010,12 +1751,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -2030,34 +1765,22 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "7dc0882f7b5bb01ae8c5215a1230832694481c1a4be062fd410e12ea3da5b631" dependencies = [ "cfg-if 1.0.0", + "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "75973d3066e01d035dbedaad2864c398df42f8dd7b1ea057c35b8407c015b537" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2065,28 +1788,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "91af5e4be765819e0bcfee7322c14374dc821e35e72fa663a830bbc7dc199eac" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 1.0.109", - "wasm-bindgen-backend", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "c9bf0406a78f02f336bf1e451799cca198e8acde4ffa278f0fb20487b150a633" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "749466a37ee189057f54748b200186b59a03417a117267baf3fd89cecc9fb837" dependencies = [ "js-sys", "wasm-bindgen", @@ -2108,28 +1834,6 @@ dependencies = [ "safe_arch", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "winnow" version = "0.6.5" diff --git a/image-processor/Cargo.toml b/image-processor/Cargo.toml index c51ec0c..cc91eea 100644 --- a/image-processor/Cargo.toml +++ b/image-processor/Cargo.toml @@ -11,11 +11,11 @@ image = "0.25" imageproc = "0.24" hex = "0.4" anyhow = "1.0" -photon-rs = { version = "0.3.2", default-features = false } +photon-rs = { version = "0.3.2" } console_error_panic_hook = { version = "0.1.7", optional = true } -wasm-bindgen = "0.2.78" +wasm-bindgen = "0.2.100" include_dir = "0.7.3" -web-sys = "0.3.55" +web-sys = "0.3.77" [lib] crate-type = ["cdylib", "rlib"] diff --git a/image-processor/output.jpg b/image-processor/output.jpg deleted file mode 100644 index 3b96db6..0000000 Binary files a/image-processor/output.jpg and /dev/null differ diff --git a/image-processor/src/lib.rs b/image-processor/src/lib.rs index 6a12b7f..8b1b41d 100644 --- a/image-processor/src/lib.rs +++ b/image-processor/src/lib.rs @@ -1,11 +1,9 @@ use image::{GenericImage, GenericImageView, Pixel, Rgba, RgbaImage}; use photon_rs::PhotonImage; -use std::collections::LinkedList; use image::imageops::FilterType; mod samples; -use samples::log; use wasm_bindgen::prelude::*; static BLACK: Rgba = Rgba([0, 0, 0, 0]); @@ -39,7 +37,6 @@ fn apply_samples_to_image(src: &mut RgbaImage) -> RgbaImage { let mut out = RgbaImage::new(src.width(), src.height()); unsafe { for y in 0..src.height() { - log(&format!("{}", y)); for x in 0..src.width() { if out.unsafe_get_pixel(x, y) == BLACK { let pixel = src.unsafe_get_pixel(x, y); @@ -68,45 +65,34 @@ fn fill( unsafe { let height = sample.height(); let width = sample.width(); - let mut points = LinkedList::new(); + let mut points: Vec = Vec::new(); if is_same(src.unsafe_get_pixel(px, py), color) { - points.push_back(Coord(px, py)); + points.push(Coord(px, py)); } - while !points.is_empty() { - if let Some(coord) = points.pop_back() { - let orig_pixel = src.unsafe_get_pixel(coord.0, coord.1); - let x = coord.0; - let y = coord.1; - if src.unsafe_get_pixel(x, y) != BLACK { - if is_same(orig_pixel, color) { - let mut xx = x; - let mut yy = y; - while xx >= width { - xx -= width; - } - while yy >= height { - yy -= height; - } - dest.unsafe_put_pixel(x, y, sample.unsafe_get_pixel(xx, yy)); - src.unsafe_put_pixel(x, y, BLACK); - if x > 1 { - points.push_front(Coord(x - 1, y)); - } - if y > 1 { - points.push_front(Coord(x, y - 1)); - } - if x < src.width() - 1 { - points.push_front(Coord(x + 1, y)); - } - if y < src.height() - 1 { - points.push_front(Coord(x, y + 1)); - } + while let Some(coord) = points.pop() { + let orig_pixel = src.unsafe_get_pixel(coord.0, coord.1); + let x = coord.0; + let y = coord.1; + if src.unsafe_get_pixel(x, y) != BLACK { + if is_same(orig_pixel, color) { + let xx = x % width; + let yy = y % height; + dest.unsafe_put_pixel(x, y, sample.unsafe_get_pixel(xx, yy)); + src.unsafe_put_pixel(x, y, BLACK); + if x > 1 { + points.push(Coord(x - 1, y)); + } + if y > 1 { + points.push(Coord(x, y - 1)); + } + if x < src.width() - 1 { + points.push(Coord(x + 1, y)); + } + if y < src.height() - 1 { + points.push(Coord(x, y + 1)); } } - } else { - println!("break"); - break; } } } diff --git a/image-processor/src/samples.rs b/image-processor/src/samples.rs index 56fb1b0..842d7f2 100644 --- a/image-processor/src/samples.rs +++ b/image-processor/src/samples.rs @@ -5,6 +5,7 @@ use wasm_bindgen::prelude::*; use include_dir::{include_dir, Dir, DirEntry}; static mut SAMPLES: OnceLock> = OnceLock::new(); +static LUT: OnceLock> = OnceLock::new(); static SAMPLES_DIR: Dir = include_dir!("src/samples"); pub fn read_jpeg_bytes() { @@ -14,31 +15,50 @@ pub fn read_jpeg_bytes() { read_color_samples().unwrap() }); } + let samples = unsafe { SAMPLES.get().unwrap() }; + LUT.get_or_init(|| { + log("building color LUT"); + init_lut(samples) + }); } -pub fn get_closest_color<'a>(r: u8, g: u8, b: u8) -> &'static ColorSample { - unsafe { - let color_samples = SAMPLES.get_mut().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, r, g, b); - if diff < min_diff { - closest = Some(sample); - min_diff = diff; +fn init_lut(samples: &[ColorSample]) -> Vec { + let mut lut = vec![0usize; 32 * 32 * 32]; + for ri in 0u8..32 { + for gi in 0u8..32 { + for bi in 0u8..32 { + let r = (ri << 3) | 4; + let g = (gi << 3) | 4; + let b = (bi << 3) | 4; + let mut best_idx = 0; + let mut best_dist = f32::MAX; + for (i, s) in samples.iter().enumerate() { + let d = get_distance(s.r, s.g, s.b, r, g, b); + if d < best_dist { + best_dist = d; + best_idx = i; + } + } + lut[(ri as usize * 32 + gi as usize) * 32 + bi as usize] = best_idx; } } + } + lut +} - let closest = closest.unwrap(); - if closest.image.is_none() { - let sample_image = - load_from_memory_with_format(closest.raw_bytes, image::ImageFormat::Jpeg) - .unwrap() - .to_rgba8(); - closest.image = Some(sample_image); +pub fn get_closest_color(r: u8, g: u8, b: u8) -> &'static ColorSample { + unsafe { + let lut = LUT.get().unwrap(); + let idx = lut[((r >> 3) as usize * 32 + (g >> 3) as usize) * 32 + (b >> 3) as usize]; + let samples = SAMPLES.get_mut().unwrap(); + let sample = &mut samples[idx]; + if sample.image.is_none() { + let img = load_from_memory_with_format(sample.raw_bytes, image::ImageFormat::Jpeg) + .unwrap() + .to_rgba8(); + sample.image = Some(img); } - closest + &*sample } } diff --git a/index.html b/index.html index d1ba718..77d6b10 100644 --- a/index.html +++ b/index.html @@ -36,10 +36,6 @@ -

(Painting can take long, be patient

-

all image processing is done in your browser).

-
And ignore all the warnings! It will be all right.
-