Implement barcode scanning

This commit is contained in:
Knyffen 2024-08-19 18:11:59 +02:00
parent b92483998b
commit 9cb3463826
11 changed files with 792 additions and 15 deletions

454
Cargo.lock generated
View File

@ -2,6 +2,22 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ab_glyph"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
]
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.22.0" version = "0.22.0"
@ -82,6 +98,15 @@ version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
version = "1.3.2" version = "1.3.2"
@ -260,12 +285,33 @@ dependencies = [
"syn 2.0.74", "syn 2.0.74",
] ]
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]] [[package]]
name = "bit_field" name = "bit_field"
version = "0.10.2" version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bit_reverse"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99528ca30abb9495c7e106bf7c3177b257c62040fc0f2909fe470b0f43097296"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -407,7 +453,12 @@ name = "calories_browser"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"console_error_panic_hook", "console_error_panic_hook",
"image 0.25.2",
"js-sys",
"rxing",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
] ]
[[package]] [[package]]
@ -483,6 +534,28 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "chrono-tz"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
dependencies = [
"chrono",
"chrono-tz-build",
"phf",
]
[[package]]
name = "chrono-tz-build"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
dependencies = [
"parse-zoneinfo",
"phf",
"phf_codegen",
]
[[package]] [[package]]
name = "clang-sys" name = "clang-sys"
version = "1.8.1" version = "1.8.1"
@ -503,6 +576,15 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "codepage-437"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e40c1169585d8d08e5675a39f2fc056cd19a258fc4cba5e3bbf4a9c1026de535"
dependencies = [
"csv",
]
[[package]] [[package]]
name = "color_quant" name = "color_quant"
version = "1.1.0" version = "1.1.0"
@ -671,6 +753,27 @@ dependencies = [
"quote", "quote",
] ]
[[package]]
name = "csv"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.10" version = "0.20.10"
@ -784,6 +887,70 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "encoding"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
dependencies = [
"encoding-index-japanese",
"encoding-index-korean",
"encoding-index-simpchinese",
"encoding-index-singlebyte",
"encoding-index-tradchinese",
]
[[package]]
name = "encoding-index-japanese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-korean"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-simpchinese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-singlebyte"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-tradchinese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding_index_tests"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -816,6 +983,17 @@ dependencies = [
"zune-inflate", "zune-inflate",
] ]
[[package]]
name = "fancy-regex"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
dependencies = [
"bit-set",
"regex-automata",
"regex-syntax",
]
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.1.0" version = "2.1.0"
@ -1064,8 +1242,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys",
"libc", "libc",
"wasi", "wasi",
"wasm-bindgen",
] ]
[[package]] [[package]]
@ -1319,6 +1499,24 @@ dependencies = [
"quick-error", "quick-error",
] ]
[[package]]
name = "imageproc"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2393fb7808960751a52e8a154f67e7dd3f8a2ef9bd80d1553078a7b4e8ed3f0d"
dependencies = [
"ab_glyph",
"approx",
"getrandom",
"image 0.25.2",
"itertools",
"nalgebra",
"num",
"rand",
"rand_distr",
"rayon",
]
[[package]] [[package]]
name = "imgref" name = "imgref"
version = "1.10.1" version = "1.10.1"
@ -1512,6 +1710,16 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "matrixmultiply"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
dependencies = [
"autocfg",
"rawpointer",
]
[[package]] [[package]]
name = "maybe-rayon" name = "maybe-rayon"
version = "0.1.1" version = "0.1.1"
@ -1571,6 +1779,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "multimap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "mysql" name = "mysql"
version = "25.0.1" version = "25.0.1"
@ -1653,6 +1870,21 @@ dependencies = [
"zstd", "zstd",
] ]
[[package]]
name = "nalgebra"
version = "0.32.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4"
dependencies = [
"approx",
"matrixmultiply",
"num-complex",
"num-rational",
"num-traits",
"simba",
"typenum",
]
[[package]] [[package]]
name = "named_pipe" name = "named_pipe"
version = "0.4.1" version = "0.4.1"
@ -1701,6 +1933,20 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
[[package]]
name = "num"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.6" version = "0.4.6"
@ -1711,6 +1957,15 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.1.0" version = "0.1.0"
@ -1737,6 +1992,17 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-iter"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.4.2" version = "0.4.2"
@ -1755,6 +2021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"libm",
] ]
[[package]] [[package]]
@ -1816,6 +2083,24 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "owned_ttf_parser"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90"
dependencies = [
"ttf-parser 0.24.1",
]
[[package]]
name = "parse-zoneinfo"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.15" version = "1.0.15"
@ -1857,6 +2142,44 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.5" version = "1.1.5"
@ -1910,7 +2233,7 @@ dependencies = [
"plotters-backend", "plotters-backend",
"plotters-bitmap", "plotters-bitmap",
"plotters-svg", "plotters-svg",
"ttf-parser", "ttf-parser 0.20.0",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
] ]
@ -2122,6 +2445,16 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "rand_distr"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
dependencies = [
"num-traits",
"rand",
]
[[package]] [[package]]
name = "rav1e" name = "rav1e"
version = "0.7.1" version = "0.7.1"
@ -2171,6 +2504,12 @@ dependencies = [
"rgb", "rgb",
] ]
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.10.0" version = "1.10.0"
@ -2334,12 +2673,56 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "rxing"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "786ea2f74b327842bab8c9e611fa3e40f1549d7931fb6e63d1fc2f84e06c2323"
dependencies = [
"bit_reverse",
"chrono",
"chrono-tz",
"codepage-437",
"encoding",
"fancy-regex",
"image 0.25.2",
"imageproc",
"multimap",
"num",
"once_cell",
"regex",
"rxing-one-d-proc-derive",
"thiserror",
"unicode-segmentation",
"uriparse",
"urlencoding",
]
[[package]]
name = "rxing-one-d-proc-derive"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59c92a4da773eed06d54210368684b4325bc70a0f8b0cc4d50a106bf71b954f2"
dependencies = [
"quote",
"syn 2.0.74",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.18" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "safe_arch"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a"
dependencies = [
"bytemuck",
]
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@ -2496,6 +2879,19 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simba"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae"
dependencies = [
"approx",
"num-complex",
"num-traits",
"paste",
"wide",
]
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.7" version = "0.3.7"
@ -2517,6 +2913,12 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.13.2" version = "1.13.2"
@ -2917,6 +3319,12 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
[[package]]
name = "ttf-parser"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a"
[[package]] [[package]]
name = "twox-hash" name = "twox-hash"
version = "1.6.3" version = "1.6.3"
@ -2964,6 +3372,22 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "uriparse"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff"
dependencies = [
"fnv",
"lazy_static",
]
[[package]] [[package]]
name = "url" name = "url"
version = "2.5.2" version = "2.5.2"
@ -2975,6 +3399,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.10.0" version = "1.10.0"
@ -3052,6 +3482,18 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.93" version = "0.2.93"
@ -3097,6 +3539,16 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
[[package]]
name = "wide"
version = "0.7.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690"
dependencies = [
"bytemuck",
"safe_arch",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@ -18,6 +18,12 @@ wasm-bindgen = "0.2.84"
# code size when deploying. # code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true } console_error_panic_hook = { version = "0.1.7", optional = true }
rxing = "0.6.1"
image = "0.25.2"
web-sys = { version = "0.3.70", features = ["Navigator", "MediaDevices", "Document", "HtmlCanvasElement", "CanvasRenderingContext2d", "VideoFrame", "HtmlVideoElement", "ImageData", "Window", "HtmlInputElement", "HtmlButtonElement", "MediaStreamConstraints", "MediaStream", "HtmlMediaElement", "console", "EventTarget"] }
wasm-bindgen-futures = "0.4.43"
js-sys = "0.3.70"
[profile.release] [profile.release]
# Tell `rustc` to optimize for small code size. # Tell `rustc` to optimize for small code size.
opt-level = "s" opt-level = "s"

2
browser/config.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["--cfg=web_sys_unstable_apis"]

View File

@ -1,16 +1,162 @@
mod utils; mod utils;
use image::{DynamicImage, RgbaImage};
use std::collections::HashMap;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use web_sys::*;
const CANVAS_WIDTH: u32 = 1920;
const CANVAS_HEIGHT: u32 = 1080;
const VIDEO_ID: &str = "video";
const CANVAS_ID: &str = "canvas";
const BARCODE_ID: &str = "barcode";
const SCAN_BUTTON_ID: &str = "scan_barcode_button";
// Import the `window.alert` function from the Web.
#[wasm_bindgen] #[wasm_bindgen]
extern "C" { extern "C" {
fn alert(s: &str); fn alert(s: &str);
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
#[wasm_bindgen(js_namespace = console)]
fn error(s: &str);
} }
// Export a `greet` function from Rust to JavaScript, that alerts a
// hello message.
#[wasm_bindgen] #[wasm_bindgen]
pub fn greet(name: &str) { pub fn init_camera_feed() -> Result<(), String> {
alert(&format!("Hello, {}!", name)); utils::set_panic_hook();
let window = window().unwrap();
let document = window.document().unwrap();
let video: HtmlVideoElement = document
.get_element_by_id(VIDEO_ID)
.unwrap()
.dyn_into()
.unwrap();
let video2 = video.clone();
let video3 = video.clone();
let canvas: HtmlCanvasElement = document
.get_element_by_id(CANVAS_ID)
.unwrap()
.dyn_into()
.unwrap();
let button: HtmlButtonElement = document
.get_element_by_id(SCAN_BUTTON_ID)
.unwrap()
.dyn_into()
.unwrap();
let navigator = window.navigator();
let media_devices = navigator.media_devices().unwrap();
let media_stream_constraints = MediaStreamConstraints::new();
media_stream_constraints.set_video(&JsValue::from_bool(true));
media_stream_constraints.set_audio(&JsValue::from_bool(false));
let user_media = media_devices
.get_user_media_with_constraints(&media_stream_constraints)
.unwrap();
let succ: Closure<dyn FnMut(JsValue)> = Closure::new(move |stream: JsValue| {
video.set_src_object(Some(&MediaStream::unchecked_from_js(stream)));
let _ = video.play();
});
let fail: Closure<dyn FnMut(JsValue)> = Closure::new(|err| {
error(format!("An error occured: {:?}", err).as_str());
});
let _ = user_media.then(&succ).catch(&fail);
succ.forget(); // Memory leak
fail.forget(); // Memory leak
let set_width_and_height: Closure<dyn FnMut()> = Closure::new(move || {
let width: u32 = 640;
let height: u32 =
((width as f32 / video3.video_width() as f32) * video3.video_height() as f32) as u32;
video3.set_width(width);
video3.set_height(height);
canvas.set_width(CANVAS_WIDTH);
canvas.set_height(CANVAS_HEIGHT);
});
let _ = video2
.add_event_listener_with_callback("canplay", set_width_and_height.as_ref().unchecked_ref());
set_width_and_height.forget(); // Memory leak
//
let scan_barcode_wrapper: Closure<dyn FnMut()> = Closure::new(move || {
match scan_barcode() {
Ok(()) => {}
Err(e) => error(e.as_str()),
};
});
let _ = button
.add_event_listener_with_callback("click", scan_barcode_wrapper.as_ref().unchecked_ref());
scan_barcode_wrapper.forget(); // Memory leak
Ok(())
}
fn convert_rgba_to_luma(data: &[u8]) -> Vec<u8> {
let rgba = RgbaImage::from_raw((data.len() / 4) as u32, 1, data.to_vec());
let luma = DynamicImage::ImageRgba8(rgba.unwrap()).into_luma8();
luma.to_vec()
}
fn decode_barcode(data: Vec<u8>, width: u32, height: u32) -> Result<String, rxing::Exceptions> {
let mut hints: rxing::DecodingHintDictionary = HashMap::new();
hints.insert(
rxing::DecodeHintType::TRY_HARDER,
rxing::DecodeHintValue::TryHarder(true),
);
let result =
match rxing::helpers::detect_in_luma_with_hints(data, width, height, None, &mut hints) {
Ok(r) => r,
Err(e) => return Err(e),
};
Ok(result.getText().to_string())
}
fn scan_barcode() -> Result<(), String> {
let window = window().unwrap();
let document = window.document().unwrap();
let video: HtmlVideoElement = document
.get_element_by_id(VIDEO_ID)
.unwrap()
.dyn_into()
.unwrap();
let canvas: HtmlCanvasElement = document
.get_element_by_id(CANVAS_ID)
.unwrap()
.dyn_into()
.unwrap();
let barcode: HtmlInputElement = document
.get_element_by_id(BARCODE_ID)
.unwrap()
.dyn_into()
.unwrap();
let context: CanvasRenderingContext2d = match canvas.get_context("2d").unwrap() {
Some(c) => c.dyn_into().unwrap(),
None => return Err("Could not get canvas context".to_string()),
};
for _ in 0..100 {
let _ = context.draw_image_with_html_video_element(&video, 0., 0.);
let rgba = context
.get_image_data(0., 0., CANVAS_WIDTH.into(), CANVAS_HEIGHT.into())
.unwrap()
.data();
let luma = convert_rgba_to_luma(&rgba);
let code: String = match decode_barcode(luma, CANVAS_WIDTH, CANVAS_HEIGHT) {
Ok(c) => c,
Err(rxing::Exceptions::NotFoundException(_)) => {
log(".");
continue;
}
Err(e) => return Err(format!("{:?}", e)),
};
barcode.set_value(&code);
break;
}
Ok(())
} }

View File

@ -1,3 +1,4 @@
#[allow(dead_code)]
pub fn set_panic_hook() { pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the // When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then // `set_panic_hook` function at least once during initialization, and then

82
javascript/camera.js Normal file
View File

@ -0,0 +1,82 @@
import init, { init_camera_feed } from '/pkg/calories_browser.js';
await init();
init_camera_feed();
// (() => {
// // The width and height of the captured photo. We will set the
// // width to the value defined here, but the height will be
// // calculated based on the aspect ratio of the input stream.
// const width = 1080; // We will scale the photo width to this
// let height = 0; // This will be computed based on the input stream
// // |streaming| indicates whether or not we're currently streaming
// // video from the camera. Obviously, we start at false.
// let streaming = false;
// // The various HTML elements we need to configure or control. These
// // will be set by the startup() function.
// let video = null;
// let canvas = null;
// let startbutton = null;
// async function startup() {
// await init();
// video = document.getElementById("video");
// canvas = document.getElementById("canvas");
// startbutton = document.getElementById("startbutton");
// navigator.mediaDevices
// .getUserMedia({ video: true, audio: false })
// .then((stream) => {
// video.srcObject = stream;
// video.play();
// })
// .catch((err) => {
// console.error(`An error occurred: ${err}`);
// });
// video.addEventListener(
// "canplay",
// (ev) => {
// if (!streaming) {
// height = video.videoHeight / (video.videoWidth / width);
// // Firefox currently has a bug where the height can't be read from
// // the video, so we will make assumptions if this happens.
// if (isNaN(height)) {
// height = width / (4 / 3);
// }
// video.setAttribute("width", width);
// video.setAttribute("height", height);
// canvas.setAttribute("width", width);
// canvas.setAttribute("height", height);
// streaming = true;
// }
// },
// false,
// );
// startbutton.addEventListener(
// "click",
// (ev) => {
// takepicture();
// ev.preventDefault();
// },
// false,
// );
// }
// function takepicture() {
// fill_barcode();
// }
// // Set up our event listener to run the startup process
// // once loading is complete.
// // window.addEventListener("load", startup, false);
// })();

2
server/config.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["--cfg=web_sys_unstable_apis"]

View File

@ -58,6 +58,7 @@ async fn main() {
.route("/calorie_intake.svg", get(svg_calorie_intake)) .route("/calorie_intake.svg", get(svg_calorie_intake))
.route("/calorie_intake", get(calorie_intake)) .route("/calorie_intake", get(calorie_intake))
.route("/wasm_test", get(wasm_test)) .route("/wasm_test", get(wasm_test))
.route("/camera_test", get(camera_test))
.nest_service("/pkg", get_service(ServeDir::new("../browser/pkg"))) .nest_service("/pkg", get_service(ServeDir::new("../browser/pkg")))
.with_state(shared_state) .with_state(shared_state)
.fallback(not_found); .fallback(not_found);
@ -130,15 +131,74 @@ async fn calorie_intake(State(_state): State<Arc<AppState>>) -> Html<String> {
Html("<body><img src=/calorie_intake.svg></img></body>".to_string()) Html("<body><img src=/calorie_intake.svg></img></body>".to_string())
} }
async fn wasm_test(State(_state): State<Arc<AppState>>) -> Html<String> { fn construct_js(path: &str) -> Result<String, my_structs::MyError> {
let javascript = std::fs::read_to_string(format!("../javascript/{}", path))?;
let module = format!(
"
<script type=\"module\">
{}
</script>
",
javascript
);
Ok(module)
}
fn construct_tmpl(path: &str) -> Result<String, my_structs::MyError> {
Ok(std::fs::read_to_string(format!("../templates/{}", path))?)
}
fn construct_html(
js_paths: Vec<&str>,
tmpl_paths: Vec<&str>,
) -> Result<String, my_structs::MyError> {
let js_modules: Vec<String> = js_paths
.into_iter()
.map(construct_js)
.collect::<Result<Vec<String>, my_structs::MyError>>()?;
let tmpl_snippets: Vec<String> = tmpl_paths
.into_iter()
.map(construct_tmpl)
.collect::<Result<Vec<String>, my_structs::MyError>>()?;
let html = format!(
"
<!DOCTYPE html>
<html lang=\"en\">
<head>
{}
</head>
<body>
{}
</body>
",
js_modules.join(""),
tmpl_snippets.join("")
);
Ok(html)
}
fn get_template(path: &str) -> Result<String, my_structs::MyError> {
Ok(std::fs::read_to_string(format!("../templates/{}", path))?)
}
async fn wasm_test(
State(_state): State<Arc<AppState>>,
) -> Result<Html<String>, my_structs::MyError> {
println!("Serving: wasm_test"); println!("Serving: wasm_test");
Html( let content = get_template("view_calories.html")?;
"<head><script type='module'>
import init, { greet } from '/pkg/calories_browser.js'; Ok(Html(content))
await init(); }
greet('You!');
</script></head><body>wasm_test</body>" async fn camera_test(
.to_string(), State(_state): State<Arc<AppState>>,
) ) -> Result<Html<String>, my_structs::MyError> {
println!("Serving: camera_test");
let html = construct_html(vec!["camera.js"], vec!["camera_test.html"])?;
Ok(Html(html))
} }

View File

@ -5,6 +5,7 @@ use axum::{
pub enum MyError { pub enum MyError {
MySQLError(mysql::Error), MySQLError(mysql::Error),
IOError(std::io::Error),
} }
impl IntoResponse for MyError { impl IntoResponse for MyError {
@ -12,6 +13,7 @@ impl IntoResponse for MyError {
let (status, message) = match self { let (status, message) = match self {
// # TODO: Don't expose error messages once this goes into production // # TODO: Don't expose error messages once this goes into production
MyError::MySQLError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()), MyError::MySQLError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
MyError::IOError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
}; };
(status, message).into_response() (status, message).into_response()
@ -23,3 +25,9 @@ impl From<mysql::Error> for MyError {
Self::MySQLError(error) Self::MySQLError(error)
} }
} }
impl From<std::io::Error> for MyError {
fn from(error: std::io::Error) -> Self {
Self::IOError(error)
}
}

View File

@ -0,0 +1,8 @@
<div>
<video id="video">Camera not available.</video>
<canvas id="canvas" hidden> </canvas>
</div>
<div>
<button id="scan_barcode_button">Scan barcode</button>
<input id="barcode"/>
</div>

View File

@ -0,0 +1,10 @@
<head>
<script type='module'>
import init, { greet } from '/pkg/calories_browser.js';
await init();
greet('You!');
</script>
</head>
<body>
wasm_test
</body>