diff --git a/Cargo.lock b/Cargo.lock index 7c55d6f..7ba0b3c 100644 --- a/Cargo.lock +++ b/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 = "actix-codec" @@ -222,6 +222,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -237,6 +243,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + [[package]] name = "approx" version = "0.5.1" @@ -246,6 +258,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -258,6 +293,29 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +dependencies = [ + "arrayvec", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -280,27 +338,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "bindgen" -version = "0.69.5" +name = "bit_field" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags 2.6.0", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", -] +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" @@ -314,6 +355,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "block-buffer" version = "0.10.4" @@ -344,18 +391,36 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "built" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.7.2" @@ -383,12 +448,13 @@ dependencies = [ ] [[package]] -name = "cexpr" -version = "0.6.0" +name = "cfg-expr" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ - "nom", + "smallvec", + "target-lexicon", ] [[package]] @@ -398,15 +464,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "clang-sys" -version = "1.8.1" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "console" @@ -471,6 +532,37 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -513,34 +605,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "eccodes" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7851e2dfed8264270ebee69af9ab16ffc6d0981f7829d4c8379359b97f5abeed" -dependencies = [ - "eccodes-sys", - "errno", - "fallible-iterator", - "fallible-streaming-iterator", - "libc", - "log", - "ndarray", - "num-derive", - "num-traits", - "thiserror", -] - -[[package]] -name = "eccodes-sys" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2bdc129e03da6393abb9fea441903fb6a5e88f1fd15da111c17be03017fd59" -dependencies = [ - "bindgen", - "pkg-config", -] - [[package]] name = "either" version = "1.13.0" @@ -579,16 +643,19 @@ dependencies = [ ] [[package]] -name = "fallible-iterator" -version = "0.3.0" +name = "exr" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] [[package]] name = "fastrand" @@ -705,18 +772,22 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "h2" version = "0.3.26" @@ -755,27 +826,34 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "http" version = "0.2.12" @@ -915,6 +993,45 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "image" +version = "0.25.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "impl-more" version = "0.1.6" @@ -943,6 +1060,17 @@ dependencies = [ "similar", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ipnet" version = "2.10.1" @@ -973,6 +1101,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.71" @@ -995,10 +1129,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "lazycell" -version = "1.3.0" +name = "lebe" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" @@ -1007,13 +1141,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] -name = "libloading" -version = "0.8.5" +name = "libfuzzer-sys" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" dependencies = [ - "cfg-if", - "windows-targets", + "arbitrary", + "cc", ] [[package]] @@ -1062,13 +1196,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] -name = "matrixmultiply" -version = "0.3.9" +name = "loop9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" dependencies = [ - "autocfg", - "rawpointer", + "imgref", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", ] [[package]] @@ -1130,19 +1273,10 @@ dependencies = [ ] [[package]] -name = "ndarray" -version = "0.16.1" +name = "new_debug_unreachable" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" -dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "portable-atomic", - "portable-atomic-util", - "rawpointer", -] +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nom" @@ -1155,11 +1289,28 @@ dependencies = [ ] [[package]] -name = "num-complex" +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ + "num-integer", "num-traits", ] @@ -1189,6 +1340,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1266,6 +1428,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1332,21 +1500,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "portable-atomic" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" - -[[package]] -name = "portable-atomic-util" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a7d5beecc52a491b54d6dd05c7a45ba1801666a5baad9fdbfc6fef8d2d206c" -dependencies = [ - "portable-atomic", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1363,24 +1516,48 @@ dependencies = [ ] [[package]] -name = "prettyplease" -version = "0.2.23" +name = "proc-macro2" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904afd36257cdb6ce0bee88b7981847bd7b955e5e216bb32f466b302923ad446" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ - "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", "syn", ] [[package]] -name = "proc-macro2" -version = "1.0.87" +name = "qoi" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" dependencies = [ - "unicode-ident", + "bytemuck", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.37" @@ -1421,10 +1598,74 @@ dependencies = [ ] [[package]] -name = "rawpointer" -version = "0.2.1" +name = "rav1e" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror 1.0.64", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] [[package]] name = "redox_syscall" @@ -1513,6 +1754,12 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" + [[package]] name = "ring" version = "0.17.8" @@ -1534,12 +1781,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc_version" version = "0.4.1" @@ -1683,6 +1924,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1706,6 +1956,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1727,6 +1986,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "similar" version = "2.6.0" @@ -1772,9 +2040,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.80" +version = "2.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e185e337f816bc8da115b8afcb3324006ccc82eeaddf35113888d3bd8e44ac" +checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" dependencies = [ "proc-macro2", "quote", @@ -1811,6 +2079,25 @@ dependencies = [ "libc", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tempfile" version = "3.13.0" @@ -1830,7 +2117,16 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.64", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl 2.0.9", ] [[package]] @@ -1844,6 +2140,38 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "tikv-jemalloc-sys" version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" @@ -1961,6 +2289,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.3" @@ -1975,9 +2337,21 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -1985,6 +2359,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -2037,12 +2437,35 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" @@ -2142,17 +2565,33 @@ dependencies = [ ] [[package]] -name = "which" -version = "4.4.2" +name = "weezl" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "either", - "home", - "once_cell", - "rustix", + "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 = "windows-registry" version = "0.2.0" @@ -2265,12 +2704,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f5bb5257f2407a5425c6e749bfd9692192a73e70a6060516ac04f889087d68" +dependencies = [ + "memchr", +] + +[[package]] +name = "wxbox-grib2" +version = "0.1.0" +dependencies = [ + "image", + "png", + "thiserror 2.0.9", + "tracing", +] + [[package]] name = "wxbox-pal" version = "0.1.0" dependencies = [ "ordered-float", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2279,17 +2737,18 @@ version = "0.1.0" dependencies = [ "actix-web", "approx", - "eccodes", "flate2", "insta", "mime", - "ndarray", "ordered-float", "png", "reqwest", - "thiserror", + "thiserror 1.0.64", "tikv-jemallocator", "tokio", + "tracing", + "tracing-subscriber", + "wxbox-grib2", "wxbox-pal", ] @@ -2347,3 +2806,27 @@ dependencies = [ "cc", "pkg-config", ] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index cb9a13e..61b1384 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,12 @@ [workspace] resolver = "2" -members = ["wxbox-pal","wxbox-tiler"] +members = [ "wxbox-grib2","wxbox-pal","wxbox-tiler"] [profile.release] codegen-units = 1 lto = "fat" + +[profile.dev.package.image] +opt-level = 3 +[profile.dev.package.png] +opt-level = 3 \ No newline at end of file diff --git a/data.png b/data.png new file mode 100644 index 0000000..cdd5a7e Binary files /dev/null and b/data.png differ diff --git a/wxbox-grib2/Cargo.toml b/wxbox-grib2/Cargo.toml new file mode 100644 index 0000000..440cbee --- /dev/null +++ b/wxbox-grib2/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "wxbox-grib2" +version = "0.1.0" +edition = "2021" + +[dependencies] +thiserror = "2" +tracing = "0.1" +png = "0.17" +image = "0.25" \ No newline at end of file diff --git a/wxbox-grib2/src/error.rs b/wxbox-grib2/src/error.rs new file mode 100644 index 0000000..b98d005 --- /dev/null +++ b/wxbox-grib2/src/error.rs @@ -0,0 +1,42 @@ +use std::io; +use image::ImageError; +use png::DecodingError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum GribError { + #[error("i/o error")] + IoError(#[from] io::Error), + #[error("incorrect indicator: found {0}")] + IncorrectIndicator(u32), + #[error("incorrect edition: found {0}")] + IncorrectEdition(u8), + #[error("this library only supports global grids in table 3.1")] + NonTable31, + #[error("this library does not support reading octets 15-xx in section 3")] + ListOfNumbersNotSupported, + #[error("unsupported grid definition template {0}")] + UnsupportedGrid(u16), + #[error("unsupported product definition template {0}")] + UnsupportedProductDefTmpl(u16), + #[error("unsupported data representation template {0}")] + UnsupportedDataRepresentationTemplate(u16), + #[error("unsupported bitmap")] + UnsupportedBitmap(u8), + #[error("missing data representation")] + MissingDataRepresentation, + #[error("missing identification")] + MissingIdentification, + #[error("missing grid definition")] + MissingGridDefinition, + #[error("missing product definition")] + MissingProductDefinition, + #[error("missing bitmap")] + MissingBitmap, + #[error("missing data")] + MissingData, + #[error("image error")] + PNGImageError(#[from] DecodingError), + #[error("image error")] + ImageError(#[from] ImageError) +} \ No newline at end of file diff --git a/wxbox-grib2/src/lib.rs b/wxbox-grib2/src/lib.rs new file mode 100644 index 0000000..101fd79 --- /dev/null +++ b/wxbox-grib2/src/lib.rs @@ -0,0 +1,587 @@ +pub mod error; +mod nommer; +pub mod wgs84; + +use std::fmt::{Debug, Formatter}; +use std::io::{Cursor, Read}; +use std::time::Instant; +use image::codecs::png::PngDecoder; +use image::{DynamicImage, ImageBuffer, ImageDecoder, ImageFormat, ImageReader, Luma}; +use tracing::{debug, warn}; +use crate::error::GribError; +use crate::LatLongVectorRelativity::{EasterlyAndNortherly, IncreasingXY}; +use crate::nommer::NomReader; +use crate::wgs84::LatLong; + +pub const INDICATOR: u32 = u32::from_be_bytes(*b"GRIB"); +pub const EDITION: u8 = 2; + +#[derive(Debug)] +pub struct GribMessage { + pub indicator: u32, + pub reserved: u16, + pub discipline: u8, + pub edition: u8, + pub message_length: u64, + pub identification: IdentificationSection, + pub grid_definition: GridDefinitionSection, + pub product_definition: ProductDefinitionSection, + pub data_representation: DataRepresentationSection, + pub bitmap: BitmapSection, + pub data: DataSection, +} +impl GribMessage { + pub fn new(reader: R) -> Result { + let mut nommer = NomReader::new(reader); + let indicator = nommer.read_u32()?; + + if indicator != INDICATOR { + return Err(GribError::IncorrectIndicator(indicator)); + } + + let reserved = nommer.read_u16()?; + let discipline = nommer.read_u8()?; + let edition = nommer.read_u8()?; + + if edition != EDITION { + return Err(GribError::IncorrectEdition(edition)); + } + + let message_length = nommer.read_u64()?; + + let mut identification: Option = None; + let mut grid_definition: Option = None; + let mut product_definition: Option = None; + let mut data_representation: Option = None; + let mut bitmap: Option = None; + let mut data: Option = None; + + loop { + let length = match nommer.read_u32() { + Ok(l) => l, + Err(e) => return match e.kind() { + std::io::ErrorKind::UnexpectedEof => break, + _ => return Err(e.into()) + } + }; + + if length == u32::from_be_bytes(*b"7777") { + break; + } + + let section_number = nommer.read_u8()?; + + match section_number { + 1 => { + identification = Some(IdentificationSection::parse(length, &mut nommer)?); + }, + 3 => { + grid_definition = Some(GridDefinitionSection::parse(length, &mut nommer)?); + }, + 4 => { + product_definition = Some(ProductDefinitionSection::parse(length, &mut nommer)?); + }, + 5 => { + data_representation = Some(DataRepresentationSection::parse(length, &mut nommer)?); + }, + 6 => { + bitmap = Some(BitmapSection::parse(length, &mut nommer)?); + }, + 7 => { + data = Some(DataSection::parse(length, &mut nommer)?) + }, + _ => { + let _ = nommer.read_n((length - 5) as usize); + warn!("unimplemented section # {} len {}", section_number, length) + } + } + } + + let identification = identification.ok_or(GribError::MissingIdentification)?; + let grid_definition = grid_definition.ok_or(GribError::MissingGridDefinition)?; + let product_definition = product_definition.ok_or(GribError::MissingProductDefinition)?; + let mut data_representation = data_representation.ok_or(GribError::MissingDataRepresentation)?; + let bitmap = bitmap.ok_or(GribError::MissingBitmap)?; + let data = data.ok_or(GribError::MissingData)?; + + data_representation.load_data(data.data.clone())?; + + Ok(Self { + indicator, + reserved, + discipline, + edition, + message_length, + identification, + grid_definition, + product_definition, + data_representation, + bitmap, + data + }) + } + + pub fn value_for(&self, coord: LatLong) -> Option { + match self.grid_definition.image_coordinates(coord) { + Some((i, j)) => self.data_representation.get_image_coordinate(i as u32, j as u32), + None => None + } + } +} + +#[derive(Debug)] +pub struct IdentificationSection { + pub originating_center_id: u16, + pub originating_subcenter_id: u16, + pub master_tables_version: u8, + pub local_tables_version: u8, + pub reference_time_significance: u8, + pub year: u16, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: u8, + pub production_status: u8, + pub processed_data_type: u8, + pub reserved: Vec +} +impl IdentificationSection { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + let originating_center_id = nommer.read_u16()?; + let originating_subcenter_id = nommer.read_u16()?; + let master_tables_version = nommer.read_u8()?; + let local_tables_version = nommer.read_u8()?; + let reference_time_significance = nommer.read_u8()?; + let year = nommer.read_u16()?; + let month = nommer.read_u8()?; + let day = nommer.read_u8()?; + let hour = nommer.read_u8()?; + let minute = nommer.read_u8()?; + let second = nommer.read_u8()?; + let production_status = nommer.read_u8()?; + let processed_data_type = nommer.read_u8()?; + let reserved = nommer.read_n((length - 21) as usize)?; + Ok(Self { + originating_center_id, + originating_subcenter_id, + master_tables_version, + local_tables_version, + reference_time_significance, + year, + month, + day, + hour, + minute, + second, + production_status, + processed_data_type, + reserved + }) + } +} + + +#[derive(Debug)] +pub struct GridDefinitionSection { + pub source: u8, + pub number_of_data_points: u32, + pub length_of_optional_number_list: u8, + pub interpretation_of_number_list: u8, + pub grid_definition_template_number: u16, + pub grid_definition: GridDefinition +} +impl GridDefinitionSection { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + let source = nommer.read_u8()?; + + if source != 0 { + return Err(GribError::NonTable31); + } + + let number_of_data_points = nommer.read_u32()?; + let length_of_optional_number_list = nommer.read_u8()?; + + if length_of_optional_number_list != 0 { + return Err(GribError::ListOfNumbersNotSupported); + } + + let interpretation_of_number_list = nommer.read_u8()?; + let grid_definition_template_number = nommer.read_u16()?; + + + let grid_definition = match grid_definition_template_number { + 0 => GridDefinition::LatitudeLongitude(LatLongGrid::parse(length, nommer)?), + _ => return Err(GribError::UnsupportedGrid(grid_definition_template_number)), + }; + + Ok(Self { + source, + number_of_data_points, + length_of_optional_number_list, + interpretation_of_number_list, + grid_definition_template_number, + grid_definition + }) + } + + fn image_coordinates(&self, at: LatLong) -> Option<(u64, u64)> { + self.grid_definition.image_coordinates(at) + } +} + +#[derive(Debug)] +pub struct ProductDefinitionSection { + pub number_of_coordinate_values_after_template: u16, + pub product_definition_template_number: u16, + pub product_definition: ProductDefinition, +} +impl ProductDefinitionSection { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + let number_of_coordinate_values_after_template = nommer.read_u16()?; + let product_definition_template_number = nommer.read_u16()?; + + + if number_of_coordinate_values_after_template != 0 { + return Err(GribError::ListOfNumbersNotSupported); + } + + let product_definition = match product_definition_template_number { + 0 => ProductDefinition::HorizontalLayerAtPointInTime(HorizontalLayerInstantaneousProductDef::parse(length, nommer)?), + _ => return Err(GribError::UnsupportedProductDefTmpl(product_definition_template_number)) + }; + + Ok(Self { + number_of_coordinate_values_after_template, + product_definition_template_number, + product_definition + }) + } +} + +#[derive(Debug)] +pub struct DataRepresentationSection { + pub number_of_data_points: u32, + pub data_representation_template_number: u16, + pub data_representation_template: DataRepresentationTemplate +} +impl DataRepresentationSection { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + let number_of_data_points = nommer.read_u32()?; + let data_representation_template_number = nommer.read_u16()?; + + let data_representation_template = match data_representation_template_number { + 41 => DataRepresentationTemplate::GridpointPNG(GridpointPNGDataRepresentation::parse(length, nommer)?), + _ => return Err(GribError::UnsupportedDataRepresentationTemplate(data_representation_template_number)) + }; + + Ok(Self { + number_of_data_points, + data_representation_template_number, + data_representation_template + }) + } + + fn load_data(&mut self, data: Vec) -> Result<(), GribError> { + self.data_representation_template.load_data(data) + } + fn get_image_coordinate(&self, x: u32, y: u32) -> Option { + self.data_representation_template.get_image_coordinate(x, y) + } +} + +#[derive(Debug)] +pub enum DataRepresentationTemplate { + GridpointPNG(GridpointPNGDataRepresentation) +} +impl DataRepresentationTemplate { + fn load_data(&mut self, data: Vec) -> Result<(), GribError> { + match self { + Self::GridpointPNG(png) => png.load_data(data) + } + } + fn get_image_coordinate(&self, x: u32, y: u32) -> Option { + match self { + Self::GridpointPNG(png) => png.get_image_coordinate(x, y) + } + } +} + +#[derive(Debug)] +pub struct GridpointPNGDataRepresentation { + pub reference_value: f32, + pub binary_scale_factor: u16, + pub decimal_scale_factor: u16, + pub depth: u8, + pub type_of_values: u8, + + pub image: Option, Vec>> +} +impl GridpointPNGDataRepresentation { + fn parse(_length: u32, nommer: &mut NomReader) -> Result { + let reference_value = nommer.read_f32()?; + let binary_scale_factor = nommer.read_u16()?; + let decimal_scale_factor = nommer.read_u16()?; + let depth = nommer.read_u8()?; + let type_of_values = nommer.read_u8()?; + Ok(Self { + reference_value, + binary_scale_factor, + decimal_scale_factor, + depth, + type_of_values, + image: None + }) + } + fn load_data(&mut self, data: Vec) -> Result<(), GribError> { + let mut image_reader = ImageReader::new(Cursor::new(data)); + image_reader.set_format(ImageFormat::Png); + + let image = image_reader.decode()?; + + self.image = Some(image.to_luma16()); + + Ok(()) + } + + fn get_image_coordinate(&self, x: u32, y: u32) -> Option { + match &self.image { + Some(i) => { + if x >= i.width() || y >= i.height() { + None + } else { + let datapoint = i.get_pixel(x, y).0[0] as f32; + let diff = datapoint * 2.0_f32.powi(self.binary_scale_factor as i32); + let dig_factor = 10_f32.powi(-(self.decimal_scale_factor as i32)); + let value = (self.reference_value + diff) * dig_factor; + Some(value) + } + }, + None => None, + } + } +} + +#[derive(Debug)] +pub struct BitmapSection { + pub indicator: u8, + pub bitmap: Vec +} +impl BitmapSection { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + let indicator = nommer.read_u8()?; + if indicator != 255 { + return Err(GribError::UnsupportedBitmap(indicator)); + } + + let bitmap = nommer.read_n((length - 6) as usize)?; + Ok(Self { + indicator, + bitmap + }) + } +} + +pub struct DataSection { + pub data: Vec +} +impl DataSection { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + let data = nommer.read_n((length - 5) as usize)?; + Ok(Self { + data + }) + } +} +impl Debug for DataSection { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "[data - {} bytes]", self.data.len()) + } +} + +#[derive(Debug)] +pub enum ProductDefinition { + HorizontalLayerAtPointInTime(HorizontalLayerInstantaneousProductDef), +} +#[derive(Debug)] +pub struct HorizontalLayerInstantaneousProductDef { + pub parameter_category: u8, + pub parameter_number: u8, + pub type_of_generating_process: u8, + pub background_generating_process_id: u8, + pub type_of_generating_process_identified: u8, + pub obs_data_cutoff_hours: u16, + pub obs_data_cutoff_minutes: u8, + pub indicator_of_unit_in_time_range: u8, + pub forecast_time: u32, + pub first_fixed_surface_type: u8, + pub scale_factor_first_fixed_surface: u8, + pub scaled_value_first_fixed_surface: u32, + pub second_fixed_surface_type: u8, + pub scale_factor_second_fixed_surface: u8, + pub scaled_value_second_fixed_surface: u32 +} +impl HorizontalLayerInstantaneousProductDef { + fn parse(_length: u32, nommer: &mut NomReader) -> Result { + let parameter_category = nommer.read_u8()?; + let parameter_number = nommer.read_u8()?; + let type_of_generating_process = nommer.read_u8()?; + let background_generating_process_id = nommer.read_u8()?; + let type_of_generating_process_identified = nommer.read_u8()?; + let obs_data_cutoff_hours = nommer.read_u16()?; + let obs_data_cutoff_minutes = nommer.read_u8()?; + let indicator_of_unit_in_time_range = nommer.read_u8()?; + let forecast_time = nommer.read_u32()?; + let first_fixed_surface_type = nommer.read_u8()?; + let scale_factor_first_fixed_surface = nommer.read_u8()?; + let scaled_value_first_fixed_surface = nommer.read_u32()?; + let second_fixed_surface_type = nommer.read_u8()?; + let scale_factor_second_fixed_surface = nommer.read_u8()?; + let scaled_value_second_fixed_surface = nommer.read_u32()?; + Ok(Self { + parameter_category, + parameter_number, + type_of_generating_process, + background_generating_process_id, + type_of_generating_process_identified, + obs_data_cutoff_hours, + obs_data_cutoff_minutes, + indicator_of_unit_in_time_range, + forecast_time, + first_fixed_surface_type, + scale_factor_first_fixed_surface, + scaled_value_first_fixed_surface, + second_fixed_surface_type, + scale_factor_second_fixed_surface, + scaled_value_second_fixed_surface, + }) + } +} + +#[derive(Debug)] +pub enum GridDefinition { + LatitudeLongitude(LatLongGrid) +} +impl GridDefinition { + fn image_coordinates(&self, at: LatLong) -> Option<(u64, u64)> { + match self { + GridDefinition::LatitudeLongitude(grid) => grid.image_coordinates(at) + } + } +} + +#[derive(Debug)] +pub struct LatLongGrid { + pub shape_of_the_earth: u8, + pub scale_factor_of_radius_of_spherical_earth: u8, + pub scale_value_of_radius_of_spherical_earth: u32, + pub scale_factor_of_major_axis_of_oblate_spheroid_earth: u8, + pub scaled_value_of_major_axis_of_oblate_spheroid_earth: u32, + pub scale_factor_of_minor_axis_of_oblate_spheroid_earth: u8, + pub scaled_value_of_minor_axis_of_oblate_spheroid_earth: u32, + pub ni: u32, // number of points along a parallel + pub nj: u32, // number of points along a meridian + pub basic_angle_of_the_initial_production_domain: u32, + pub subdivisions_of_basic_angle: u32, + pub la1: f64, + pub lo1: f64, + pub i_direction_increments_given: bool, + pub j_direction_increments_given: bool, + pub vector_relativity: LatLongVectorRelativity, + pub la2: f64, + pub lo2: f64, + pub di: f64, + pub dj: f64, + pub scanning_mode_flags: u8, +} +#[derive(Debug)] +pub enum LatLongVectorRelativity { + EasterlyAndNortherly, + IncreasingXY +} +impl LatLongGrid { + fn parse(length: u32, nommer: &mut NomReader) -> Result { + if length != 72 { + return Err(GribError::ListOfNumbersNotSupported); + } + let shape_of_the_earth= nommer.read_u8()?; + let scale_factor_of_radius_of_spherical_earth= nommer.read_u8()?; + let scale_value_of_radius_of_spherical_earth= nommer.read_u32()?; + let scale_factor_of_major_axis_of_oblate_spheroid_earth= nommer.read_u8()?; + let scaled_value_of_major_axis_of_oblate_spheroid_earth= nommer.read_u32()?; + let scale_factor_of_minor_axis_of_oblate_spheroid_earth= nommer.read_u8()?; + let scaled_value_of_minor_axis_of_oblate_spheroid_earth= nommer.read_u32()?; + let ni= nommer.read_u32()?; // number of points along a parallel + let nj= nommer.read_u32()?; // number of points along a meridian + let basic_angle_of_the_initial_production_domain= nommer.read_u32()?; + let subdivisions_of_basic_angle= nommer.read_u32()?; + let la1= nommer.read_u32()? as f64 * 10.0_f64.powi(-6); + let lo1= convert_longitude(nommer.read_u32()? as f64 * 10.0_f64.powi(-6)); + let resolution_and_component_flags= nommer.read_u8()?; + + let i_direction_increments_given = resolution_and_component_flags & (1 << 5) != 0; + let j_direction_increments_given = resolution_and_component_flags & (1 << 4) != 0; + let vector_relativity = if resolution_and_component_flags & (1 << 3) != 0 { IncreasingXY } else { EasterlyAndNortherly }; + + let la2= nommer.read_u32()? as f64 * 10.0_f64.powi(-6); + let lo2= convert_longitude(nommer.read_u32()? as f64 * 10.0_f64.powi(-6)); + let di= nommer.read_u32()? as f64 * 10.0_f64.powi(-6); + let dj= nommer.read_u32()? as f64 * 10.0_f64.powi(-6); + let scanning_mode_flags= nommer.read_u8()?; + + Ok(Self { + shape_of_the_earth, + scale_factor_of_radius_of_spherical_earth, + scale_value_of_radius_of_spherical_earth, + scale_factor_of_major_axis_of_oblate_spheroid_earth, + scaled_value_of_major_axis_of_oblate_spheroid_earth, + scale_factor_of_minor_axis_of_oblate_spheroid_earth, + scaled_value_of_minor_axis_of_oblate_spheroid_earth, + ni, + nj, + basic_angle_of_the_initial_production_domain, + subdivisions_of_basic_angle, + la1, + lo1, + i_direction_increments_given, + j_direction_increments_given, + vector_relativity, + la2, + lo2, + di, + dj, + scanning_mode_flags, + }) + } + + fn image_coordinates(&self, at: LatLong) -> Option<(u64, u64)> { + if at.lat > self.la1 || at.lat < self.la2 { return None; } + if at.long < self.lo1 || at.long > self.lo2 { return None; } + + let lat = ((at.lat - self.la1) / self.di ).round() * self.di + self.la1; + let long = ((at.long - self.lo1) / self.dj).round() * self.dj + self.lo1; + + if (lat - at.lat).abs() > self.di || (long - at.long).abs() > self.dj { + return None; + } + + let diff_lat = at.lat - self.la1; + let num_steps_lat = diff_lat / -self.di; + + let diff_long = at.long - self.lo1; + let num_steps_long = diff_long / self.dj; + + Some((num_steps_long as u64, num_steps_lat as u64)) + } +} + + + + +fn convert_longitude(longitude: f64) -> f64 { + if longitude > 180.0 { + longitude - 360.0 + } else { + longitude + } +} \ No newline at end of file diff --git a/wxbox-grib2/src/nommer.rs b/wxbox-grib2/src/nommer.rs new file mode 100644 index 0000000..872894d --- /dev/null +++ b/wxbox-grib2/src/nommer.rs @@ -0,0 +1,44 @@ +use std::io::Read; + +#[derive(Debug)] +pub struct NomReader { + inner: R +} +impl NomReader { + pub fn new(inner: R) -> NomReader { + Self { + inner + } + } + + pub fn read_u8(&mut self) -> Result { + let mut buf = [0u8; 1]; + self.inner.read_exact(&mut buf)?; + Ok(u8::from_be_bytes(buf)) + } + pub fn read_u16(&mut self) -> Result { + let mut buf = [0u8; 2]; + self.inner.read_exact(&mut buf)?; + Ok(u16::from_be_bytes(buf)) + } + pub fn read_u32(&mut self) -> Result { + let mut buf = [0u8; 4]; + self.inner.read_exact(&mut buf)?; + Ok(u32::from_be_bytes(buf)) + } + pub fn read_u64(&mut self) -> Result { + let mut buf = [0u8; 8]; + self.inner.read_exact(&mut buf)?; + Ok(u64::from_be_bytes(buf)) + } + pub fn read_n(&mut self, n: usize) -> Result, std::io::Error> { + let mut buf = vec![0u8; n]; + self.inner.read_exact(&mut buf)?; + Ok(buf) + } + pub fn read_f32(&mut self) -> Result { + let mut buf = [0u8; 4]; + self.inner.read_exact(&mut buf)?; + Ok(f32::from_be_bytes(buf)) + } +} \ No newline at end of file diff --git a/wxbox-grib2/src/wgs84.rs b/wxbox-grib2/src/wgs84.rs new file mode 100644 index 0000000..92b1e18 --- /dev/null +++ b/wxbox-grib2/src/wgs84.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Copy, Clone)] +pub struct LatLong { + pub lat: f64, + pub long: f64 +} \ No newline at end of file diff --git a/wxbox-tiler/Cargo.toml b/wxbox-tiler/Cargo.toml index e61edb8..cf3b6b3 100644 --- a/wxbox-tiler/Cargo.toml +++ b/wxbox-tiler/Cargo.toml @@ -16,8 +16,9 @@ tokio = "1" wxbox-pal = { version = "0.1", path = "../wxbox-pal" } png = "0.17" mime = "0.3.17" -eccodes = { version = "0.12", features = ["message_ndarray"] } -ndarray = "0.16" +wxbox-grib2 = { version = "0.1", path = "../wxbox-grib2" } +tracing = "0.1" +tracing-subscriber = "0.3" [dev-dependencies] approx = "0.5" diff --git a/wxbox-tiler/src/grib2.rs b/wxbox-tiler/src/grib2.rs deleted file mode 100644 index dab6b7a..0000000 --- a/wxbox-tiler/src/grib2.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::collections::BTreeMap; -use ordered_float::OrderedFloat; - -pub fn closest_key(map: &BTreeMap, V>, val: f64) -> Option<(OrderedFloat, f64)> { - let mut r1 = map.range(OrderedFloat(val)..); - let r2 = map.range(..=OrderedFloat(val)); - let o1 = r1.next(); - let o2 = r2.last(); - match (o1, o2) { - (None, None) => { - None - }, - (Some(i), None) => { - Some((*i.0, (*i.0 - val).abs())) - }, - (None, Some(i)) => { - Some((*i.0, (*i.0 - val).abs())) - }, - (Some(i1), Some(i2)) => { - // abs(f - i) - let i1_dist = (i1.0 - val).abs(); - let i2_dist = (i2.0 - val).abs(); - Some(if i1_dist < i2_dist { - (*i1.0, i1_dist) - } else { - (*i2.0, i2_dist) - }) - } - } -} - -pub fn lookup(map: &BTreeMap, V>, val: f64) -> Option<&V> { - let mut r1 = map.range(OrderedFloat(val)..); - let mut r2 = map.range(..OrderedFloat(val)); - let o1 = r1.next(); - let o2 = r2.next(); - match (o1, o2) { - (None, None) => None, - (Some(i), None) => Some(i.1), - (None, Some(i)) => Some(i.1), - (Some(i1), Some(i2)) => { - // abs(f - i) - let i1_dist = (i1.0 - val).abs(); - let i2_dist = (i2.0 - val).abs(); - Some(if i1_dist < i2_dist { - i1.1 - } else { - i2.1 - }) - } - } -} - - -pub type LookupTable2D = BTreeMap, BTreeMap, f64>>; diff --git a/wxbox-tiler/src/main.rs b/wxbox-tiler/src/main.rs index 74c0038..7caa532 100644 --- a/wxbox-tiler/src/main.rs +++ b/wxbox-tiler/src/main.rs @@ -1,39 +1,28 @@ pub(crate) mod sources; -mod grib2; mod pixmap; -use std::collections::{BTreeMap}; +use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; +use std::sync::Arc; use tokio::sync::RwLock; use std::time::SystemTime; use actix_web::{App, HttpServer}; use actix_web::web::Data; -use crate::grib2::{LookupTable2D}; - -#[global_allocator] -static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; - -#[repr(usize)] -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone, Copy)] -pub enum LutKey { - NoaaMrmsMergedCompositeReflectivityQc = 1 -} +use wxbox_grib2::GribMessage; pub struct AppState { - lut_cache: RwLock>, - lut_cache_timestamps: RwLock> + grib2_cache: RwLock>>>, + grib2_cache_timestamps: RwLock> } #[actix_web::main] async fn main() -> std::io::Result<()> { - let f = reqwest::get("https://mrms.ncep.noaa.gov/data/2D/ReflectivityAtLowestAltitude/MRMS_ReflectivityAtLowestAltitude.latest.grib2.gz").await.unwrap(); - - + tracing_subscriber::fmt::init(); let data = Data::new(AppState { - lut_cache: RwLock::new(BTreeMap::new()), - lut_cache_timestamps: RwLock::new(BTreeMap::new()) + grib2_cache: RwLock::new(HashMap::new()), + grib2_cache_timestamps: RwLock::new(HashMap::new()) }); HttpServer::new(move || { App::new() diff --git a/wxbox-tiler/src/sources/grib2.rs b/wxbox-tiler/src/sources/grib2.rs index 00826b6..b9bf6c4 100644 --- a/wxbox-tiler/src/sources/grib2.rs +++ b/wxbox-tiler/src/sources/grib2.rs @@ -1,24 +1,20 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::f64::consts::PI; use std::io::{BufWriter, Cursor, Read}; -use std::time::{SystemTime, UNIX_EPOCH}; -use eccodes::{CodesHandle, FallibleStreamingIterator, ProductKind}; +use std::sync::Arc; +use std::time::SystemTime; use flate2::read::GzDecoder; -use ndarray::Zip; -use ordered_float::OrderedFloat; use png::{BitDepth, ColorType, Encoder}; use tokio::sync::RwLock; +use wxbox_grib2::GribMessage; +use wxbox_grib2::wgs84::LatLong; use wxbox_pal::{Color, ColorPalette, Palette}; -use crate::grib2::{closest_key, LookupTable2D}; -use crate::LutKey; use crate::pixmap::Pixmap; -pub async fn needs_reload(lct: &RwLock>, lutkey: &LutKey, valid_for: u64) -> bool { - eprintln!("debug: try lock needs_reload() lut_cache_timestamps start"); +pub async fn needs_reload(lct: &RwLock>, lutkey: &String, valid_for: u64) -> bool { let lct_reader = lct.read().await; - eprintln!("debug: try lock needs_reload() lut_cache_timestamps locked"); - if let Some(t) = lct_reader.get(&lutkey) { + if let Some(t) = lct_reader.get(lutkey) { let dur = SystemTime::now().duration_since(*t).expect("time went backwards").as_secs(); if dur > valid_for { return true; @@ -51,101 +47,56 @@ pub async fn load(url: &str, is_gzipped: bool) -> Vec { out } -pub fn eccodes_remap(data: Vec) -> LookupTable2D { - let product_kind = ProductKind::GRIB; - let mut handle = CodesHandle::new_from_memory(data.clone(), product_kind).unwrap(); - let msg = handle.next().expect("empty grib2 file").expect("empty grib2 file").try_clone().unwrap(); - - let mut map = LookupTable2D::new(); - - let arr = msg.to_lons_lats_values().unwrap(); - - Zip::from(&arr.latitudes) - .and(&arr.longitudes) - .and(&arr.values) - .for_each(|&lat, &long, &value| { - let lat = OrderedFloat(lat); - - let mut long = long; - if long > 180.0 { - long -= 360.0; - } - - let long = OrderedFloat(long); - - if let Some(row) = map.get_mut(&lat) { - row.insert(long, value); - } else { - map.insert(lat, BTreeMap::from([ - (long, value) - ])); - } - }); - - map -} - -pub async fn reload_if_required(from: &str, needs_gzip: bool, valid_for: u64, lut_key: LutKey, lct_cache: &RwLock>, lut_cache: &RwLock>) { - if needs_reload(&lct_cache, &lut_key, valid_for).await { - eprintln!("debug: try lock reload_if_required() lut_cache_timestamps start WRITE"); +pub async fn reload_if_required(from: &str, needs_gzip: bool, valid_for: u64, lut_key: &String, lct_cache: &RwLock>, lut_cache: &RwLock>>>) { + if needs_reload(&lct_cache, lut_key, valid_for).await { let mut lct_writer = lct_cache.write().await; - eprintln!("debug: try lock reload_if_required() lut_cache_timestamps locked WRITE"); - let map = eccodes_remap(load(from, needs_gzip).await); + let message = load(from, needs_gzip).await; + let grib = GribMessage::new(Cursor::new(message)).unwrap(); - eprintln!("debug: try lock reload_if_required() lut_cache start"); - lut_cache.write().await.insert(lut_key, map); - eprintln!("debug: try lock reload_if_required() lut_cache locked"); - lct_writer.insert(lut_key, SystemTime::now()); + lut_cache.write().await.insert(lut_key.clone(), Arc::new(RwLock::new(grib))); + lct_writer.insert(lut_key.clone(), SystemTime::now()); } } const TWO_PI: f64 = PI * 2.0; const HALF_PI: f64 = PI / 2.0; -pub fn render(xtile: f64, ytile: f64, z: i32, tilesize: usize, pal: Palette, map: &LookupTable2D, missing: Option, range_folded: Option, no_coverage: Option) -> Vec { +pub async fn render(xtile: f64, ytile: f64, z: i32, tilesize: usize, pal: Palette, map: &Arc>, missing: Option, range_folded: Option, no_coverage: Option) -> Vec { let mut image: Pixmap = Pixmap::new(); let denominator = 2.0_f64.powi(z) * tilesize as f64; let xtile_times_tilesize = xtile * tilesize as f64; let ytile_times_tilesize = ytile * tilesize as f64; - for x in 0..tilesize { - for y in 0..tilesize { - let tx = (xtile_times_tilesize + x as f64) / denominator; - let ty = (ytile_times_tilesize + y as f64) / denominator; + { + let message = map.read().await; + for x in 0..tilesize { + for y in 0..tilesize { + let tx = (xtile_times_tilesize + x as f64) / denominator; + let ty = (ytile_times_tilesize + y as f64) / denominator; - let lon = (TWO_PI * tx - PI).to_degrees(); - let lat = ((PI - TWO_PI * ty).exp().atan() * 2.0_f64 - HALF_PI).to_degrees(); + let lon = (TWO_PI * tx - PI).to_degrees(); + let lat = ((PI - TWO_PI * ty).exp().atan() * 2.0_f64 - HALF_PI).to_degrees(); + let nearest = message.value_for(LatLong { + lat, + long: lon + }).map(|u| u as f64); - let closest_lat_in_map = &closest_key(map, lat).unwrap(); + let color = match nearest { + Some(c) if Some(c) == no_coverage => Color { red: 0, green: 0, blue: 0, alpha: 30 }, + Some(c) if Some(c) == missing => Color { red: 0, green: 0, blue: 0, alpha: 0 }, + Some(c) if Some(c) == range_folded => Color { red: 141, green: 0, blue: 160, alpha: 0 }, + Some(value_at_pos) => { + pal.colorize(value_at_pos) + }, + None => Color { red: 0, green: 0, blue: 0, alpha: 30 } + }; - if closest_lat_in_map.1 > 0.01 { - image.set(y, x, Color { red: 0, green: 0, blue: 0, alpha: 30 }); - continue; + image.set(y, x, color); } - - let row = map.get(&closest_lat_in_map.0).unwrap(); - let closest_long_in_row = closest_key(row, lon).unwrap(); - - let value = row.get(&closest_long_in_row.0).unwrap(); - - if closest_long_in_row.1 > 0.01 { - image.set(y, x, Color { red: 0, green: 0, blue: 0, alpha: 30 }); - continue; - } - - let color = match value { - c if Some(*c) == no_coverage => Color { red: 0, green: 0, blue: 0, alpha: 30 }, - c if Some(*c) == missing => Color { red: 0, green: 0, blue: 0, alpha: 0 }, - c if Some(*c) == range_folded => Color { red: 141, green: 0, blue: 160, alpha: 0 }, - value_at_pos => { - pal.colorize(*value_at_pos) - } - }; - image.set(y, x, color); } } @@ -176,28 +127,26 @@ pub fn render(xtile: f64, ytile: f64, z: i32, tilesize: usize, pal: Palette, map #[macro_export] macro_rules! grib2_handler { - (mount $f:ident, at: $path:expr, from: $from:expr, needs_gzip: $needs_gzip:expr, valid_for: $valid_for:expr, lut_with: $lut_key:expr, palette: $pal:expr, missing: $missing:expr, range_folded: $rf:expr, no_coverage: $nc:expr) => { + (mount $f:ident, at: $path:expr, from: $from:expr, needs_gzip: $needs_gzip:expr, valid_for: $valid_for:expr, palette: $pal:expr, missing: $missing:expr, range_folded: $rf:expr, no_coverage: $nc:expr) => { #[::actix_web::get($path)] async fn $f(path: ::actix_web::web::Path<(i32,u32,u32)>, data: ::actix_web::web::Data) -> ::actix_web::HttpResponse { crate::sources::grib2::reload_if_required( $from, $needs_gzip, $valid_for, - $lut_key, - &data.lut_cache_timestamps, - &data.lut_cache + &String::from($path), + &data.grib2_cache_timestamps, + &data.grib2_cache ).await; - eprintln!("debug: try lock handler lut_cache_timestamps start"); - let lct_reader = data.lut_cache_timestamps.read().await; - eprintln!("debug: try lock handler lut_cache_timestamps locked"); - if let Some(map) = data.lut_cache.read().await.get(&$lut_key) { + let lct_reader = data.grib2_cache_timestamps.read().await; + if let Some(map) = data.grib2_cache.read().await.get($path) { ::actix_web::HttpResponse::Ok() .insert_header(::actix_web::http::header::ContentType(::mime::IMAGE_PNG)) - .insert_header(("x-wxbox-tiler-data-valid-time", lct_reader.get(&$lut_key).expect("impossible").duration_since(::std::time::UNIX_EPOCH).expect("time went backwards").as_secs().to_string())) + .insert_header(("x-wxbox-tiler-data-valid-time", lct_reader.get($path).expect("impossible").duration_since(::std::time::UNIX_EPOCH).expect("time went backwards").as_secs().to_string())) .insert_header(("Access-Control-Allow-Origin", "*")) .insert_header(("Access-Control-Expose-Headers", "*")) .insert_header(("Access-Control-Allow-Headers", "*")) - .body(crate::sources::grib2::render(path.1 as f64, path.2 as f64, path.0, 256, $pal, map, $missing, $rf, $nc)) + .body(crate::sources::grib2::render(path.1 as f64, path.2 as f64, path.0, 256, $pal, map, $missing, $rf, $nc).await) } else { ::actix_web::HttpResponse::new(::actix_web::http::StatusCode::NOT_FOUND) } diff --git a/wxbox-tiler/src/sources/noaa/mod.rs b/wxbox-tiler/src/sources/noaa/mod.rs index 077d513..4f2be63 100644 --- a/wxbox-tiler/src/sources/noaa/mod.rs +++ b/wxbox-tiler/src/sources/noaa/mod.rs @@ -1,4 +1,4 @@ -use crate::{grib2_handler, LutKey}; +use crate::grib2_handler; grib2_handler! { mount noaa_mrms_merged_composite_reflectivity_qc, @@ -6,7 +6,6 @@ grib2_handler! { from: "https://mrms.ncep.noaa.gov/data/2D/MergedReflectivityQCComposite/MRMS_MergedReflectivityQCComposite.latest.grib2.gz", needs_gzip: true, valid_for: 120, - lut_with: LutKey::NoaaMrmsMergedCompositeReflectivityQc, palette: wxbox_pal::parser::parse(wxbox_pal::default_palettes::DEFAULT_REFLECTIVITY_PALETTE).unwrap(), missing: Some(-99.0), range_folded: None, diff --git a/wxbox-web/package.json b/wxbox-web/package.json index 6d0bd31..4e91ebe 100644 --- a/wxbox-web/package.json +++ b/wxbox-web/package.json @@ -24,7 +24,6 @@ "prettier": "^3.3.3", "prettier-plugin-svelte": "^3.2.7", "svelte": "^5.1.3", - "svelte-adapter-bun": "^0.5.2", "svelte-check": "^4.0.5", "typescript": "^5.6.3", "typescript-eslint": "^8.11.0", diff --git a/wxbox-web/src/routes/+page.svelte b/wxbox-web/src/routes/+page.svelte index 4b8c947..1dd64d8 100644 --- a/wxbox-web/src/routes/+page.svelte +++ b/wxbox-web/src/routes/+page.svelte @@ -373,7 +373,7 @@ {/if} diff --git a/wxbox-web/svelte.config.js b/wxbox-web/svelte.config.js index 1d5479b..1295460 100644 --- a/wxbox-web/svelte.config.js +++ b/wxbox-web/svelte.config.js @@ -1,4 +1,4 @@ -import adapter from 'svelte-adapter-bun'; +import adapter from '@sveltejs/adapter-auto'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; /** @type {import('@sveltejs/kit').Config} */