diff --git a/Cargo.lock b/Cargo.lock index 14f9391..9ce767d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,11 +2,478 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[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 = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bitstream-io" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] + +[[package]] +name = "built" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "exr" +version = "1.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "flate2" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gif" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "image" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core 0.5.1", + "zune-jpeg 0.5.10", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + +[[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 = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "markprint" version = "0.1.0" dependencies = [ - "nom", + "image", + "quick-xml", + "serde", +] + +[[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]] @@ -15,6 +482,32 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nom" version = "8.0.0" @@ -23,3 +516,543 @@ checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" dependencies = [ "memchr", ] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "pxfm" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "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", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg 0.4.21", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core 0.4.12", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2db9186c0a6ad1aa7012046f3fadc8db9001691b367c510f5867f17f975752" +dependencies = [ + "zune-core 0.5.1", +] diff --git a/Cargo.toml b/Cargo.toml index baa9aff..714ba64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] -nom = "8.0.0" +image = "0.25.9" +quick-xml = { version = "0.39.0", features = ["serialize"] } +serde = { version = "1.0.228", features = ["derive"] } +# nom = "8.0.0" + diff --git a/src/escpos.rs b/src/escpos.rs new file mode 100644 index 0000000..28721d4 --- /dev/null +++ b/src/escpos.rs @@ -0,0 +1,305 @@ +use std::{error::Error, fmt::Display}; + +use image::{ + DynamicImage, GrayImage, + imageops::{self, FilterType, colorops}, +}; +use serde::Deserialize; + +// TYPES +#[derive(Debug)] +pub enum EscPosError { + InvalidBarcodeLength(String), +} + +#[repr(u8)] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum QREcc { + Low = 48, + Medium = 49, + Quartile = 50, + High = 51, +} +#[repr(u8)] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum BARTextPosition { + Hidden = 0, + Above = 1, + Below = 2, + Both = 3, +} +#[repr(u8)] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum BARType { + Code128 = 0x49, + Ean13 = 0x43, + Upca = 0x41, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum ImageOrientation { + Preserve, + Largest, + LargestOrientation, +} + +#[repr(u8)] +#[derive(Debug, Deserialize, Default)] +#[serde(rename_all = "lowercase")] +pub enum JustifyOrientation { + #[default] + Left = 0, + Center = 1, + Right = 2, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TextEffect { + Bold, + DoubleHeight, + DoubleWidth, + // InvertColor, + Justify(JustifyOrientation), +} + +pub struct EscPosBuilder { + pub content: Vec, + max_width: u16, +} + +fn is_numeric(s: &[u8]) -> bool { + s.iter().all(|&b| b.is_ascii_digit()) +} +fn bitmap_auto_brighten(gray: &mut GrayImage) { + let avg = gray.pixels().map(|p| p.0[0] as u32).sum::() / gray.len() as u32; + + if avg < 100 { + colorops::brighten_in_place(gray, 40); + colorops::contrast_in_place(gray, 25.0); + } else if avg > 180 { + colorops::brighten_in_place(gray, -15); + } +} +fn bitmap_pack_bits(w: usize, h: usize, gray: &GrayImage) -> Vec { + let pitch = (w + 7) >> 3; // pixels per row + let mut bits = vec![0u8; pitch * h]; + + for y in 0..h { + for x in 0..w { + let byte = y * pitch + (x >> 3); // get index of byte that contains bit for the current pixel + let bit = 7 - (x & 7); // get bit position in byte + if gray[(x as u32, y as u32)].0[0] == 0 { + // if the pixel is black, set it to one + bits[byte] |= 1 << bit; + } + } + } + + bits +} + +impl Copy for JustifyOrientation {} +impl Clone for JustifyOrientation { + fn clone(&self) -> Self { + *self + } +} +impl Error for EscPosError {} +impl Display for EscPosError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +impl EscPosBuilder { + fn extend(&mut self, slice: &[u8]) { + self.content.extend([0x1B, b'@']); + self.content.extend(slice); + } + + pub fn new(max_width: u16) -> Self { + EscPosBuilder { + content: vec![0x1B, b'@'], + max_width, + } + } + + pub fn write_feed(&mut self, amount: Option) { + let amount = amount.unwrap_or(1); + self.extend(&[0x1B, b'd', amount]) + } + + pub fn write_justify(&mut self, justify: JustifyOrientation) { + self.extend(&[0x1B, b'a', justify as u8]); + } + + pub fn write_text(&mut self, text: &str, text_effect: Option<&[TextEffect]>) -> () { + let mut buf: Vec = vec![]; + buf.reserve(12 + text.len()); + + for i in text_effect.unwrap_or(&[]) { + match i { + TextEffect::Bold => buf.extend(&[0x1B, b'!', 8]), + TextEffect::DoubleWidth => buf.extend(&[0x1B, b'!', 0x10]), + TextEffect::DoubleHeight => buf.extend(&[0x1B, b'!', 0x20]), + TextEffect::Justify(orientation) => buf.extend(&[0x1B, b'a', *orientation as u8]), + } + } + + buf.extend(text.as_bytes()); + self.extend(&buf); + } + + pub fn write_bitmap( + &mut self, + img: &DynamicImage, + orientation: Option, + ) -> () { + let orientation = orientation.unwrap_or(ImageOrientation::Preserve); + let mw = self.max_width as u32; + + let mut image = img.clone(); + + if matches!(orientation, ImageOrientation::LargestOrientation) + && image.width() > image.height() + { + image = image.rotate90(); + } + + let iw = image.width(); + let ih = image.height(); + + let w = if iw > mw || !matches!(orientation, ImageOrientation::Preserve) { + mw + } else { + iw + }; + + let h = (ih * w) / iw; + let img = image.resize(w, h, FilterType::Triangle); + + let mut gray = img.to_luma8(); + imageops::dither(&mut gray, &imageops::colorops::BiLevel); + bitmap_auto_brighten(&mut gray); + + let w = img.width(); + let h = img.height(); + + let bits = bitmap_pack_bits(w as usize, h as usize, &gray); + let mut buf: Vec = vec![]; + + let width_bytes = ((w + 7) >> 3) as u16; + let height_u16 = h as u16; + + buf.extend(&[ + 0x1D, + b'v', + b'0', + 0, + (width_bytes & 0xFF) as u8, + ((width_bytes >> 8) & 0xFF) as u8, + (height_u16 & 0xFF) as u8, + ((height_u16 >> 8) & 0xFF) as u8, + ]); + buf.extend(bits); + self.extend(&buf); + } + + pub fn write_qr(&mut self, text: &str, size: Option, ecc: Option) -> () { + let mut buf: Vec = vec![]; + let ecc = ecc.unwrap_or(QREcc::Medium); + let size = match size { + Some(v) => v.clamp(6, 15), + None => 10, + }; + + let text = text.as_bytes(); + let len = text.len() + 3; + buf.extend(&[ + // Size + 0x1D, + 0x28, + 0x6B, + 0x03, + 0x00, + 0x31, + 0x43, + size, + // Error correction level + 0x1D, + 0x28, + 0x6B, + 0x03, + 0x00, + 0x31, + 0x45, + ecc as u8, + // Storing data... + 0x1D, + 0x28, + 0x6B, + (len & 0xFF) as u8, + ((len >> 8) & 0xFF) as u8, + 0x31, + 0x50, + 0x30, + ]); + buf.extend(text); + buf.extend(&[0x1D, 0x28, 0x6B, 0x03, 0x00, 0x31, 0x51, 0x30, 0x0A]); // Print! + + self.extend(&buf); + } + pub fn write_barcode( + &mut self, + text: &str, + height: Option, + mod_width: Option, + text_position: Option, + bar_type: Option, + ) -> Result<(), EscPosError> { + let height: u8 = height.unwrap_or(80); + let mod_width: u8 = mod_width.unwrap_or(2); + let text_position = text_position.unwrap_or(BARTextPosition::Below) as u8; + let bar_type = bar_type.unwrap_or(BARType::Code128); + + let text = text.as_bytes(); + let len = text.len() as u8; + let is_num = is_numeric(text); + match bar_type { + BARType::Upca if len != 11 || !is_num => Err(EscPosError::InvalidBarcodeLength( + "UCPA Requires 11 numbers.".to_string(), + )), + + BARType::Ean13 if len != 12 || !is_num => Err(EscPosError::InvalidBarcodeLength( + "EAN13 Requires 12 numbers.".to_string(), + )), + _ => Ok(()), + }?; + + let mut buf: Vec = vec![]; + buf.extend([ + 0x1D, + 0x68, + height, + 0x1D, + 0x77, + mod_width, + 0x1d, + 0x48, + text_position, + 0x1D, + 0x6B, + bar_type as u8, + len, + ]); + buf.extend(text); + self.extend(&buf); + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index 9a230a6..65f8cdb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,70 +1,218 @@ -use nom::{ - IResult, Parser, - branch::alt, - bytes::complete::{tag, take_until}, - character::complete::{line_ending, not_line_ending}, - combinator::{map, success}, - error::Error, - multi::fold, - sequence::{delimited, preceded}, -}; -use std::vec::Vec; +use quick_xml::de::from_str; +use serde::de::IntoDeserializer; +use serde::{Deserialize, de}; +use std::io::{Read, Write, stdout}; +use std::{error::Error, io::stdin}; -enum Fragment<'a> { - Literal(&'a str), - Header(&'a str), +mod escpos; +use escpos::{BARTextPosition, BARType, EscPosBuilder, ImageOrientation, QREcc, TextEffect}; + +use crate::escpos::JustifyOrientation; + +#[derive(Debug, Deserialize)] +struct Document { + #[serde(rename = "$value")] + pub children: Vec, } -fn main() { - let input = concat!( - // "Hallo daar!\n", - // "Hoe gaat het?\n", - "# Met mij gaat het goed\n", - "Met jou\n", - "## Ja ook goed\n", - // "Echt?\n", - // "### Wow (not matched because we only accept 1 or 2 '#')\n", - // "#StartOfFileHeaderNoSpace <-- not matched because we require a space after '#'\n", - // " ## Indented header\n" - ); +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +enum Node { + #[serde(rename = "$text")] + PlainText(String), - let vec = Vec::::new(); - use nom::bytes::complete::tag; - use nom::sequence::preceded; + #[serde(rename = "h")] + Heading(Heading), - println!("{:?}", parse_fragment(input)) + #[serde(rename = "p")] + Text(Text), + + #[serde(rename = "justify")] + Justify(Justify), + + #[serde(rename = "img")] + Img(Img), + + #[serde(rename = "qr")] + Qr(Qr), + + #[serde(rename = "bar")] + Barcode(Barcode), + + #[serde(rename = "br")] + Feed(Feed), } -fn parse_header<'a>(input: &'a str) -> IResult<&'a str, &str, ()> { - delimited(tag::<&str, &str, ()>("# "), not_line_ending, line_ending).parse(input) -} -fn parse_fragment<'a>(input: &'a str) -> IResult<&str, Fragment, ()> { - alt(( - map(parse_header, Fragment::Header), - map(not_line_ending, Fragment::Literal), - )) - .parse(input) -} -fn parse_string<'a>(input: &'a str) -> IResult<&'a str, Vec>, ()> { - fold( - 0.., - parse_fragment, - Vec::::new(), - |mut vector, fragment| vector, - ) +#[derive(Debug, Deserialize)] +struct Justify { + #[serde(rename = "@align")] + pub align: JustifyOrientation, + + #[serde(rename = "$value")] + pub value: Vec, } -// fn parse_fragment<'a, E>(input: &'a str) -> IResult<&'a str, StringFragment<'a>, E> -// where -// E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>, -// { -// alt((map(parse_header, Fragment::Header))) -// } -// -// fn parse_header<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> { -// preceded( -// permutation((char('\n'), many_m_n(1, 2, char('#')))), -// take_until("\n"), -// ) -// .parse(input) -// } +#[derive(Debug, Deserialize)] +struct Heading { + #[serde(rename = "$value")] + pub value: String, +} + +#[derive(Debug, Deserialize)] +struct Text { + #[serde(rename = "@effects")] + #[serde(deserialize_with = "deserialize_effects")] + #[serde(default)] + pub style: Option>, + + #[serde(rename = "$value")] + pub value: String, +} + +#[derive(Debug, Deserialize)] +struct Img { + #[serde(rename = "@src")] + pub src: String, + + #[serde(rename = "@orientation")] + #[serde(default)] + pub orientation: Option, +} + +#[derive(Debug, Deserialize)] +struct Qr { + #[serde(rename = "@size")] + #[serde(default)] + pub size: Option, + + #[serde(rename = "@ecc")] + #[serde(default)] + pub ecc: Option, + + #[serde(rename = "$value")] + pub value: String, +} + +#[derive(Debug, Deserialize)] +struct Barcode { + #[serde(rename = "@height")] + #[serde(default)] + pub height: Option, + + #[serde(rename = "@mod_width")] + #[serde(default)] + pub mod_width: Option, + + #[serde(rename = "@text_position")] + #[serde(default)] + pub text_position: Option, + + #[serde(rename = "@bar_type")] + #[serde(default)] + pub bar_type: Option, + + #[serde(rename = "$value")] + pub value: String, +} + +#[derive(Debug, Deserialize)] +struct Feed { + #[serde(rename = "@amount")] + #[serde(default)] + pub amount: Option, +} + +fn deserialize_effects<'de, D>(deserializer: D) -> Result>, D::Error> +where + D: de::Deserializer<'de>, +{ + let opt: Option = Option::deserialize(deserializer)?; + let mut out: Vec = Vec::new(); + if let Some(s) = opt { + for raw in s.split(';') { + let tok = raw.trim(); + if tok.is_empty() { + continue; + } + let deserialized = TextEffect::deserialize(tok.into_deserializer())?; + out.push(deserialized); + } + } + Ok(Some(out)) +} + +fn handle_node(node: Node, builder: &mut EscPosBuilder) -> Result<(), Box> { + match node { + Node::PlainText(ref t) => { + builder.write_text(t.trim(), None); + builder.write_feed(None); + } + Node::Heading(t) => { + builder.write_text( + &t.value, + Some(&[TextEffect::DoubleHeight, TextEffect::DoubleWidth]), + ); + builder.write_feed(None); + } + Node::Text(t) => { + if let Some(ref list) = t.style { + builder.write_text(&t.value, Some(list)); + } else { + builder.write_text(&t.value, None); + } + + builder.write_feed(None); + } + Node::Justify(t) => { + builder.write_justify(t.align); + for i in t.value { + handle_node(i, builder)?; + } + builder.write_justify(JustifyOrientation::default()); + } + Node::Img(img) => { + let dynimg = image::open(&img.src)?; + builder.write_bitmap(&dynimg, img.orientation); + } + Node::Qr(q) => { + let value = q.value; + let value = value.trim(); + + if value.is_empty() { + return Ok(()); + }; + builder.write_qr(&value, q.size, q.ecc); + } + Node::Barcode(b) => { + let value = b.value; + let value = value.trim(); + + if value.is_empty() { + return Ok(()); + }; + builder.write_barcode(&value, b.height, b.mod_width, b.text_position, b.bar_type)?; + } + Node::Feed(f) => { + builder.write_feed(f.amount); + } + } + Ok(()) +} +fn handle_document(doc: Document, builder: &mut EscPosBuilder) -> Result<(), Box> { + for node in doc.children { + handle_node(node, builder)?; + } + Ok(()) +} + +fn main() -> Result<(), Box> { + let mut xml: String = String::new(); + stdin().read_to_string(&mut xml)?; + let doc: Document = from_str::(&xml)?; + + let mut builder = EscPosBuilder::new(384); + handle_document(doc, &mut builder)?; + + stdout().write(&builder.content)?; + Ok(()) +}