qrencode-0.14.0/.cargo_vcs_info.json0000644000000001360000000000100127160ustar { "git": { "sha1": "9c1d54ca68985056b111e353a9272a07043604a8" }, "path_in_vcs": "" }qrencode-0.14.0/.github/FUNDING.yml000064400000000000000000000013451046102023000146660ustar 00000000000000# These are supported funding model platforms github: [ sayanarijit ] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] qrencode-0.14.0/.github/workflows/ci.yml000064400000000000000000000007771046102023000162340ustar 00000000000000on: [push] name: CI jobs: build_and_test: name: qrencode runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable - uses: actions-rs/cargo@v1 with: command: test args: --no-default-features - uses: actions-rs/cargo@v1 with: command: test - uses: actions-rs/cargo@v1 with: command: run args: --bin qrencode -- foo qrencode-0.14.0/Cargo.lock0000644000000353240000000000100107000ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bit_field" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytemuck" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "checked_int_cast" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" [[package]] name = "color_quant" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "crc32fast" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", "scopeguard", ] [[package]] name = "crossbeam-utils" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "exr" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8af5ef47e2ed89d23d0ecbc1b681b30390069de70260937877514377fc24feb" dependencies = [ "bit_field", "flume", "half", "lebe", "miniz_oxide", "smallvec", "threadpool", "zune-inflate", ] [[package]] name = "flate2" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] name = "flume" version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", "nanorand", "pin-project", "spin", ] [[package]] name = "futures-core" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-sink" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "getrandom" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "gif" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" dependencies = [ "color_quant", "weezl", ] [[package]] name = "half" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" dependencies = [ "crunchy", ] [[package]] name = "hermit-abi" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] [[package]] name = "image" version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" dependencies = [ "bytemuck", "byteorder", "color_quant", "exr", "gif", "jpeg-decoder", "num-rational", "num-traits", "png", "scoped_threadpool", "tiff", ] [[package]] name = "jpeg-decoder" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" dependencies = [ "rayon", ] [[package]] name = "js-sys" version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] [[package]] name = "lebe" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "lock_api" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] [[package]] name = "memoffset" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] [[package]] name = "miniz_oxide" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] [[package]] name = "nanorand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ "getrandom", ] [[package]] name = "num-integer" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", ] [[package]] name = "num-rational" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "pin-project" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "png" version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ "bitflags", "crc32fast", "flate2", "miniz_oxide", ] [[package]] name = "proc-macro2" version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] [[package]] name = "qrencode" version = "0.14.0" dependencies = [ "checked_int_cast", "image", ] [[package]] name = "quote" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", "num_cpus", ] [[package]] name = "scoped_threadpool" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "simd-adler32" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14a5df39617d7c8558154693a1bb8157a4aab8179209540cc0b10e5dc24e0b18" [[package]] name = "smallvec" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "spin" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" dependencies = [ "lock_api", ] [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "threadpool" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" dependencies = [ "num_cpus", ] [[package]] name = "tiff" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" dependencies = [ "flate2", "jpeg-decoder", "weezl", ] [[package]] name = "unicode-ident" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "weezl" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "zune-inflate" version = "0.2.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589245df6230839c305984dcc0a8385cc72af1fd223f360ffd5d65efa4216d40" dependencies = [ "simd-adler32", ] qrencode-0.14.0/Cargo.toml0000644000000024750000000000100107240ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "qrencode" version = "0.14.0" authors = [ "kennytm ", "Arijit Basu ", ] exclude = [ ".travis.yml", ".gitignore", "test-data/**", ] description = "QR code encoder in Rust" documentation = "http://docs.rs/qrencode" readme = "README.md" keywords = ["qrcode"] license = "MIT OR Apache-2.0" repository = "https://github.com/sayanarijit/qrencode" [[bin]] name = "qrencode" [[example]] name = "encode_image" required-features = ["image"] [[example]] name = "encode_string" [[example]] name = "encode_svg" required-features = ["svg"] [dependencies.checked_int_cast] version = "1.0.0" [dependencies.image] version = "0.24.5" optional = true default-features = false [dev-dependencies.image] version = "0.24.5" [features] bench = [] default = [ "image", "svg", ] svg = [] qrencode-0.14.0/Cargo.toml.orig000064400000000000000000000014631046102023000144010ustar 00000000000000[package] name = "qrencode" description = "QR code encoder in Rust" license = "MIT OR Apache-2.0" version = "0.14.0" edition = "2021" authors = ["kennytm ", "Arijit Basu "] keywords = ["qrcode"] repository = "https://github.com/sayanarijit/qrencode" readme = "README.md" documentation = "http://docs.rs/qrencode" exclude = [ ".travis.yml", ".gitignore", "test-data/**" ] [dependencies] image = { version = "0.24.5", default-features = false, optional = true } checked_int_cast = "1.0.0" [dev-dependencies] image = "0.24.5" [features] default = ["image", "svg"] bench = [] svg = [] [[bin]] name = "qrencode" [[example]] name = "encode_image" required-features = ["image"] [[example]] name = "encode_string" [[example]] name = "encode_svg" required-features = ["svg"] qrencode-0.14.0/LICENSE-APACHE.txt000064400000000000000000000261361046102023000142600ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. qrencode-0.14.0/LICENSE-MIT.txt000064400000000000000000000020631046102023000137610ustar 00000000000000Copyright (c) 2016-2023 kennytm, 2023 Arijit Basu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. qrencode-0.14.0/README.md000064400000000000000000000103261046102023000127670ustar 00000000000000# qrencode A fork of [qm3ster/qrcode-rust](https://github.com/qm3ster/qrcode-rust), which is a fork of [kennytm/qrcode-rust](https://github.com/kennytm/qrcode-rust). Since the original crate has stopped being maintained, and two of my projects depend on it, I'll be maintaining this fork until the original author returns. Any help from the community is appreciated. ## Cargo.toml ```toml [dependencies] qrencode = "*" ``` The default settings will depend on the `image` crate. If you don't need image generation capability, disable the `default-features`: ```toml [dependencies] qrencode = { version = "*", default-features = false } ``` ## Example ## Image generation ```rust use qrencode::QrCode; use image::Luma; fn main() { // Encode some data into bits. let code = QrCode::new(b"01234567").unwrap(); // Render the bits into an image. let image = code.render::>().build(); // Save the image. image.save("/tmp/qrcode.png").unwrap(); } ``` Generates this image: ![Output](src/test_annex_i_qr_as_image.png) ## String generation ```rust use qrencode::QrCode; fn main() { let code = QrCode::new(b"Hello").unwrap(); let string = code.render::() .quiet_zone(false) .module_dimensions(2, 1) .build(); println!("{}", string); } ``` Generates this output: ```none ############## ######## ############## ## ## ## ## ## ## ###### ## ## ## ## ## ###### ## ## ###### ## ## ## ## ###### ## ## ###### ## #### ## ## ###### ## ## ## #### ## ## ## ############## ## ## ## ############## ## ## ## ########## ## ## ########## ## ## ######## #### ## ########## #### ## #### ###### ## ## #### ########## #### ###### ########## ## ## ## ## ## ## ## ############## ## ## ## ## #### ## ## ## ## ########## ## ###### ## ## ## ## ## ## ## ###### ## #### ########## ## ## ###### ## #### ## #### ## ## ## ## ######## ###### ############## #### ## ## ## ``` ## SVG generation ```rust use qrencode::{QrCode, Version, EcLevel}; use qrencode::render::svg; fn main() { let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); let image = code.render() .min_dimensions(200, 200) .dark_color(svg::Color("#800000")) .light_color(svg::Color("#ffff80")) .build(); println!("{}", image); } ``` Generates this SVG: [![Output](src/test_annex_i_micro_qr_as_svg.svg)](src/test_annex_i_micro_qr_as_svg.svg) ## Unicode string generation ```rust use qrencode::QrCode; use qrencode::render::unicode; fn main() { let code = QrCode::new("mow mow").unwrap(); let image = code.render::() .dark_color(unicode::Dense1x2::Light) .light_color(unicode::Dense1x2::Dark) .build(); println!("{}", image); } ``` Generates this output: ```text █████████████████████████████ █████████████████████████████ ████ ▄▄▄▄▄ █ ▀▀▀▄█ ▄▄▄▄▄ ████ ████ █ █ █▀ ▀ ▀█ █ █ ████ ████ █▄▄▄█ ██▄ ▀█ █▄▄▄█ ████ ████▄▄▄▄▄▄▄█ ▀▄▀ █▄▄▄▄▄▄▄████ ████▄▀ ▄▀ ▄ █▄█ ▀ ▀█ █▄ ████ ████▄██▄▄▀▄▄▀█▄ ██▀▀█▀▄▄▄████ █████▄▄▄█▄▄█ ▀▀▄█▀▀▀▄█▄▄████ ████ ▄▄▄▄▄ █ ▄▄██▄ ▄ ▀▀████ ████ █ █ █▀▄▄▀▄▄ ▄▄▄▄ ▄████ ████ █▄▄▄█ █▄ █▄▀▄▀██▄█▀████ ████▄▄▄▄▄▄▄█▄████▄█▄██▄██████ █████████████████████████████ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ``` qrencode-0.14.0/examples/encode_image.rs000064400000000000000000000004511046102023000162710ustar 00000000000000use image::Luma; use qrencode::QrCode; fn main() { // Encode some data into bits. let code = QrCode::new(b"01234567").unwrap(); // Render the bits into an image. let image = code.render::>().build(); // Save the image. image.save("/tmp/qrcode.png").unwrap(); } qrencode-0.14.0/examples/encode_string.rs000064400000000000000000000003121046102023000165110ustar 00000000000000use qrencode::QrCode; fn main() { let code = QrCode::new(b"Hello").unwrap(); let string = code.render::().quiet_zone(false).module_dimensions(2, 1).build(); println!("{}", string); } qrencode-0.14.0/examples/encode_svg.rs000064400000000000000000000005731046102023000160130ustar 00000000000000use qrencode::render::svg; use qrencode::{EcLevel, QrCode, Version}; fn main() { let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); let image = code .render() .min_dimensions(200, 200) .dark_color(svg::Color("#800000")) .light_color(svg::Color("#ffff80")) .build(); println!("{}", image); } qrencode-0.14.0/rustfmt.toml000064400000000000000000000001151046102023000141040ustar 00000000000000max_width = 120 use_small_heuristics = "Max" use_field_init_shorthand = true qrencode-0.14.0/src/bin/qrencode.rs000064400000000000000000000010141046102023000152070ustar 00000000000000use std::env; use std::io::Read; pub fn main() { let bytes = if let Some(arg) = env::args().nth(1) { arg.as_bytes().to_vec() } else { let stdin = std::io::stdin(); let mut stdin = stdin.lock(); let mut bytes = Vec::new(); stdin.read_to_end(&mut bytes).expect("Failed to read from stdin"); bytes }; let code = qrencode::QrCode::new(bytes).unwrap(); println!("{}", code.render().dark_color("\x1b[7m \x1b[0m").light_color("\x1b[49m \x1b[0m").build()); } qrencode-0.14.0/src/bits.rs000064400000000000000000000776641046102023000136300ustar 00000000000000#![allow(clippy::unreadable_literal, clippy::unusual_byte_groupings)] //! The `bits` module encodes binary data into raw bits used in a QR code. use std::cmp::min; #[cfg(feature = "bench")] extern crate test; use crate::cast::{As, Truncate}; use crate::optimize::{total_encoded_len, Optimizer, Parser, Segment}; use crate::types::{EcLevel, Mode, QrError, QrResult, Version}; //------------------------------------------------------------------------------ //{{{ Bits /// The `Bits` structure stores the encoded data for a QR code. pub struct Bits { data: Vec, bit_offset: usize, version: Version, } impl Bits { /// Constructs a new, empty bits structure. pub fn new(version: Version) -> Self { Self { data: Vec::new(), bit_offset: 0, version } } /// Pushes an N-bit big-endian integer to the end of the bits. /// /// Note: It is up to the developer to ensure that `number` really only is /// `n` bit in size. Otherwise the excess bits may stomp on the existing /// ones. fn push_number(&mut self, n: usize, number: u16) { debug_assert!(n == 16 || n < 16 && number < (1 << n), "{} is too big as a {}-bit number", number, n); let b = self.bit_offset + n; let last_index = self.data.len().wrapping_sub(1); match (self.bit_offset, b) { (0, 0..=8) => { self.data.push((number << (8 - b)).truncate_as_u8()); } (0, _) => { self.data.push((number >> (b - 8)).truncate_as_u8()); self.data.push((number << (16 - b)).truncate_as_u8()); } (_, 0..=8) => { self.data[last_index] |= (number << (8 - b)).truncate_as_u8(); } (_, 9..=16) => { self.data[last_index] |= (number >> (b - 8)).truncate_as_u8(); self.data.push((number << (16 - b)).truncate_as_u8()); } _ => { self.data[last_index] |= (number >> (b - 8)).truncate_as_u8(); self.data.push((number >> (b - 16)).truncate_as_u8()); self.data.push((number << (24 - b)).truncate_as_u8()); } } self.bit_offset = b & 7; } /// Pushes an N-bit big-endian integer to the end of the bits, and check /// that the number does not overflow the bits. /// /// Returns `Err(QrError::DataTooLong)` on overflow. fn push_number_checked(&mut self, n: usize, number: usize) -> QrResult<()> { if n > 16 || number >= (1 << n) { Err(QrError::DataTooLong) } else { self.push_number(n, number.as_u16()); Ok(()) } } /// Reserves `n` extra bits of space for pushing. fn reserve(&mut self, n: usize) { let extra_bytes = (n + (8 - self.bit_offset) % 8) / 8; self.data.reserve(extra_bytes); } /// Convert the bits into a bytes vector. pub fn into_bytes(self) -> Vec { self.data } /// Total number of bits currently pushed. pub fn len(&self) -> usize { if self.bit_offset == 0 { self.data.len() * 8 } else { (self.data.len() - 1) * 8 + self.bit_offset } } /// Whether there are any bits pushed. pub fn is_empty(&self) -> bool { self.data.is_empty() } /// The maximum number of bits allowed by the provided QR code version and /// error correction level. /// /// # Errors /// /// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the /// `ec_level` for the given version (e.g. `Version::Micro(1)` with /// `EcLevel::H`). pub fn max_len(&self, ec_level: EcLevel) -> QrResult { self.version.fetch(ec_level, &DATA_LENGTHS) } /// Version of the QR code. pub fn version(&self) -> Version { self.version } } #[test] fn test_push_number() { let mut bits = Bits::new(Version::Normal(1)); bits.push_number(3, 0b010); // 0:0 .. 0:3 bits.push_number(3, 0b110); // 0:3 .. 0:6 bits.push_number(3, 0b101); // 0:6 .. 1:1 bits.push_number(7, 0b001_1010); // 1:1 .. 2:0 bits.push_number(4, 0b1100); // 2:0 .. 2:4 bits.push_number(12, 0b1011_0110_1101); // 2:4 .. 4:0 bits.push_number(10, 0b01_1001_0001); // 4:0 .. 5:2 bits.push_number(15, 0b111_0010_1110_0011); // 5:2 .. 7:1 let bytes = bits.into_bytes(); assert_eq!( bytes, vec![ 0b010_110_10, // 90 0b1_001_1010, // 154 0b1100_1011, // 203 0b0110_1101, // 109 0b01_1001_00, // 100 0b01_111_001, // 121 0b0_1110_001, // 113 0b1_0000000, // 128 ] ); } #[cfg(feature = "bench")] #[bench] fn bench_push_splitted_bytes(bencher: &mut test::Bencher) { bencher.iter(|| { let mut bits = Bits::new(Version::Normal(40)); bits.push_number(4, 0b0101); for _ in 0..1024 { bits.push_number(8, 0b10101010); } bits.into_bytes() }); } //}}} //------------------------------------------------------------------------------ //{{{ Mode indicator /// An "extended" mode indicator, includes all indicators supported by QR code /// beyond those bearing data. #[derive(Copy, Clone)] pub enum ExtendedMode { /// ECI mode indicator, to introduce an ECI designator. Eci, /// The normal mode to introduce data. Data(Mode), /// FNC-1 mode in the first position. Fnc1First, /// FNC-1 mode in the second position. Fnc1Second, /// Structured append. StructuredAppend, } impl Bits { /// Push the mode indicator to the end of the bits. /// /// # Errors /// /// If the mode is not supported in the provided version, this method /// returns `Err(QrError::UnsupportedCharacterSet)`. pub fn push_mode_indicator(&mut self, mode: ExtendedMode) -> QrResult<()> { #[allow(clippy::match_same_arms)] let number = match (self.version, mode) { (Version::Micro(1), ExtendedMode::Data(Mode::Numeric)) => return Ok(()), (Version::Micro(_), ExtendedMode::Data(Mode::Numeric)) => 0, (Version::Micro(_), ExtendedMode::Data(Mode::Alphanumeric)) => 1, (Version::Micro(_), ExtendedMode::Data(Mode::Byte)) => 0b10, (Version::Micro(_), ExtendedMode::Data(Mode::Kanji)) => 0b11, (Version::Micro(_), _) => return Err(QrError::UnsupportedCharacterSet), (_, ExtendedMode::Data(Mode::Numeric)) => 0b0001, (_, ExtendedMode::Data(Mode::Alphanumeric)) => 0b0010, (_, ExtendedMode::Data(Mode::Byte)) => 0b0100, (_, ExtendedMode::Data(Mode::Kanji)) => 0b1000, (_, ExtendedMode::Eci) => 0b0111, (_, ExtendedMode::Fnc1First) => 0b0101, (_, ExtendedMode::Fnc1Second) => 0b1001, (_, ExtendedMode::StructuredAppend) => 0b0011, }; let bits = self.version.mode_bits_count(); self.push_number_checked(bits, number).or(Err(QrError::UnsupportedCharacterSet)) } } //}}} //------------------------------------------------------------------------------ //{{{ ECI impl Bits { /// Push an ECI (Extended Channel Interpretation) designator to the bits. /// /// An ECI designator is a 6-digit number to specify the character set of /// the following binary data. After calling this method, one could call /// `.push_byte_data()` or similar methods to insert the actual data, e.g. /// /// #![allow(unused_must_use)] /// /// use qrencode::bits::Bits; /// use qrencode::types::Version; /// /// let mut bits = Bits::new(Version::Normal(1)); /// bits.push_eci_designator(9); // 9 = ISO-8859-7 (Greek). /// bits.push_byte_data(b"\xa1\xa2\xa3\xa4\xa5"); // ΑΒΓΔΕ /// /// /// The full list of ECI designator values can be found from /// . Some example values are: /// /// ECI # | Character set /// ------|------------------------------------- /// 3 | ISO-8859-1 (Western European) /// 20 | Shift JIS (Japanese) /// 23 | Windows 1252 (Latin 1) (Western European) /// 25 | UTF-16 Big Endian /// 26 | UTF-8 /// 28 | Big 5 (Traditional Chinese) /// 29 | GB-18030 (Simplified Chinese) /// 30 | EUC-KR (Korean) /// /// # Errors /// /// If the QR code version does not support ECI, this method will return /// `Err(QrError::UnsupportedCharacterSet)`. /// /// If the designator is outside of the expected range, this method will /// return `Err(QrError::InvalidECIDesignator)`. pub fn push_eci_designator(&mut self, eci_designator: u32) -> QrResult<()> { self.reserve(12); // assume the common case that eci_designator <= 127. self.push_mode_indicator(ExtendedMode::Eci)?; match eci_designator { 0..=127 => { self.push_number(8, eci_designator.as_u16()); } 128..=16383 => { self.push_number(2, 0b10); self.push_number(14, eci_designator.as_u16()); } 16384..=999_999 => { self.push_number(3, 0b110); self.push_number(5, (eci_designator >> 16).as_u16()); self.push_number(16, (eci_designator & 0xffff).as_u16()); } _ => return Err(QrError::InvalidEciDesignator), } Ok(()) } } #[cfg(test)] mod eci_tests { use crate::bits::Bits; use crate::types::{QrError, Version}; #[test] fn test_9() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_eci_designator(9), Ok(())); assert_eq!(bits.into_bytes(), vec![0b0111_0000, 0b1001_0000]); } #[test] fn test_899() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_eci_designator(899), Ok(())); assert_eq!(bits.into_bytes(), vec![0b0111_10_00, 0b00111000, 0b0011_0000]); } #[test] fn test_999999() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_eci_designator(999999), Ok(())); assert_eq!(bits.into_bytes(), vec![0b0111_110_0, 0b11110100, 0b00100011, 0b1111_0000]); } #[test] fn test_invalid_designator() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_eci_designator(1000000), Err(QrError::InvalidEciDesignator)); } #[test] fn test_unsupported_character_set() { let mut bits = Bits::new(Version::Micro(4)); assert_eq!(bits.push_eci_designator(9), Err(QrError::UnsupportedCharacterSet)); } } //}}} //------------------------------------------------------------------------------ //{{{ Mode::Numeric mode impl Bits { fn push_header(&mut self, mode: Mode, raw_data_len: usize) -> QrResult<()> { let length_bits = mode.length_bits_count(self.version); self.reserve(length_bits + 4 + mode.data_bits_count(raw_data_len)); self.push_mode_indicator(ExtendedMode::Data(mode))?; self.push_number_checked(length_bits, raw_data_len)?; Ok(()) } /// Encodes a numeric string to the bits. /// /// The data should only contain the characters 0 to 9. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> { self.push_header(Mode::Numeric, data.len())?; for chunk in data.chunks(3) { let number = chunk.iter().map(|b| u16::from(*b - b'0')).fold(0, |a, b| a * 10 + b); let length = chunk.len() * 3 + 1; self.push_number(length, number); } Ok(()) } } #[cfg(test)] mod numeric_tests { use crate::bits::Bits; use crate::types::{QrError, Version}; #[test] fn test_iso_18004_2006_example_1() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_numeric_data(b"01234567"), Ok(())); assert_eq!(bits.into_bytes(), vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b01_100001, 0b1_0000000]); } #[test] fn test_iso_18004_2000_example_2() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); assert_eq!( bits.into_bytes(), vec![ 0b0001_0000, 0b010000_00, 0b00001100, 0b01010110, 0b01_101010, 0b0110_1110, 0b000101_00, 0b11101010, 0b0101_0000, ] ); } #[test] fn test_iso_18004_2006_example_2() { let mut bits = Bits::new(Version::Micro(3)); assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); assert_eq!( bits.into_bytes(), vec![0b00_10000_0, 0b00000110, 0b0_0101011, 0b001_10101, 0b00110_111, 0b0000101_0, 0b01110101, 0b00101_000,] ); } #[test] fn test_data_too_long_error() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_numeric_data(b"12345678"), Err(QrError::DataTooLong)); } } //}}} //------------------------------------------------------------------------------ //{{{ Mode::Alphanumeric mode /// In QR code `Mode::Alphanumeric` mode, a pair of alphanumeric characters will /// be encoded as a base-45 integer. `alphanumeric_digit` converts each /// character into its corresponding base-45 digit. /// /// The conversion is specified in ISO/IEC 18004:2006, §8.4.3, Table 5. #[inline] fn alphanumeric_digit(character: u8) -> u16 { match character { b'0'..=b'9' => u16::from(character - b'0'), b'A'..=b'Z' => u16::from(character - b'A') + 10, b' ' => 36, b'$' => 37, b'%' => 38, b'*' => 39, b'+' => 40, b'-' => 41, b'.' => 42, b'/' => 43, b':' => 44, _ => 0, } } impl Bits { /// Encodes an alphanumeric string to the bits. /// /// The data should only contain the charaters A to Z (excluding lowercase), /// 0 to 9, space, `$`, `%`, `*`, `+`, `-`, `.`, `/` or `:`. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> { self.push_header(Mode::Alphanumeric, data.len())?; for chunk in data.chunks(2) { let number = chunk.iter().map(|b| alphanumeric_digit(*b)).fold(0, |a, b| a * 45 + b); let length = chunk.len() * 5 + 1; self.push_number(length, number); } Ok(()) } } #[cfg(test)] mod alphanumeric_tests { use crate::bits::Bits; use crate::types::{QrError, Version}; #[test] fn test_iso_18004_2006_example() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(())); assert_eq!(bits.into_bytes(), vec![0b0010_0000, 0b00101_001, 0b11001110, 0b11100111, 0b001_00001, 0b0_0000000]); } #[test] fn test_micro_qr_unsupported() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_alphanumeric_data(b"A"), Err(QrError::UnsupportedCharacterSet)); } #[test] fn test_data_too_long() { let mut bits = Bits::new(Version::Micro(2)); assert_eq!(bits.push_alphanumeric_data(b"ABCDEFGH"), Err(QrError::DataTooLong)); } } //}}} //------------------------------------------------------------------------------ //{{{ Mode::Byte mode impl Bits { /// Encodes 8-bit byte data to the bits. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. pub fn push_byte_data(&mut self, data: &[u8]) -> QrResult<()> { self.push_header(Mode::Byte, data.len())?; for b in data { self.push_number(8, u16::from(*b)); } Ok(()) } } #[cfg(test)] mod byte_tests { use crate::bits::Bits; use crate::types::{QrError, Version}; #[test] fn test() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_byte_data(b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"), Ok(())); assert_eq!( bits.into_bytes(), vec![ 0b0100_0000, 0b1000_0001, 0b0010_0011, 0b0100_0101, 0b0110_0111, 0b1000_1001, 0b1010_1011, 0b1100_1101, 0b1110_1111, 0b0000_0000, ] ); } #[test] fn test_micro_qr_unsupported() { let mut bits = Bits::new(Version::Micro(2)); assert_eq!(bits.push_byte_data(b"?"), Err(QrError::UnsupportedCharacterSet)); } #[test] fn test_data_too_long() { let mut bits = Bits::new(Version::Micro(3)); assert_eq!(bits.push_byte_data(b"0123456701234567"), Err(QrError::DataTooLong)); } } //}}} //------------------------------------------------------------------------------ //{{{ Mode::Kanji mode impl Bits { /// Encodes Shift JIS double-byte data to the bits. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. /// /// Returns `Err(QrError::InvalidCharacter)` if the data is not Shift JIS /// double-byte data (e.g. if the length of data is not an even number). pub fn push_kanji_data(&mut self, data: &[u8]) -> QrResult<()> { self.push_header(Mode::Kanji, data.len() / 2)?; for kanji in data.chunks(2) { if kanji.len() != 2 { return Err(QrError::InvalidCharacter); } let cp = u16::from(kanji[0]) * 256 + u16::from(kanji[1]); let bytes = if cp < 0xe040 { cp - 0x8140 } else { cp - 0xc140 }; let number = (bytes >> 8) * 0xc0 + (bytes & 0xff); self.push_number(13, number); } Ok(()) } } #[cfg(test)] mod kanji_tests { use crate::bits::Bits; use crate::types::{QrError, Version}; #[test] fn test_iso_18004_example() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_kanji_data(b"\x93\x5f\xe4\xaa"), Ok(())); assert_eq!(bits.into_bytes(), vec![0b1000_0000, 0b0010_0110, 0b11001111, 0b1_1101010, 0b101010_00]); } #[test] fn test_micro_qr_unsupported() { let mut bits = Bits::new(Version::Micro(2)); assert_eq!(bits.push_kanji_data(b"?"), Err(QrError::UnsupportedCharacterSet)); } #[test] fn test_data_too_long() { let mut bits = Bits::new(Version::Micro(3)); assert_eq!(bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"), Err(QrError::DataTooLong)); } } //}}} //------------------------------------------------------------------------------ //{{{ FNC1 mode impl Bits { /// Encodes an indicator that the following data are formatted according to /// the UCC/EAN Application Identifiers standard. /// /// #![allow(unused_must_use)] /// /// use qrencode::bits::Bits; /// use qrencode::types::Version; /// /// let mut bits = Bits::new(Version::Normal(1)); /// bits.push_fnc1_first_position(); /// bits.push_numeric_data(b"01049123451234591597033130128"); /// bits.push_alphanumeric_data(b"%10ABC123"); /// /// In QR code, the character `%` is used as the data field separator (0x1D). /// /// # Errors /// /// If the mode is not supported in the provided version, this method /// returns `Err(QrError::UnsupportedCharacterSet)`. pub fn push_fnc1_first_position(&mut self) -> QrResult<()> { self.push_mode_indicator(ExtendedMode::Fnc1First) } /// Encodes an indicator that the following data are formatted in accordance /// with specific industry or application specifications previously agreed /// with AIM International. /// /// #![allow(unused_must_use)] /// /// use qrencode::bits::Bits; /// use qrencode::types::Version; /// /// let mut bits = Bits::new(Version::Normal(1)); /// bits.push_fnc1_second_position(37); /// bits.push_alphanumeric_data(b"AA1234BBB112"); /// bits.push_byte_data(b"text text text text\r"); /// /// If the application indicator is a single Latin alphabet (a–z / A–Z), /// please pass in its ASCII value + 100: /// /// ```ignore /// bits.push_fnc1_second_position(b'A' + 100); /// ``` /// /// # Errors /// /// If the mode is not supported in the provided version, this method /// returns `Err(QrError::UnsupportedCharacterSet)`. pub fn push_fnc1_second_position(&mut self, application_indicator: u8) -> QrResult<()> { self.push_mode_indicator(ExtendedMode::Fnc1Second)?; self.push_number(8, u16::from(application_indicator)); Ok(()) } } //}}} //------------------------------------------------------------------------------ //{{{ Finish // This table is copied from ISO/IEC 18004:2006 §6.4.10, Table 7. static DATA_LENGTHS: [[usize; 4]; 44] = [ // Normal versions [152, 128, 104, 72], [272, 224, 176, 128], [440, 352, 272, 208], [640, 512, 384, 288], [864, 688, 496, 368], [1088, 864, 608, 480], [1248, 992, 704, 528], [1552, 1232, 880, 688], [1856, 1456, 1056, 800], [2192, 1728, 1232, 976], [2592, 2032, 1440, 1120], [2960, 2320, 1648, 1264], [3424, 2672, 1952, 1440], [3688, 2920, 2088, 1576], [4184, 3320, 2360, 1784], [4712, 3624, 2600, 2024], [5176, 4056, 2936, 2264], [5768, 4504, 3176, 2504], [6360, 5016, 3560, 2728], [6888, 5352, 3880, 3080], [7456, 5712, 4096, 3248], [8048, 6256, 4544, 3536], [8752, 6880, 4912, 3712], [9392, 7312, 5312, 4112], [10208, 8000, 5744, 4304], [10960, 8496, 6032, 4768], [11744, 9024, 6464, 5024], [12248, 9544, 6968, 5288], [13048, 10136, 7288, 5608], [13880, 10984, 7880, 5960], [14744, 11640, 8264, 6344], [15640, 12328, 8920, 6760], [16568, 13048, 9368, 7208], [17528, 13800, 9848, 7688], [18448, 14496, 10288, 7888], [19472, 15312, 10832, 8432], [20528, 15936, 11408, 8768], [21616, 16816, 12016, 9136], [22496, 17728, 12656, 9776], [23648, 18672, 13328, 10208], // Micro versions [20, 0, 0, 0], [40, 32, 0, 0], [84, 68, 0, 0], [128, 112, 80, 0], ]; impl Bits { /// Pushes the ending bits to indicate no more data. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. /// /// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the /// `ec_level` for the given version (e.g. `Version::Micro(1)` with /// `EcLevel::H`). pub fn push_terminator(&mut self, ec_level: EcLevel) -> QrResult<()> { let terminator_size = match self.version { Version::Micro(a) => a.as_usize() * 2 + 1, Version::Normal(_) => 4, }; let cur_length = self.len(); let data_length = self.max_len(ec_level)?; if cur_length > data_length { return Err(QrError::DataTooLong); } let terminator_size = min(terminator_size, data_length - cur_length); if terminator_size > 0 { self.push_number(terminator_size, 0); } if self.len() < data_length { const PADDING_BYTES: &[u8] = &[0b1110_1100, 0b0001_0001]; self.bit_offset = 0; let data_bytes_length = data_length / 8; let padding_bytes_count = data_bytes_length - self.data.len(); let padding = PADDING_BYTES.iter().copied().cycle().take(padding_bytes_count); self.data.extend(padding); } if self.len() < data_length { self.data.push(0); } Ok(()) } } #[cfg(test)] mod finish_tests { use crate::bits::Bits; use crate::types::{EcLevel, QrError, Version}; #[test] fn test_hello_world() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_alphanumeric_data(b"HELLO WORLD"), Ok(())); assert_eq!(bits.push_terminator(EcLevel::Q), Ok(())); assert_eq!( bits.into_bytes(), vec![ 0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101, 0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100, ] ); } #[test] fn test_too_long() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_numeric_data(b"9999999"), Ok(())); assert_eq!(bits.push_terminator(EcLevel::L), Err(QrError::DataTooLong)); } #[test] fn test_no_terminator() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_numeric_data(b"99999"), Ok(())); assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); assert_eq!(bits.into_bytes(), vec![0b101_11111, 0b00111_110, 0b0011_0000]); } #[test] fn test_no_padding() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_numeric_data(b"9999"), Ok(())); assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); assert_eq!(bits.into_bytes(), vec![0b100_11111, 0b00111_100, 0b1_000_0000]); } #[test] fn test_micro_version_1_half_byte_padding() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_numeric_data(b"999"), Ok(())); assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); assert_eq!(bits.into_bytes(), vec![0b011_11111, 0b00111_000, 0b0000_0000]); } #[test] fn test_micro_version_1_full_byte_padding() { let mut bits = Bits::new(Version::Micro(1)); assert_eq!(bits.push_numeric_data(b""), Ok(())); assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); assert_eq!(bits.into_bytes(), vec![0b000_000_00, 0b11101100, 0]); } } //}}} //------------------------------------------------------------------------------ //{{{ Front end. impl Bits { /// Push a segmented data to the bits, and then terminate it. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. /// /// Returns `Err(QrError::InvalidData)` if the segment refers to incorrectly /// encoded byte sequence. pub fn push_segments(&mut self, data: &[u8], segments_iter: I) -> QrResult<()> where I: Iterator, { for segment in segments_iter { let slice = &data[segment.begin..segment.end]; match segment.mode { Mode::Numeric => self.push_numeric_data(slice), Mode::Alphanumeric => self.push_alphanumeric_data(slice), Mode::Byte => self.push_byte_data(slice), Mode::Kanji => self.push_kanji_data(slice), }?; } Ok(()) } /// Pushes the data the bits, using the optimal encoding. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` on overflow. pub fn push_optimal_data(&mut self, data: &[u8]) -> QrResult<()> { let segments = Parser::new(data).optimize(self.version); self.push_segments(data, segments) } } #[cfg(test)] mod encode_tests { use crate::bits::Bits; use crate::types::{EcLevel, QrError, QrResult, Version}; fn encode(data: &[u8], version: Version, ec_level: EcLevel) -> QrResult> { let mut bits = Bits::new(version); bits.push_optimal_data(data)?; bits.push_terminator(ec_level)?; Ok(bits.into_bytes()) } #[test] fn test_alphanumeric() { let res = encode(b"HELLO WORLD", Version::Normal(1), EcLevel::Q); assert_eq!( res, Ok(vec![ 0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101, 0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100, ]) ); } #[test] fn test_auto_mode_switch() { let res = encode(b"123A", Version::Micro(2), EcLevel::L); assert_eq!(res, Ok(vec![0b0_0011_000, 0b1111011_1, 0b001_00101, 0b0_00000_00, 0b11101100])); } #[test] fn test_too_long() { let res = encode(b">>>>>>>>", Version::Normal(1), EcLevel::H); assert_eq!(res, Err(QrError::DataTooLong)); } } //}}} //------------------------------------------------------------------------------ //{{{ Auto version minimization /// Automatically determines the minimum version to store the data, and encode /// the result. /// /// This method will not consider any Micro QR code versions. /// /// # Errors /// /// Returns `Err(QrError::DataTooLong)` if the data is too long to fit even the /// highest QR code version. pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult { let segments = Parser::new(data).collect::>(); for version in &[Version::Normal(9), Version::Normal(26), Version::Normal(40)] { let opt_segments = Optimizer::new(segments.iter().copied(), *version).collect::>(); let total_len = total_encoded_len(&*opt_segments, *version); let data_capacity = version.fetch(ec_level, &DATA_LENGTHS).expect("invalid DATA_LENGTHS"); if total_len <= data_capacity { let min_version = find_min_version(total_len, ec_level); let mut bits = Bits::new(min_version); bits.reserve(total_len); bits.push_segments(data, opt_segments.into_iter())?; bits.push_terminator(ec_level)?; return Ok(bits); } } Err(QrError::DataTooLong) } /// Finds the smallest version (QR code only) that can store N bits of data /// in the given error correction level. fn find_min_version(length: usize, ec_level: EcLevel) -> Version { let mut base = 0_usize; let mut size = 39; while size > 1 { let half = size / 2; let mid = base + half; // mid is always in [0, size). // mid >= 0: by definition // mid < size: mid = size / 2 + size / 4 + size / 8 ... base = if DATA_LENGTHS[mid][ec_level as usize] > length { base } else { mid }; size -= half; } // base is always in [0, mid) because base <= mid. base = if DATA_LENGTHS[base][ec_level as usize] >= length { base } else { base + 1 }; Version::Normal((base + 1).as_i16()) } #[cfg(test)] mod encode_auto_tests { use crate::bits::{encode_auto, find_min_version}; use crate::types::{EcLevel, Version}; #[test] fn test_find_min_version() { assert_eq!(find_min_version(60, EcLevel::L), Version::Normal(1)); assert_eq!(find_min_version(200, EcLevel::L), Version::Normal(2)); assert_eq!(find_min_version(200, EcLevel::H), Version::Normal(3)); assert_eq!(find_min_version(20000, EcLevel::L), Version::Normal(37)); assert_eq!(find_min_version(640, EcLevel::L), Version::Normal(4)); assert_eq!(find_min_version(641, EcLevel::L), Version::Normal(5)); assert_eq!(find_min_version(999999, EcLevel::H), Version::Normal(40)); } #[test] fn test_alpha_q() { let bits = encode_auto(b"HELLO WORLD", EcLevel::Q).unwrap(); assert_eq!(bits.version(), Version::Normal(1)); } #[test] fn test_alpha_h() { let bits = encode_auto(b"HELLO WORLD", EcLevel::H).unwrap(); assert_eq!(bits.version(), Version::Normal(2)); } #[test] fn test_mixed() { let bits = encode_auto(b"This is a mixed data test. 1234567890", EcLevel::H).unwrap(); assert_eq!(bits.version(), Version::Normal(4)); } } #[cfg(feature = "bench")] #[bench] fn bench_find_min_version(bencher: &mut test::Bencher) { use test::black_box; bencher.iter(|| { black_box(find_min_version(60, EcLevel::L)); black_box(find_min_version(200, EcLevel::L)); black_box(find_min_version(200, EcLevel::H)); black_box(find_min_version(20000, EcLevel::L)); black_box(find_min_version(640, EcLevel::L)); black_box(find_min_version(641, EcLevel::L)); black_box(find_min_version(999999, EcLevel::H)); }) } //}}} //------------------------------------------------------------------------------ qrencode-0.14.0/src/canvas.rs000064400000000000000000002126031046102023000141220ustar 00000000000000//! The `canvas` module puts raw bits into the QR code canvas. //! //! use qrencode::types::{Version, EcLevel}; //! use qrencode::canvas::{Canvas, MaskPattern}; //! //! let mut c = Canvas::new(Version::Normal(1), EcLevel::L); //! c.draw_all_functional_patterns(); //! c.draw_data(b"data_here", b"ec_code_here"); //! c.apply_mask(MaskPattern::Checkerboard); //! let bools = c.to_bools(); use std::cmp::max; use crate::cast::As; use crate::types::{Color, EcLevel, Version}; //------------------------------------------------------------------------------ //{{{ Modules /// The color of a module (pixel) in the QR code. #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Module { /// The module is empty. Empty, /// The module is of functional patterns which cannot be masked, or pixels /// which have been masked. Masked(Color), /// The module is of data and error correction bits before masking. Unmasked(Color), } impl From for Color { fn from(module: Module) -> Self { match module { Module::Empty => Color::Light, Module::Masked(c) | Module::Unmasked(c) => c, } } } impl Module { /// Checks whether a module is dark. pub fn is_dark(self) -> bool { Color::from(self) == Color::Dark } /// Apply a mask to the unmasked modules. /// /// use qrencode::canvas::Module; /// use qrencode::types::Color; /// /// assert_eq!(Module::Unmasked(Color::Light).mask(true), Module::Masked(Color::Dark)); /// assert_eq!(Module::Unmasked(Color::Dark).mask(true), Module::Masked(Color::Light)); /// assert_eq!(Module::Unmasked(Color::Light).mask(false), Module::Masked(Color::Light)); /// assert_eq!(Module::Masked(Color::Dark).mask(true), Module::Masked(Color::Dark)); /// assert_eq!(Module::Masked(Color::Dark).mask(false), Module::Masked(Color::Dark)); /// #[must_use] pub fn mask(self, should_invert: bool) -> Self { match (self, should_invert) { (Module::Empty, true) => Module::Masked(Color::Dark), (Module::Empty, false) => Module::Masked(Color::Light), (Module::Unmasked(c), true) => Module::Masked(!c), (Module::Unmasked(c), false) | (Module::Masked(c), _) => Module::Masked(c), } } } //}}} //------------------------------------------------------------------------------ //{{{ Canvas /// `Canvas` is an intermediate helper structure to render error-corrected data /// into a QR code. #[derive(Clone)] pub struct Canvas { /// The width and height of the canvas (cached as it is needed frequently). width: i16, /// The version of the QR code. version: Version, /// The error correction level of the QR code. ec_level: EcLevel, /// The modules of the QR code. Modules are arranged in left-to-right, then /// top-to-bottom order. modules: Vec, } impl Canvas { /// Constructs a new canvas big enough for a QR code of the given version. pub fn new(version: Version, ec_level: EcLevel) -> Self { let width = version.width(); Self { width, version, ec_level, modules: vec![Module::Empty; (width * width).as_usize()] } } /// Converts the canvas into a human-readable string. #[cfg(test)] fn to_debug_str(&self) -> String { let width = self.width; let mut res = String::with_capacity((width * (width + 1)).as_usize()); for y in 0..width { res.push('\n'); for x in 0..width { res.push(match self.get(x, y) { Module::Empty => '?', Module::Masked(Color::Light) => '.', Module::Masked(Color::Dark) => '#', Module::Unmasked(Color::Light) => '-', Module::Unmasked(Color::Dark) => '*', }); } } res } fn coords_to_index(&self, x: i16, y: i16) -> usize { let x = if x < 0 { x + self.width } else { x }.as_usize(); let y = if y < 0 { y + self.width } else { y }.as_usize(); y * self.width.as_usize() + x } /// Obtains a module at the given coordinates. For convenience, negative /// coordinates will wrap around. pub fn get(&self, x: i16, y: i16) -> Module { self.modules[self.coords_to_index(x, y)] } /// Obtains a mutable module at the given coordinates. For convenience, /// negative coordinates will wrap around. pub fn get_mut(&mut self, x: i16, y: i16) -> &mut Module { let index = self.coords_to_index(x, y); &mut self.modules[index] } /// Sets the color of a functional module at the given coordinates. For /// convenience, negative coordinates will wrap around. pub fn put(&mut self, x: i16, y: i16, color: Color) { *self.get_mut(x, y) = Module::Masked(color); } } #[cfg(test)] mod basic_canvas_tests { use crate::canvas::{Canvas, Module}; use crate::types::{Color, EcLevel, Version}; #[test] fn test_index() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); assert_eq!(c.get(0, 4), Module::Empty); assert_eq!(c.get(-1, -7), Module::Empty); assert_eq!(c.get(21 - 1, 21 - 7), Module::Empty); c.put(0, 0, Color::Dark); c.put(-1, -7, Color::Light); assert_eq!(c.get(0, 0), Module::Masked(Color::Dark)); assert_eq!(c.get(21 - 1, -7), Module::Masked(Color::Light)); assert_eq!(c.get(-1, 21 - 7), Module::Masked(Color::Light)); } #[test] fn test_debug_str() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); for i in 3_i16..20 { for j in 3_i16..20 { *c.get_mut(i, j) = match ((i * 3) ^ j) % 5 { 0 => Module::Empty, 1 => Module::Masked(Color::Light), 2 => Module::Masked(Color::Dark), 3 => Module::Unmasked(Color::Light), 4 => Module::Unmasked(Color::Dark), _ => unreachable!(), }; } } assert_eq!( &*c.to_debug_str(), "\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????####****....---?\n\ ???--.##-..##?..#??.?\n\ ???#*?-.*?#.-*#?-*.??\n\ ?????*?*?****-*-*---?\n\ ???*.-.-.-?-?#?#?#*#?\n\ ???.*#.*.*#.*#*#.*#*?\n\ ?????.#-#--??.?.#---?\n\ ???-.?*.-#?-.?#*-#?.?\n\ ???##*??*..##*--*..??\n\ ?????-???--??---?---?\n\ ???*.#.*.#**.#*#.#*#?\n\ ???##.-##..##..?#..??\n\ ???.-?*.-?#.-?#*-?#*?\n\ ????-.#?-.**#?-.#?-.?\n\ ???**?-**??--**?-**??\n\ ???#?*?#?*#.*-.-*-.-?\n\ ???..-...--??###?###?\n\ ?????????????????????" ); } } //}}} //------------------------------------------------------------------------------ //{{{ Finder patterns impl Canvas { /// Draws a single finder pattern with the center at (x, y). fn draw_finder_pattern_at(&mut self, x: i16, y: i16) { let (dx_left, dx_right) = if x >= 0 { (-3, 4) } else { (-4, 3) }; let (dy_top, dy_bottom) = if y >= 0 { (-3, 4) } else { (-4, 3) }; for j in dy_top..=dy_bottom { for i in dx_left..=dx_right { self.put( x + i, y + j, #[allow(clippy::match_same_arms)] match (i, j) { (4 | -4, _) | (_, 4 | -4) => Color::Light, (3 | -3, _) | (_, 3 | -3) => Color::Dark, (2 | -2, _) | (_, 2 | -2) => Color::Light, _ => Color::Dark, }, ); } } } /// Draws the finder patterns. /// /// The finder patterns is are 7×7 square patterns appearing at the three /// corners of a QR code. They allows scanner to locate the QR code and /// determine the orientation. fn draw_finder_patterns(&mut self) { self.draw_finder_pattern_at(3, 3); match self.version { Version::Micro(_) => {} Version::Normal(_) => { self.draw_finder_pattern_at(-4, 3); self.draw_finder_pattern_at(3, -4); } } } } #[cfg(test)] mod finder_pattern_tests { use crate::canvas::Canvas; use crate::types::{EcLevel, Version}; #[test] fn test_qr() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_finder_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######.?????.#######\n\ #.....#.?????.#.....#\n\ #.###.#.?????.#.###.#\n\ #.###.#.?????.#.###.#\n\ #.###.#.?????.#.###.#\n\ #.....#.?????.#.....#\n\ #######.?????.#######\n\ ........?????........\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ........?????????????\n\ #######.?????????????\n\ #.....#.?????????????\n\ #.###.#.?????????????\n\ #.###.#.?????????????\n\ #.###.#.?????????????\n\ #.....#.?????????????\n\ #######.?????????????" ); } #[test] fn test_micro_qr() { let mut c = Canvas::new(Version::Micro(1), EcLevel::L); c.draw_finder_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######.???\n\ #.....#.???\n\ #.###.#.???\n\ #.###.#.???\n\ #.###.#.???\n\ #.....#.???\n\ #######.???\n\ ........???\n\ ???????????\n\ ???????????\n\ ???????????" ); } } //}}} //------------------------------------------------------------------------------ //{{{ Alignment patterns impl Canvas { /// Draws a alignment pattern with the center at (x, y). fn draw_alignment_pattern_at(&mut self, x: i16, y: i16) { if self.get(x, y) != Module::Empty { return; } for j in -2..=2 { for i in -2..=2 { self.put( x + i, y + j, match (i, j) { (2 | -2, _) | (_, 2 | -2) | (0, 0) => Color::Dark, _ => Color::Light, }, ); } } } /// Draws the alignment patterns. /// /// The alignment patterns are 5×5 square patterns inside the QR code symbol /// to help the scanner create the square grid. fn draw_alignment_patterns(&mut self) { match self.version { Version::Micro(_) | Version::Normal(1) => {} Version::Normal(2..=6) => self.draw_alignment_pattern_at(-7, -7), Version::Normal(a) => { let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()]; for x in positions.iter() { for y in positions.iter() { self.draw_alignment_pattern_at(*x, *y); } } } } } } #[cfg(test)] mod alignment_pattern_tests { use crate::canvas::Canvas; use crate::types::{EcLevel, Version}; #[test] fn test_draw_alignment_patterns_1() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_finder_patterns(); c.draw_alignment_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######.?????.#######\n\ #.....#.?????.#.....#\n\ #.###.#.?????.#.###.#\n\ #.###.#.?????.#.###.#\n\ #.###.#.?????.#.###.#\n\ #.....#.?????.#.....#\n\ #######.?????.#######\n\ ........?????........\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ........?????????????\n\ #######.?????????????\n\ #.....#.?????????????\n\ #.###.#.?????????????\n\ #.###.#.?????????????\n\ #.###.#.?????????????\n\ #.....#.?????????????\n\ #######.?????????????" ); } #[test] fn test_draw_alignment_patterns_3() { let mut c = Canvas::new(Version::Normal(3), EcLevel::L); c.draw_finder_patterns(); c.draw_alignment_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######.?????????????.#######\n\ #.....#.?????????????.#.....#\n\ #.###.#.?????????????.#.###.#\n\ #.###.#.?????????????.#.###.#\n\ #.###.#.?????????????.#.###.#\n\ #.....#.?????????????.#.....#\n\ #######.?????????????.#######\n\ ........?????????????........\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ?????????????????????????????\n\ ????????????????????#####????\n\ ........????????????#...#????\n\ #######.????????????#.#.#????\n\ #.....#.????????????#...#????\n\ #.###.#.????????????#####????\n\ #.###.#.?????????????????????\n\ #.###.#.?????????????????????\n\ #.....#.?????????????????????\n\ #######.?????????????????????" ); } #[test] fn test_draw_alignment_patterns_7() { let mut c = Canvas::new(Version::Normal(7), EcLevel::L); c.draw_finder_patterns(); c.draw_alignment_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######.?????????????????????????????.#######\n\ #.....#.?????????????????????????????.#.....#\n\ #.###.#.?????????????????????????????.#.###.#\n\ #.###.#.?????????????????????????????.#.###.#\n\ #.###.#.????????????#####????????????.#.###.#\n\ #.....#.????????????#...#????????????.#.....#\n\ #######.????????????#.#.#????????????.#######\n\ ........????????????#...#????????????........\n\ ????????????????????#####????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ????#####???????????#####???????????#####????\n\ ????#...#???????????#...#???????????#...#????\n\ ????#.#.#???????????#.#.#???????????#.#.#????\n\ ????#...#???????????#...#???????????#...#????\n\ ????#####???????????#####???????????#####????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ????????????????????#####???????????#####????\n\ ........????????????#...#???????????#...#????\n\ #######.????????????#.#.#???????????#.#.#????\n\ #.....#.????????????#...#???????????#...#????\n\ #.###.#.????????????#####???????????#####????\n\ #.###.#.?????????????????????????????????????\n\ #.###.#.?????????????????????????????????????\n\ #.....#.?????????????????????????????????????\n\ #######.?????????????????????????????????????" ); } } /// `ALIGNMENT_PATTERN_POSITIONS` describes the x- and y-coordinates of the /// center of the alignment patterns. Since the QR code is symmetric, only one /// coordinate is needed. static ALIGNMENT_PATTERN_POSITIONS: [&[i16]; 34] = [ &[6, 22, 38], &[6, 24, 42], &[6, 26, 46], &[6, 28, 50], &[6, 30, 54], &[6, 32, 58], &[6, 34, 62], &[6, 26, 46, 66], &[6, 26, 48, 70], &[6, 26, 50, 74], &[6, 30, 54, 78], &[6, 30, 56, 82], &[6, 30, 58, 86], &[6, 34, 62, 90], &[6, 28, 50, 72, 94], &[6, 26, 50, 74, 98], &[6, 30, 54, 78, 102], &[6, 28, 54, 80, 106], &[6, 32, 58, 84, 110], &[6, 30, 58, 86, 114], &[6, 34, 62, 90, 118], &[6, 26, 50, 74, 98, 122], &[6, 30, 54, 78, 102, 126], &[6, 26, 52, 78, 104, 130], &[6, 30, 56, 82, 108, 134], &[6, 34, 60, 86, 112, 138], &[6, 30, 58, 86, 114, 142], &[6, 34, 62, 90, 118, 146], &[6, 30, 54, 78, 102, 126, 150], &[6, 24, 50, 76, 102, 128, 154], &[6, 28, 54, 80, 106, 132, 158], &[6, 32, 58, 84, 110, 136, 162], &[6, 26, 54, 82, 110, 138, 166], &[6, 30, 58, 86, 114, 142, 170], ]; //}}} //------------------------------------------------------------------------------ //{{{ Timing patterns impl Canvas { /// Draws a line from (x1, y1) to (x2, y2), inclusively. /// /// The line must be either horizontal or vertical, i.e. /// `x1 == x2 || y1 == y2`. Additionally, the first coordinates must be less /// then the second ones. /// /// On even coordinates, `color_even` will be plotted; on odd coordinates, /// `color_odd` will be plotted instead. Thus the timing pattern can be /// drawn using this method. /// fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16, color_even: Color, color_odd: Color) { debug_assert!(x1 == x2 || y1 == y2); if y1 == y2 { // Horizontal line. for x in x1..=x2 { self.put(x, y1, if x % 2 == 0 { color_even } else { color_odd }); } } else { // Vertical line. for y in y1..=y2 { self.put(x1, y, if y % 2 == 0 { color_even } else { color_odd }); } } } /// Draws the timing patterns. /// /// The timing patterns are checkboard-colored lines near the edge of the QR /// code symbol, to establish the fine-grained module coordinates when /// scanning. fn draw_timing_patterns(&mut self) { let width = self.width; let (y, x1, x2) = match self.version { Version::Micro(_) => (0, 8, width - 1), Version::Normal(_) => (6, 8, width - 9), }; self.draw_line(x1, y, x2, y, Color::Dark, Color::Light); self.draw_line(y, x1, y, x2, Color::Dark, Color::Light); } } #[cfg(test)] mod timing_pattern_tests { use crate::canvas::Canvas; use crate::types::{EcLevel, Version}; #[test] fn test_draw_timing_patterns_qr() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_timing_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ????????#.#.#????????\n\ ?????????????????????\n\ ??????#??????????????\n\ ??????.??????????????\n\ ??????#??????????????\n\ ??????.??????????????\n\ ??????#??????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????" ); } #[test] fn test_draw_timing_patterns_micro_qr() { let mut c = Canvas::new(Version::Micro(1), EcLevel::L); c.draw_timing_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ ????????#.#\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ #??????????\n\ .??????????\n\ #??????????" ); } } //}}} //------------------------------------------------------------------------------ //{{{ Format info & Version info impl Canvas { /// Draws a big-endian integer onto the canvas with the given coordinates. /// /// The 1 bits will be plotted with `on_color` and the 0 bits with /// `off_color`. The coordinates will be extracted from the `coords` /// iterator. It will start from the most significant bits first, so /// *trailing* zeros will be ignored. fn draw_number(&mut self, number: u32, bits: u32, on_color: Color, off_color: Color, coords: &[(i16, i16)]) { let mut mask = 1 << (bits - 1); for &(x, y) in coords { let color = if (mask & number) == 0 { off_color } else { on_color }; self.put(x, y, color); mask >>= 1; } } /// Draws the format info patterns for an encoded number. fn draw_format_info_patterns_with_number(&mut self, format_info: u16) { let format_info = u32::from(format_info); match self.version { Version::Micro(_) => { self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_MICRO_QR); } Version::Normal(_) => { self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_MAIN); self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_SIDE); self.put(8, -8, Color::Dark); // Dark module. } } } /// Reserves area to put in the format information. fn draw_reserved_format_info_patterns(&mut self) { self.draw_format_info_patterns_with_number(0); } /// Draws the version information patterns. fn draw_version_info_patterns(&mut self) { match self.version { Version::Micro(_) | Version::Normal(1..=6) => {} Version::Normal(a) => { let version_info = VERSION_INFOS[(a - 7).as_usize()]; self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_BL); self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_TR); } } } } #[cfg(test)] mod draw_version_info_tests { use crate::canvas::Canvas; use crate::types::{Color, EcLevel, Version}; #[test] fn test_draw_number() { let mut c = Canvas::new(Version::Micro(1), EcLevel::L); c.draw_number(0b1010_1101, 8, Color::Dark, Color::Light, &[(0, 0), (0, -1), (-2, -2), (-2, 0)]); assert_eq!( &*c.to_debug_str(), "\n\ #????????.?\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ???????????\n\ ?????????#?\n\ .??????????" ); } #[test] fn test_draw_version_info_1() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_version_info_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????" ); } #[test] fn test_draw_version_info_7() { let mut c = Canvas::new(Version::Normal(7), EcLevel::L); c.draw_version_info_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ ??????????????????????????????????..#????????\n\ ??????????????????????????????????.#.????????\n\ ??????????????????????????????????.#.????????\n\ ??????????????????????????????????.##????????\n\ ??????????????????????????????????###????????\n\ ??????????????????????????????????...????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ....#.???????????????????????????????????????\n\ .####.???????????????????????????????????????\n\ #..##.???????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????\n\ ?????????????????????????????????????????????" ); } #[test] fn test_draw_reserved_format_info_patterns_qr() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_reserved_format_info_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ?????????????????????\n\ ????????.????????????\n\ ......?..????........\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ????????#????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????.????????????" ); } #[test] fn test_draw_reserved_format_info_patterns_micro_qr() { let mut c = Canvas::new(Version::Micro(1), EcLevel::L); c.draw_reserved_format_info_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ ???????????\n\ ????????.??\n\ ????????.??\n\ ????????.??\n\ ????????.??\n\ ????????.??\n\ ????????.??\n\ ????????.??\n\ ?........??\n\ ???????????\n\ ???????????" ); } } static VERSION_INFO_COORDS_BL: [(i16, i16); 18] = [ (5, -9), (5, -10), (5, -11), (4, -9), (4, -10), (4, -11), (3, -9), (3, -10), (3, -11), (2, -9), (2, -10), (2, -11), (1, -9), (1, -10), (1, -11), (0, -9), (0, -10), (0, -11), ]; static VERSION_INFO_COORDS_TR: [(i16, i16); 18] = [ (-9, 5), (-10, 5), (-11, 5), (-9, 4), (-10, 4), (-11, 4), (-9, 3), (-10, 3), (-11, 3), (-9, 2), (-10, 2), (-11, 2), (-9, 1), (-10, 1), (-11, 1), (-9, 0), (-10, 0), (-11, 0), ]; static FORMAT_INFO_COORDS_QR_MAIN: [(i16, i16); 15] = [ (0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (7, 8), (8, 8), (8, 7), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (8, 0), ]; static FORMAT_INFO_COORDS_QR_SIDE: [(i16, i16); 15] = [ (8, -1), (8, -2), (8, -3), (8, -4), (8, -5), (8, -6), (8, -7), (-8, 8), (-7, 8), (-6, 8), (-5, 8), (-4, 8), (-3, 8), (-2, 8), (-1, 8), ]; static FORMAT_INFO_COORDS_MICRO_QR: [(i16, i16); 15] = [ (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (6, 8), (7, 8), (8, 8), (8, 7), (8, 6), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), ]; static VERSION_INFOS: [u32; 34] = [ 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69, ]; //}}} //------------------------------------------------------------------------------ //{{{ All functional patterns before data placement impl Canvas { /// Draw all functional patterns, before data placement. /// /// All functional patterns (e.g. the finder pattern) *except* the format /// info pattern will be filled in. The format info pattern will be filled /// with light modules instead. Data bits can then put in the empty modules. /// with `.draw_data()`. pub fn draw_all_functional_patterns(&mut self) { self.draw_finder_patterns(); self.draw_alignment_patterns(); self.draw_reserved_format_info_patterns(); self.draw_timing_patterns(); self.draw_version_info_patterns(); } } /// Gets whether the module at the given coordinates represents a functional /// module. pub fn is_functional(version: Version, width: i16, x: i16, y: i16) -> bool { debug_assert!(width == version.width()); let x = if x < 0 { x + width } else { x }; let y = if y < 0 { y + width } else { y }; match version { Version::Micro(_) => x == 0 || y == 0 || (x < 9 && y < 9), Version::Normal(a) => { let non_alignment_test = x == 6 || y == 6 || // Timing patterns (x < 9 && y < 9) || // Top-left finder pattern (x < 9 && y >= width-8) || // Bottom-left finder pattern (x >= width-8 && y < 9); // Top-right finder pattern if non_alignment_test { true } else if a == 1 { false } else if (2..=6).contains(&a) { (width - 7 - x).abs() <= 2 && (width - 7 - y).abs() <= 2 } else { let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()]; let last = positions.len() - 1; for (i, align_x) in positions.iter().enumerate() { for (j, align_y) in positions.iter().enumerate() { if i == 0 && (j == 0 || j == last) || (i == last && j == 0) { continue; } if (*align_x - x).abs() <= 2 && (*align_y - y).abs() <= 2 { return true; } } } false } } } } #[cfg(test)] mod all_functional_patterns_tests { use crate::canvas::{is_functional, Canvas}; use crate::types::{EcLevel, Version}; #[test] fn test_all_functional_patterns_qr() { let mut c = Canvas::new(Version::Normal(2), EcLevel::L); c.draw_all_functional_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######..????????.#######\n\ #.....#..????????.#.....#\n\ #.###.#..????????.#.###.#\n\ #.###.#..????????.#.###.#\n\ #.###.#..????????.#.###.#\n\ #.....#..????????.#.....#\n\ #######.#.#.#.#.#.#######\n\ .........????????........\n\ ......#..????????........\n\ ??????.??????????????????\n\ ??????#??????????????????\n\ ??????.??????????????????\n\ ??????#??????????????????\n\ ??????.??????????????????\n\ ??????#??????????????????\n\ ??????.??????????????????\n\ ??????#?????????#####????\n\ ........#???????#...#????\n\ #######..???????#.#.#????\n\ #.....#..???????#...#????\n\ #.###.#..???????#####????\n\ #.###.#..????????????????\n\ #.###.#..????????????????\n\ #.....#..????????????????\n\ #######..????????????????" ); } #[test] fn test_all_functional_patterns_micro_qr() { let mut c = Canvas::new(Version::Micro(1), EcLevel::L); c.draw_all_functional_patterns(); assert_eq!( &*c.to_debug_str(), "\n\ #######.#.#\n\ #.....#..??\n\ #.###.#..??\n\ #.###.#..??\n\ #.###.#..??\n\ #.....#..??\n\ #######..??\n\ .........??\n\ #........??\n\ .??????????\n\ #??????????" ); } #[test] fn test_is_functional_qr_1() { let version = Version::Normal(1); assert!(is_functional(version, version.width(), 0, 0)); assert!(is_functional(version, version.width(), 10, 6)); assert!(!is_functional(version, version.width(), 10, 5)); assert!(!is_functional(version, version.width(), 14, 14)); assert!(is_functional(version, version.width(), 6, 11)); assert!(!is_functional(version, version.width(), 4, 11)); assert!(is_functional(version, version.width(), 4, 13)); assert!(is_functional(version, version.width(), 17, 7)); assert!(!is_functional(version, version.width(), 17, 17)); } #[test] fn test_is_functional_qr_3() { let version = Version::Normal(3); assert!(is_functional(version, version.width(), 0, 0)); assert!(!is_functional(version, version.width(), 25, 24)); assert!(is_functional(version, version.width(), 24, 24)); assert!(!is_functional(version, version.width(), 9, 25)); assert!(!is_functional(version, version.width(), 20, 0)); assert!(is_functional(version, version.width(), 21, 0)); } #[test] fn test_is_functional_qr_7() { let version = Version::Normal(7); assert!(is_functional(version, version.width(), 21, 4)); assert!(is_functional(version, version.width(), 7, 21)); assert!(is_functional(version, version.width(), 22, 22)); assert!(is_functional(version, version.width(), 8, 8)); assert!(!is_functional(version, version.width(), 19, 5)); assert!(!is_functional(version, version.width(), 36, 3)); assert!(!is_functional(version, version.width(), 4, 36)); assert!(is_functional(version, version.width(), 38, 38)); } #[test] fn test_is_functional_micro() { let version = Version::Micro(1); assert!(is_functional(version, version.width(), 8, 0)); assert!(is_functional(version, version.width(), 10, 0)); assert!(!is_functional(version, version.width(), 10, 1)); assert!(is_functional(version, version.width(), 8, 8)); assert!(is_functional(version, version.width(), 0, 9)); assert!(!is_functional(version, version.width(), 1, 9)); } } //}}} //------------------------------------------------------------------------------ //{{{ Data placement iterator struct DataModuleIter { x: i16, y: i16, width: i16, timing_pattern_column: i16, } impl DataModuleIter { fn new(version: Version) -> Self { let width = version.width(); Self { x: width - 1, y: width - 1, width, timing_pattern_column: match version { Version::Micro(_) => 0, Version::Normal(_) => 6, }, } } } impl Iterator for DataModuleIter { type Item = (i16, i16); fn next(&mut self) -> Option<(i16, i16)> { let adjusted_ref_col = if self.x <= self.timing_pattern_column { self.x + 1 } else { self.x }; if adjusted_ref_col <= 0 { return None; } let res = (self.x, self.y); let column_type = (self.width - adjusted_ref_col) % 4; match column_type { 2 if self.y > 0 => { self.y -= 1; self.x += 1; } 0 if self.y < self.width - 1 => { self.y += 1; self.x += 1; } 0 | 2 if self.x == self.timing_pattern_column + 1 => { self.x -= 2; } _ => { self.x -= 1; } } Some(res) } } #[cfg(test)] #[rustfmt::skip] // skip to prevent file becoming too long. mod data_iter_tests { use crate::canvas::DataModuleIter; use crate::types::Version; #[test] fn test_qr() { let res = DataModuleIter::new(Version::Normal(1)).collect::>(); assert_eq!(res, vec![ (20, 20), (19, 20), (20, 19), (19, 19), (20, 18), (19, 18), (20, 17), (19, 17), (20, 16), (19, 16), (20, 15), (19, 15), (20, 14), (19, 14), (20, 13), (19, 13), (20, 12), (19, 12), (20, 11), (19, 11), (20, 10), (19, 10), (20, 9), (19, 9), (20, 8), (19, 8), (20, 7), (19, 7), (20, 6), (19, 6), (20, 5), (19, 5), (20, 4), (19, 4), (20, 3), (19, 3), (20, 2), (19, 2), (20, 1), (19, 1), (20, 0), (19, 0), (18, 0), (17, 0), (18, 1), (17, 1), (18, 2), (17, 2), (18, 3), (17, 3), (18, 4), (17, 4), (18, 5), (17, 5), (18, 6), (17, 6), (18, 7), (17, 7), (18, 8), (17, 8), (18, 9), (17, 9), (18, 10), (17, 10), (18, 11), (17, 11), (18, 12), (17, 12), (18, 13), (17, 13), (18, 14), (17, 14), (18, 15), (17, 15), (18, 16), (17, 16), (18, 17), (17, 17), (18, 18), (17, 18), (18, 19), (17, 19), (18, 20), (17, 20), (16, 20), (15, 20), (16, 19), (15, 19), (16, 18), (15, 18), (16, 17), (15, 17), (16, 16), (15, 16), (16, 15), (15, 15), (16, 14), (15, 14), (16, 13), (15, 13), (16, 12), (15, 12), (16, 11), (15, 11), (16, 10), (15, 10), (16, 9), (15, 9), (16, 8), (15, 8), (16, 7), (15, 7), (16, 6), (15, 6), (16, 5), (15, 5), (16, 4), (15, 4), (16, 3), (15, 3), (16, 2), (15, 2), (16, 1), (15, 1), (16, 0), (15, 0), (14, 0), (13, 0), (14, 1), (13, 1), (14, 2), (13, 2), (14, 3), (13, 3), (14, 4), (13, 4), (14, 5), (13, 5), (14, 6), (13, 6), (14, 7), (13, 7), (14, 8), (13, 8), (14, 9), (13, 9), (14, 10), (13, 10), (14, 11), (13, 11), (14, 12), (13, 12), (14, 13), (13, 13), (14, 14), (13, 14), (14, 15), (13, 15), (14, 16), (13, 16), (14, 17), (13, 17), (14, 18), (13, 18), (14, 19), (13, 19), (14, 20), (13, 20), (12, 20), (11, 20), (12, 19), (11, 19), (12, 18), (11, 18), (12, 17), (11, 17), (12, 16), (11, 16), (12, 15), (11, 15), (12, 14), (11, 14), (12, 13), (11, 13), (12, 12), (11, 12), (12, 11), (11, 11), (12, 10), (11, 10), (12, 9), (11, 9), (12, 8), (11, 8), (12, 7), (11, 7), (12, 6), (11, 6), (12, 5), (11, 5), (12, 4), (11, 4), (12, 3), (11, 3), (12, 2), (11, 2), (12, 1), (11, 1), (12, 0), (11, 0), (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2), (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5), (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8), (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11), (10, 12), (9, 12), (10, 13), (9, 13), (10, 14), (9, 14), (10, 15), (9, 15), (10, 16), (9, 16), (10, 17), (9, 17), (10, 18), (9, 18), (10, 19), (9, 19), (10, 20), (9, 20), (8, 20), (7, 20), (8, 19), (7, 19), (8, 18), (7, 18), (8, 17), (7, 17), (8, 16), (7, 16), (8, 15), (7, 15), (8, 14), (7, 14), (8, 13), (7, 13), (8, 12), (7, 12), (8, 11), (7, 11), (8, 10), (7, 10), (8, 9), (7, 9), (8, 8), (7, 8), (8, 7), (7, 7), (8, 6), (7, 6), (8, 5), (7, 5), (8, 4), (7, 4), (8, 3), (7, 3), (8, 2), (7, 2), (8, 1), (7, 1), (8, 0), (7, 0), (5, 0), (4, 0), (5, 1), (4, 1), (5, 2), (4, 2), (5, 3), (4, 3), (5, 4), (4, 4), (5, 5), (4, 5), (5, 6), (4, 6), (5, 7), (4, 7), (5, 8), (4, 8), (5, 9), (4, 9), (5, 10), (4, 10), (5, 11), (4, 11), (5, 12), (4, 12), (5, 13), (4, 13), (5, 14), (4, 14), (5, 15), (4, 15), (5, 16), (4, 16), (5, 17), (4, 17), (5, 18), (4, 18), (5, 19), (4, 19), (5, 20), (4, 20), (3, 20), (2, 20), (3, 19), (2, 19), (3, 18), (2, 18), (3, 17), (2, 17), (3, 16), (2, 16), (3, 15), (2, 15), (3, 14), (2, 14), (3, 13), (2, 13), (3, 12), (2, 12), (3, 11), (2, 11), (3, 10), (2, 10), (3, 9), (2, 9), (3, 8), (2, 8), (3, 7), (2, 7), (3, 6), (2, 6), (3, 5), (2, 5), (3, 4), (2, 4), (3, 3), (2, 3), (3, 2), (2, 2), (3, 1), (2, 1), (3, 0), (2, 0), (1, 0), (0, 0), (1, 1), (0, 1), (1, 2), (0, 2), (1, 3), (0, 3), (1, 4), (0, 4), (1, 5), (0, 5), (1, 6), (0, 6), (1, 7), (0, 7), (1, 8), (0, 8), (1, 9), (0, 9), (1, 10), (0, 10), (1, 11), (0, 11), (1, 12), (0, 12), (1, 13), (0, 13), (1, 14), (0, 14), (1, 15), (0, 15), (1, 16), (0, 16), (1, 17), (0, 17), (1, 18), (0, 18), (1, 19), (0, 19), (1, 20), (0, 20), ]); } #[test] fn test_micro_qr() { let res = DataModuleIter::new(Version::Micro(1)).collect::>(); assert_eq!(res, vec![ (10, 10), (9, 10), (10, 9), (9, 9), (10, 8), (9, 8), (10, 7), (9, 7), (10, 6), (9, 6), (10, 5), (9, 5), (10, 4), (9, 4), (10, 3), (9, 3), (10, 2), (9, 2), (10, 1), (9, 1), (10, 0), (9, 0), (8, 0), (7, 0), (8, 1), (7, 1), (8, 2), (7, 2), (8, 3), (7, 3), (8, 4), (7, 4), (8, 5), (7, 5), (8, 6), (7, 6), (8, 7), (7, 7), (8, 8), (7, 8), (8, 9), (7, 9), (8, 10), (7, 10), (6, 10), (5, 10), (6, 9), (5, 9), (6, 8), (5, 8), (6, 7), (5, 7), (6, 6), (5, 6), (6, 5), (5, 5), (6, 4), (5, 4), (6, 3), (5, 3), (6, 2), (5, 2), (6, 1), (5, 1), (6, 0), (5, 0), (4, 0), (3, 0), (4, 1), (3, 1), (4, 2), (3, 2), (4, 3), (3, 3), (4, 4), (3, 4), (4, 5), (3, 5), (4, 6), (3, 6), (4, 7), (3, 7), (4, 8), (3, 8), (4, 9), (3, 9), (4, 10), (3, 10), (2, 10), (1, 10), (2, 9), (1, 9), (2, 8), (1, 8), (2, 7), (1, 7), (2, 6), (1, 6), (2, 5), (1, 5), (2, 4), (1, 4), (2, 3), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), (2, 0), (1, 0), ]); } #[test] fn test_micro_qr_2() { let res = DataModuleIter::new(Version::Micro(2)).collect::>(); assert_eq!(res, vec![ (12, 12), (11, 12), (12, 11), (11, 11), (12, 10), (11, 10), (12, 9), (11, 9), (12, 8), (11, 8), (12, 7), (11, 7), (12, 6), (11, 6), (12, 5), (11, 5), (12, 4), (11, 4), (12, 3), (11, 3), (12, 2), (11, 2), (12, 1), (11, 1), (12, 0), (11, 0), (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2), (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5), (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8), (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11), (10, 12), (9, 12), (8, 12), (7, 12), (8, 11), (7, 11), (8, 10), (7, 10), (8, 9), (7, 9), (8, 8), (7, 8), (8, 7), (7, 7), (8, 6), (7, 6), (8, 5), (7, 5), (8, 4), (7, 4), (8, 3), (7, 3), (8, 2), (7, 2), (8, 1), (7, 1), (8, 0), (7, 0), (6, 0), (5, 0), (6, 1), (5, 1), (6, 2), (5, 2), (6, 3), (5, 3), (6, 4), (5, 4), (6, 5), (5, 5), (6, 6), (5, 6), (6, 7), (5, 7), (6, 8), (5, 8), (6, 9), (5, 9), (6, 10), (5, 10), (6, 11), (5, 11), (6, 12), (5, 12), (4, 12), (3, 12), (4, 11), (3, 11), (4, 10), (3, 10), (4, 9), (3, 9), (4, 8), (3, 8), (4, 7), (3, 7), (4, 6), (3, 6), (4, 5), (3, 5), (4, 4), (3, 4), (4, 3), (3, 3), (4, 2), (3, 2), (4, 1), (3, 1), (4, 0), (3, 0), (2, 0), (1, 0), (2, 1), (1, 1), (2, 2), (1, 2), (2, 3), (1, 3), (2, 4), (1, 4), (2, 5), (1, 5), (2, 6), (1, 6), (2, 7), (1, 7), (2, 8), (1, 8), (2, 9), (1, 9), (2, 10), (1, 10), (2, 11), (1, 11), (2, 12), (1, 12), ]); } } //}}} //------------------------------------------------------------------------------ //{{{ Data placement impl Canvas { fn draw_codewords(&mut self, codewords: &[u8], is_half_codeword_at_end: bool, coords: &mut I) where I: Iterator, { let length = codewords.len(); let last_word = if is_half_codeword_at_end { length - 1 } else { length }; for (i, b) in codewords.iter().enumerate() { let bits_end = if i == last_word { 4 } else { 0 }; 'outside: for j in (bits_end..=7).rev() { let color = if (*b & (1 << j)) == 0 { Color::Light } else { Color::Dark }; for (x, y) in coords.by_ref() { let r = self.get_mut(x, y); if *r == Module::Empty { *r = Module::Unmasked(color); continue 'outside; } } return; } } } /// Draws the encoded data and error correction codes to the empty modules. pub fn draw_data(&mut self, data: &[u8], ec: &[u8]) { let is_half_codeword_at_end = matches!((self.version, self.ec_level), (Version::Micro(1), EcLevel::L) | (Version::Micro(3), EcLevel::M)); let mut coords = DataModuleIter::new(self.version); self.draw_codewords(data, is_half_codeword_at_end, &mut coords); self.draw_codewords(ec, false, &mut coords); } } #[cfg(test)] mod draw_codewords_test { use crate::canvas::Canvas; use crate::types::{EcLevel, Version}; #[test] fn test_micro_qr_1() { let mut c = Canvas::new(Version::Micro(1), EcLevel::L); c.draw_all_functional_patterns(); c.draw_data(b"\x6e\x5d\xe2", b"\x2b\x63"); assert_eq!( &*c.to_debug_str(), "\n\ #######.#.#\n\ #.....#..-*\n\ #.###.#..**\n\ #.###.#..*-\n\ #.###.#..**\n\ #.....#..*-\n\ #######..*-\n\ .........-*\n\ #........**\n\ .***-**---*\n\ #---*-*-**-" ); } #[test] fn test_qr_2() { let mut c = Canvas::new(Version::Normal(2), EcLevel::L); c.draw_all_functional_patterns(); c.draw_data( b"\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\ \x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$", b"", ); assert_eq!( &*c.to_debug_str(), "\n\ #######..--*---*-.#######\n\ #.....#..-*-*-*-*.#.....#\n\ #.###.#..*---*---.#.###.#\n\ #.###.#..--*---*-.#.###.#\n\ #.###.#..-*-*-*-*.#.###.#\n\ #.....#..*---*---.#.....#\n\ #######.#.#.#.#.#.#######\n\ .........--*---*-........\n\ ......#..-*-*-*-*........\n\ --*-*-.-**---*---*--**--*\n\ -*-*--#----*---*---------\n\ *----*.*--*-*-*-*-**--**-\n\ --*-*-#-**---*---*--**--*\n\ -*-*--.----*---*---------\n\ *----*#*--*-*-*-*-**--**-\n\ --*-*-.-**---*---*--**--*\n\ -*-*--#----*---*#####----\n\ ........#-*-*-*-#...#-**-\n\ #######..*---*--#.#.#*--*\n\ #.....#..--*---*#...#----\n\ #.###.#..-*-*-*-#####-**-\n\ #.###.#..*---*--*----*--*\n\ #.###.#..--*------**-----\n\ #.....#..-*-*-**-*--*-**-\n\ #######..*---*--*----*--*" ); } } //}}} //------------------------------------------------------------------------------ //{{{ Masking /// The mask patterns. Since QR code and Micro QR code do not use the same /// pattern number, we name them according to their shape instead of the number. #[derive(Debug, Copy, Clone)] pub enum MaskPattern { /// QR code pattern 000: `(x + y) % 2 == 0`. Checkerboard = 0b000, /// QR code pattern 001: `y % 2 == 0`. HorizontalLines = 0b001, /// QR code pattern 010: `x % 3 == 0`. VerticalLines = 0b010, /// QR code pattern 011: `(x + y) % 3 == 0`. DiagonalLines = 0b011, /// QR code pattern 100: `((x/3) + (y/2)) % 2 == 0`. LargeCheckerboard = 0b100, /// QR code pattern 101: `(x*y)%2 + (x*y)%3 == 0`. Fields = 0b101, /// QR code pattern 110: `((x*y)%2 + (x*y)%3) % 2 == 0`. Diamonds = 0b110, /// QR code pattern 111: `((x+y)%2 + (x*y)%3) % 2 == 0`. Meadow = 0b111, } mod mask_functions { pub fn checkerboard(x: i16, y: i16) -> bool { (x + y) % 2 == 0 } pub fn horizontal_lines(_: i16, y: i16) -> bool { y % 2 == 0 } pub fn vertical_lines(x: i16, _: i16) -> bool { x % 3 == 0 } pub fn diagonal_lines(x: i16, y: i16) -> bool { (x + y) % 3 == 0 } pub fn large_checkerboard(x: i16, y: i16) -> bool { ((y / 2) + (x / 3)) % 2 == 0 } pub fn fields(x: i16, y: i16) -> bool { (x * y) % 2 + (x * y) % 3 == 0 } pub fn diamonds(x: i16, y: i16) -> bool { ((x * y) % 2 + (x * y) % 3) % 2 == 0 } pub fn meadow(x: i16, y: i16) -> bool { ((x + y) % 2 + (x * y) % 3) % 2 == 0 } } fn get_mask_function(pattern: MaskPattern) -> fn(i16, i16) -> bool { match pattern { MaskPattern::Checkerboard => mask_functions::checkerboard, MaskPattern::HorizontalLines => mask_functions::horizontal_lines, MaskPattern::VerticalLines => mask_functions::vertical_lines, MaskPattern::DiagonalLines => mask_functions::diagonal_lines, MaskPattern::LargeCheckerboard => mask_functions::large_checkerboard, MaskPattern::Fields => mask_functions::fields, MaskPattern::Diamonds => mask_functions::diamonds, MaskPattern::Meadow => mask_functions::meadow, } } impl Canvas { /// Applies a mask to the canvas. This method will also draw the format info /// patterns. pub fn apply_mask(&mut self, pattern: MaskPattern) { let mask_fn = get_mask_function(pattern); for x in 0..self.width { for y in 0..self.width { let module = self.get_mut(x, y); *module = module.mask(mask_fn(x, y)); } } self.draw_format_info_patterns(pattern); } /// Draws the format information to encode the error correction level and /// mask pattern. /// /// If the error correction level or mask pattern is not supported in the /// current QR code version, this method will fail. fn draw_format_info_patterns(&mut self, pattern: MaskPattern) { let format_number = match self.version { Version::Normal(_) => { let simple_format_number = ((self.ec_level as usize) ^ 1) << 3 | (pattern as usize); FORMAT_INFOS_QR[simple_format_number] } Version::Micro(a) => { let micro_pattern_number = match pattern { MaskPattern::HorizontalLines => 0b00, MaskPattern::LargeCheckerboard => 0b01, MaskPattern::Diamonds => 0b10, MaskPattern::Meadow => 0b11, _ => panic!("Unsupported mask pattern in Micro QR code"), }; let symbol_number = match (a, self.ec_level) { (1, EcLevel::L) => 0b000, (2, EcLevel::L) => 0b001, (2, EcLevel::M) => 0b010, (3, EcLevel::L) => 0b011, (3, EcLevel::M) => 0b100, (4, EcLevel::L) => 0b101, (4, EcLevel::M) => 0b110, (4, EcLevel::Q) => 0b111, _ => panic!("Unsupported version/ec_level combination in Micro QR code"), }; let simple_format_number = symbol_number << 2 | micro_pattern_number; FORMAT_INFOS_MICRO_QR[simple_format_number] } }; self.draw_format_info_patterns_with_number(format_number); } } #[cfg(test)] mod mask_tests { use crate::canvas::{Canvas, MaskPattern}; use crate::types::{EcLevel, Version}; #[test] fn test_apply_mask_qr() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_all_functional_patterns(); c.apply_mask(MaskPattern::Checkerboard); assert_eq!( &*c.to_debug_str(), "\n\ #######...#.#.#######\n\ #.....#..#.#..#.....#\n\ #.###.#.#.#.#.#.###.#\n\ #.###.#..#.#..#.###.#\n\ #.###.#...#.#.#.###.#\n\ #.....#..#.#..#.....#\n\ #######.#.#.#.#######\n\ ........##.#.........\n\ ###.#####.#.###...#..\n\ .#.#.#.#.#.#.#.#.#.#.\n\ #.#.#.#.#.#.#.#.#.#.#\n\ .#.#.#.#.#.#.#.#.#.#.\n\ #.#.#.#.#.#.#.#.#.#.#\n\ ........##.#.#.#.#.#.\n\ #######.#.#.#.#.#.#.#\n\ #.....#.##.#.#.#.#.#.\n\ #.###.#.#.#.#.#.#.#.#\n\ #.###.#..#.#.#.#.#.#.\n\ #.###.#.#.#.#.#.#.#.#\n\ #.....#.##.#.#.#.#.#.\n\ #######.#.#.#.#.#.#.#" ); } #[test] fn test_draw_format_info_patterns_qr() { let mut c = Canvas::new(Version::Normal(1), EcLevel::L); c.draw_format_info_patterns(MaskPattern::LargeCheckerboard); assert_eq!( &*c.to_debug_str(), "\n\ ????????#????????????\n\ ????????#????????????\n\ ????????#????????????\n\ ????????#????????????\n\ ????????.????????????\n\ ????????#????????????\n\ ?????????????????????\n\ ????????.????????????\n\ ##..##?..????..#.####\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ?????????????????????\n\ ????????#????????????\n\ ????????.????????????\n\ ????????#????????????\n\ ????????#????????????\n\ ????????.????????????\n\ ????????.????????????\n\ ????????#????????????\n\ ????????#????????????" ); } #[test] fn test_draw_format_info_patterns_micro_qr() { let mut c = Canvas::new(Version::Micro(2), EcLevel::L); c.draw_format_info_patterns(MaskPattern::LargeCheckerboard); assert_eq!( &*c.to_debug_str(), "\n\ ?????????????\n\ ????????#????\n\ ????????.????\n\ ????????.????\n\ ????????#????\n\ ????????#????\n\ ????????.????\n\ ????????.????\n\ ?#.#....#????\n\ ?????????????\n\ ?????????????\n\ ?????????????\n\ ?????????????" ); } } static FORMAT_INFOS_QR: [u16; 32] = [ 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, ]; static FORMAT_INFOS_MICRO_QR: [u16; 32] = [ 0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f, 0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51, 0x34e3, 0x31d4, 0x3e8d, 0x3bba, ]; //}}} //------------------------------------------------------------------------------ //{{{ Penalty score impl Canvas { /// Compute the penalty score for having too many adjacent modules with the /// same color. /// /// Every 5+N adjacent modules in the same column/row having the same color /// will contribute 3+N points. fn compute_adjacent_penalty_score(&self, is_horizontal: bool) -> u16 { let mut total_score = 0; for i in 0..self.width { let map_fn = |j| if is_horizontal { self.get(j, i) } else { self.get(i, j) }; let colors = (0..self.width).map(map_fn).chain(Some(Module::Empty).into_iter()); let mut last_color = Module::Empty; let mut consecutive_len = 1_u16; for color in colors { if color == last_color { consecutive_len += 1; } else { last_color = color; if consecutive_len >= 5 { total_score += consecutive_len - 2; } consecutive_len = 1; } } } total_score } /// Compute the penalty score for having too many rectangles with the same /// color. /// /// Every 2×2 blocks (with overlapping counted) having the same color will /// contribute 3 points. fn compute_block_penalty_score(&self) -> u16 { let mut total_score = 0; for i in 0..self.width - 1 { for j in 0..self.width - 1 { let this = self.get(i, j); let right = self.get(i + 1, j); let bottom = self.get(i, j + 1); let bottom_right = self.get(i + 1, j + 1); if this == right && right == bottom && bottom == bottom_right { total_score += 3; } } } total_score } /// Compute the penalty score for having a pattern similar to the finder /// pattern in the wrong place. /// /// Every pattern that looks like `#.###.#....` in any orientation will add /// 40 points. fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 { static PATTERN: [Color; 7] = [Color::Dark, Color::Light, Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Dark]; let mut total_score = 0; for i in 0..self.width { for j in 0..self.width - 6 { // TODO a ref to a closure should be enough? let get: Box Color> = if is_horizontal { Box::new(|k| self.get(k, i).into()) } else { Box::new(|k| self.get(i, k).into()) }; if (j..(j + 7)).map(&*get).ne(PATTERN.iter().copied()) { continue; } let check = |k| 0 <= k && k < self.width && get(k) != Color::Light; if !((j - 4)..j).any(&check) || !((j + 7)..(j + 11)).any(&check) { total_score += 40; } } } total_score - 360 } /// Compute the penalty score for having an unbalanced dark/light ratio. /// /// The score is given linearly by the deviation from a 50% ratio of dark /// modules. The highest possible score is 100. /// /// Note that this algorithm differs slightly from the standard we do not /// round the result every 5%, but the difference should be negligible and /// should not affect which mask is chosen. fn compute_balance_penalty_score(&self) -> u16 { let dark_modules = self.modules.iter().filter(|m| m.is_dark()).count(); let total_modules = self.modules.len(); let ratio = dark_modules * 200 / total_modules; if ratio >= 100 { ratio - 100 } else { 100 - ratio }.as_u16() } /// Compute the penalty score for having too many light modules on the sides. /// /// This penalty score is exclusive to Micro QR code. /// /// Note that the standard gives the formula for *efficiency* score, which /// has the inverse meaning of this method, but it is very easy to convert /// between the two (this score is (16×width − standard-score)). fn compute_light_side_penalty_score(&self) -> u16 { let h = (1..self.width).filter(|j| !self.get(*j, -1).is_dark()).count(); let v = (1..self.width).filter(|j| !self.get(-1, *j).is_dark()).count(); (h + v + 15 * max(h, v)).as_u16() } /// Compute the total penalty scores. A QR code having higher points is less /// desirable. fn compute_total_penalty_scores(&self) -> u16 { match self.version { Version::Normal(_) => { let s1_a = self.compute_adjacent_penalty_score(true); let s1_b = self.compute_adjacent_penalty_score(false); let s2 = self.compute_block_penalty_score(); let s3_a = self.compute_finder_penalty_score(true); let s3_b = self.compute_finder_penalty_score(false); let s4 = self.compute_balance_penalty_score(); s1_a + s1_b + s2 + s3_a + s3_b + s4 } Version::Micro(_) => self.compute_light_side_penalty_score(), } } } #[cfg(test)] mod penalty_tests { use crate::canvas::{Canvas, MaskPattern}; use crate::cast::As; use crate::types::{Color, EcLevel, Version}; fn create_test_canvas() -> Canvas { let mut c = Canvas::new(Version::Normal(1), EcLevel::Q); c.draw_all_functional_patterns(); c.draw_data( b"\x20\x5b\x0b\x78\xd1\x72\xdc\x4d\x43\x40\xec\x11\x00", b"\xa8\x48\x16\x52\xd9\x36\x9c\x00\x2e\x0f\xb4\x7a\x10", ); c.apply_mask(MaskPattern::Checkerboard); c } #[test] fn check_penalty_canvas() { let c = create_test_canvas(); assert_eq!( &*c.to_debug_str(), "\n\ #######.##....#######\n\ #.....#.#..#..#.....#\n\ #.###.#.#..##.#.###.#\n\ #.###.#.#.....#.###.#\n\ #.###.#.#.#...#.###.#\n\ #.....#...#...#.....#\n\ #######.#.#.#.#######\n\ ........#............\n\ .##.#.##....#.#.#####\n\ .#......####....#...#\n\ ..##.###.##...#.##...\n\ .##.##.#..##.#.#.###.\n\ #...#.#.#.###.###.#.#\n\ ........##.#..#...#.#\n\ #######.#.#....#.##..\n\ #.....#..#.##.##.#...\n\ #.###.#.#.#...#######\n\ #.###.#..#.#.#.#...#.\n\ #.###.#.#...####.#..#\n\ #.....#.#.##.#...#.##\n\ #######.....####....#" ); } #[test] fn test_penalty_score_adjacent() { let c = create_test_canvas(); assert_eq!(c.compute_adjacent_penalty_score(true), 88); assert_eq!(c.compute_adjacent_penalty_score(false), 92); } #[test] fn test_penalty_score_block() { let c = create_test_canvas(); assert_eq!(c.compute_block_penalty_score(), 90); } #[test] fn test_penalty_score_finder() { let c = create_test_canvas(); assert_eq!(c.compute_finder_penalty_score(true), 0); assert_eq!(c.compute_finder_penalty_score(false), 40); } #[test] fn test_penalty_score_balance() { let c = create_test_canvas(); assert_eq!(c.compute_balance_penalty_score(), 2); } #[test] fn test_penalty_score_light_sides() { static HORIZONTAL_SIDE: [Color; 17] = [ Color::Dark, Color::Light, Color::Light, Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Light, Color::Dark, Color::Light, Color::Dark, Color::Light, Color::Light, Color::Dark, Color::Light, Color::Light, Color::Light, ]; static VERTICAL_SIDE: [Color; 17] = [ Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Light, Color::Dark, Color::Dark, Color::Light, Color::Dark, Color::Light, Color::Dark, Color::Light, Color::Dark, Color::Light, Color::Light, Color::Dark, Color::Light, ]; let mut c = Canvas::new(Version::Micro(4), EcLevel::Q); for i in 0_i16..17 { c.put(i, -1, HORIZONTAL_SIDE[i.as_usize()]); c.put(-1, i, VERTICAL_SIDE[i.as_usize()]); } assert_eq!(c.compute_light_side_penalty_score(), 168); } } //}}} //------------------------------------------------------------------------------ //{{{ Select mask with lowest penalty score static ALL_PATTERNS_QR: [MaskPattern; 8] = [ MaskPattern::Checkerboard, MaskPattern::HorizontalLines, MaskPattern::VerticalLines, MaskPattern::DiagonalLines, MaskPattern::LargeCheckerboard, MaskPattern::Fields, MaskPattern::Diamonds, MaskPattern::Meadow, ]; static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] = [MaskPattern::HorizontalLines, MaskPattern::LargeCheckerboard, MaskPattern::Diamonds, MaskPattern::Meadow]; impl Canvas { /// Construct a new canvas and apply the best masking that gives the lowest /// penalty score. #[must_use] pub fn apply_best_mask(&self) -> Self { match self.version { Version::Normal(_) => ALL_PATTERNS_QR.iter(), Version::Micro(_) => ALL_PATTERNS_MICRO_QR.iter(), } .map(|ptn| { let mut c = self.clone(); c.apply_mask(*ptn); c }) .min_by_key(Self::compute_total_penalty_scores) .expect("at least one pattern") } /// Convert the modules into a vector of booleans. #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")] pub fn to_bools(&self) -> Vec { self.modules.iter().map(|m| m.is_dark()).collect() } /// Convert the modules into a vector of colors. pub fn into_colors(self) -> Vec { self.modules.into_iter().map(Color::from).collect() } } //}}} //------------------------------------------------------------------------------ qrencode-0.14.0/src/cast.rs000064400000000000000000000042061046102023000135770ustar 00000000000000use std::fmt::Display; #[cfg(debug_assertions)] use checked_int_cast::CheckedIntCast; pub trait Truncate { fn truncate_as_u8(self) -> u8; } impl Truncate for u16 { #[allow(clippy::cast_possible_truncation)] fn truncate_as_u8(self) -> u8 { (self & 0xff) as u8 } } #[allow(clippy::wrong_self_convention)] pub trait As { fn as_u16(self) -> u16; fn as_i16(self) -> i16; fn as_u32(self) -> u32; fn as_usize(self) -> usize; fn as_isize(self) -> isize; } trait ExpectOrOverflow { type Output; fn expect_or_overflow(self, value: D, ty: &str) -> Self::Output; } impl ExpectOrOverflow for Option { type Output = T; fn expect_or_overflow(self, value: D, ty: &str) -> Self::Output { match self { Some(v) => v, None => panic!("{} overflows {}", value, ty), } } } macro_rules! impl_as { ($ty:ty) => { #[cfg(debug_assertions)] impl As for $ty { fn as_u16(self) -> u16 { self.as_u16_checked().expect_or_overflow(self, "u16") } fn as_i16(self) -> i16 { self.as_i16_checked().expect_or_overflow(self, "i16") } fn as_u32(self) -> u32 { self.as_u32_checked().expect_or_overflow(self, "u32") } fn as_usize(self) -> usize { self.as_usize_checked().expect_or_overflow(self, "usize") } fn as_isize(self) -> isize { self.as_isize_checked().expect_or_overflow(self, "usize") } } #[cfg(not(debug_assertions))] impl As for $ty { fn as_u16(self) -> u16 { self as u16 } fn as_i16(self) -> i16 { self as i16 } fn as_u32(self) -> u32 { self as u32 } fn as_usize(self) -> usize { self as usize } fn as_isize(self) -> isize { self as isize } } }; } impl_as!(i16); impl_as!(u32); impl_as!(usize); impl_as!(isize); qrencode-0.14.0/src/ec.rs000064400000000000000000000677741046102023000132570ustar 00000000000000//! The `ec` module applies the Reed-Solomon error correction codes. use std::ops::Deref; use crate::types::{EcLevel, QrResult, Version}; //------------------------------------------------------------------------------ //{{{ Error correction primitive /// Creates the error correction code in N bytes. /// /// This method only supports computing the error-correction code up to /// 69 bytes. Longer blocks will result in task panic. /// /// This method treats the data as a polynomial of the form /// (a\[0\] xm+n + a\[1\] xm+n-1 + … + a\[m\] xn) /// in GF(28), and then computes the polynomial modulus with a /// generator polynomial of degree N. pub fn create_error_correction_code(data: &[u8], ec_code_size: usize) -> Vec { let data_len = data.len(); let log_den = GENERATOR_POLYNOMIALS[ec_code_size]; let mut res = data.to_vec(); res.resize(ec_code_size + data_len, 0); // rust-lang-nursery/rust-clippy#2213 for i in 0..data_len { let lead_coeff = res[i] as usize; if lead_coeff == 0 { continue; } let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]); for (u, v) in res[i + 1..].iter_mut().zip(log_den.iter()) { *u ^= EXP_TABLE[(usize::from(*v) + log_lead_coeff) % 255]; } } res.split_off(data_len) } #[cfg(test)] mod ec_tests { use crate::ec::create_error_correction_code; #[test] fn test_poly_mod_1() { let res = create_error_correction_code(b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11", 10); assert_eq!(&*res, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17"); } #[test] fn test_poly_mod_2() { let res = create_error_correction_code(b" [\x0bx\xd1r\xdcMC@\xec\x11\xec", 13); assert_eq!(&*res, b"\xa8H\x16R\xd96\x9c\x00.\x0f\xb4z\x10"); } #[test] fn test_poly_mod_3() { let res = create_error_correction_code(b"CUF\x86W&U\xc2w2\x06\x12\x06g&", 18); assert_eq!(&*res, b"\xd5\xc7\x0b-s\xf7\xf1\xdf\xe5\xf8\x9au\x9aoV\xa1o'"); } } //}}} //------------------------------------------------------------------------------ //{{{ Interleave support /// This method interleaves a vector of slices into a single vector. /// /// It will first insert all the first elements of the slices in `blocks`, then /// all the second elements, then all the third elements, and so on. /// /// The longest slice must be at the last of `blocks`, and `blocks` must not be /// empty. fn interleave>(blocks: &[V]) -> Vec { let last_block_len = blocks.last().expect("non-empty blocks").len(); let mut res = Vec::with_capacity(last_block_len * blocks.len()); for i in 0..last_block_len { for t in blocks { if i < t.len() { res.push(t[i]); } } } res } #[test] fn test_interleave() { let res = interleave(&[&b"1234"[..], b"5678", b"abcdef", b"ghijkl"]); assert_eq!(&*res, b"15ag26bh37ci48djekfl"); } //}}} //------------------------------------------------------------------------------ //{{{ QR code error correction /// Constructs data and error correction codewords ready to be put in the QR /// code matrix. /// /// # Errors /// /// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the /// `ec_level` for the given version (e.g. `Version::Micro(1)` with /// `EcLevel::H`). pub fn construct_codewords(rawbits: &[u8], version: Version, ec_level: EcLevel) -> QrResult<(Vec, Vec)> { let (block_1_size, block_1_count, block_2_size, block_2_count) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?; let blocks_count = block_1_count + block_2_count; let block_1_end = block_1_size * block_1_count; let total_size = block_1_end + block_2_size * block_2_count; debug_assert_eq!(rawbits.len(), total_size); // Divide the data into blocks. let mut blocks = Vec::with_capacity(blocks_count); blocks.extend(rawbits[..block_1_end].chunks(block_1_size)); if block_2_size > 0 { blocks.extend(rawbits[block_1_end..].chunks(block_2_size)); } // Generate EC codes. let ec_bytes = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?; let ec_codes = blocks.iter().map(|block| create_error_correction_code(*block, ec_bytes)).collect::>>(); let blocks_vec = interleave(&blocks); let ec_vec = interleave(&ec_codes); Ok((blocks_vec, ec_vec)) } #[cfg(test)] mod construct_codewords_test { use crate::ec::construct_codewords; use crate::types::{EcLevel, Version}; #[test] fn test_add_ec_simple() { let msg = b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11"; let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(1), EcLevel::M).unwrap(); assert_eq!(&*blocks_vec, msg); assert_eq!(&*ec_vec, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17"); } #[test] fn test_add_ec_complex() { let msg = b"CUF\x86W&U\xc2w2\x06\x12\x06g&\xf6\xf6B\x07v\x86\xf2\x07&V\x16\xc6\xc7\x92\x06\ \xb6\xe6\xf7w2\x07v\x86W&R\x06\x86\x972\x07F\xf7vV\xc2\x06\x972\x10\xec\x11\xec\ \x11\xec\x11\xec"; let expected_blocks = b"C\xf6\xb6FU\xf6\xe6\xf7FB\xf7v\x86\x07wVWv2\xc2&\x86\x07\x06U\xf2v\ \x97\xc2\x07\x862w&W\x102V&\xec\x06\x16R\x11\x12\xc6\x06\xec\x06\ \xc7\x86\x11g\x92\x97\xec&\x062\x11\x07\xec"; let expected_ec = b"\xd5W\x94\xeb\xc7\xcct\x9f\x0b`\xb1\x05-<\xd4\xads\xcaL\x18\xf7\xb6\x85\ \x93\xf1|K;\xdf\x9d\xf2!\xe5\xc8\xeej\xf8\x86L(\x9a\x1b\xc3\xffu\x81\ \xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\ \x8d\xec"; let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap(); assert_eq!(&*blocks_vec, &expected_blocks[..]); assert_eq!(&*ec_vec, &expected_ec[..]); } } //}}} //------------------------------------------------------------------------------ //{{{ Number of allowed errors /// Computes the maximum allowed number of erratic modules can be introduced to /// the QR code, before the data becomes truly corrupted. /// /// # Errors /// /// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the /// `ec_level` for the given version (e.g. `Version::Micro(1)` with /// `EcLevel::H`). pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult { use crate::EcLevel::{L, M}; use crate::Version::{Micro, Normal}; let p = match (version, ec_level) { (Micro(2) | Normal(1), L) => 3, (Micro(_) | Normal(2), L) | (Micro(2) | Normal(1), M) => 2, (Normal(1), _) | (Normal(3), L) => 1, _ => 0, }; let ec_bytes_per_block = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?; let (_, count1, _, count2) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?; let ec_bytes = (count1 + count2) * ec_bytes_per_block; Ok((ec_bytes - p) / 2) } #[cfg(test)] mod max_allowed_errors_test { use crate::ec::max_allowed_errors; use crate::types::{EcLevel, Version}; #[test] fn test_low_versions() { assert_eq!(Ok(0), max_allowed_errors(Version::Micro(1), EcLevel::L)); assert_eq!(Ok(1), max_allowed_errors(Version::Micro(2), EcLevel::L)); assert_eq!(Ok(2), max_allowed_errors(Version::Micro(2), EcLevel::M)); assert_eq!(Ok(2), max_allowed_errors(Version::Micro(3), EcLevel::L)); assert_eq!(Ok(4), max_allowed_errors(Version::Micro(3), EcLevel::M)); assert_eq!(Ok(3), max_allowed_errors(Version::Micro(4), EcLevel::L)); assert_eq!(Ok(5), max_allowed_errors(Version::Micro(4), EcLevel::M)); assert_eq!(Ok(7), max_allowed_errors(Version::Micro(4), EcLevel::Q)); assert_eq!(Ok(2), max_allowed_errors(Version::Normal(1), EcLevel::L)); assert_eq!(Ok(4), max_allowed_errors(Version::Normal(1), EcLevel::M)); assert_eq!(Ok(6), max_allowed_errors(Version::Normal(1), EcLevel::Q)); assert_eq!(Ok(8), max_allowed_errors(Version::Normal(1), EcLevel::H)); assert_eq!(Ok(4), max_allowed_errors(Version::Normal(2), EcLevel::L)); assert_eq!(Ok(8), max_allowed_errors(Version::Normal(2), EcLevel::M)); assert_eq!(Ok(11), max_allowed_errors(Version::Normal(2), EcLevel::Q)); assert_eq!(Ok(14), max_allowed_errors(Version::Normal(2), EcLevel::H)); assert_eq!(Ok(7), max_allowed_errors(Version::Normal(3), EcLevel::L)); assert_eq!(Ok(13), max_allowed_errors(Version::Normal(3), EcLevel::M)); assert_eq!(Ok(18), max_allowed_errors(Version::Normal(3), EcLevel::Q)); assert_eq!(Ok(22), max_allowed_errors(Version::Normal(3), EcLevel::H)); assert_eq!(Ok(10), max_allowed_errors(Version::Normal(4), EcLevel::L)); assert_eq!(Ok(18), max_allowed_errors(Version::Normal(4), EcLevel::M)); assert_eq!(Ok(26), max_allowed_errors(Version::Normal(4), EcLevel::Q)); assert_eq!(Ok(32), max_allowed_errors(Version::Normal(4), EcLevel::H)); } #[test] fn test_high_versions() { assert_eq!(Ok(375), max_allowed_errors(Version::Normal(40), EcLevel::L)); assert_eq!(Ok(686), max_allowed_errors(Version::Normal(40), EcLevel::M)); assert_eq!(Ok(1020), max_allowed_errors(Version::Normal(40), EcLevel::Q)); assert_eq!(Ok(1215), max_allowed_errors(Version::Normal(40), EcLevel::H)); } } //}}} //------------------------------------------------------------------------------ //{{{ Precomputed tables for GF(256). /// `EXP_TABLE` encodes the value of 2n in the Galois Field GF(256). static EXP_TABLE: &[u8] = b"\ \x01\x02\x04\x08\x10\x20\x40\x80\x1d\x3a\x74\xe8\xcd\x87\x13\x26\ \x4c\x98\x2d\x5a\xb4\x75\xea\xc9\x8f\x03\x06\x0c\x18\x30\x60\xc0\ \x9d\x27\x4e\x9c\x25\x4a\x94\x35\x6a\xd4\xb5\x77\xee\xc1\x9f\x23\ \x46\x8c\x05\x0a\x14\x28\x50\xa0\x5d\xba\x69\xd2\xb9\x6f\xde\xa1\ \x5f\xbe\x61\xc2\x99\x2f\x5e\xbc\x65\xca\x89\x0f\x1e\x3c\x78\xf0\ \xfd\xe7\xd3\xbb\x6b\xd6\xb1\x7f\xfe\xe1\xdf\xa3\x5b\xb6\x71\xe2\ \xd9\xaf\x43\x86\x11\x22\x44\x88\x0d\x1a\x34\x68\xd0\xbd\x67\xce\ \x81\x1f\x3e\x7c\xf8\xed\xc7\x93\x3b\x76\xec\xc5\x97\x33\x66\xcc\ \x85\x17\x2e\x5c\xb8\x6d\xda\xa9\x4f\x9e\x21\x42\x84\x15\x2a\x54\ \xa8\x4d\x9a\x29\x52\xa4\x55\xaa\x49\x92\x39\x72\xe4\xd5\xb7\x73\ \xe6\xd1\xbf\x63\xc6\x91\x3f\x7e\xfc\xe5\xd7\xb3\x7b\xf6\xf1\xff\ \xe3\xdb\xab\x4b\x96\x31\x62\xc4\x95\x37\x6e\xdc\xa5\x57\xae\x41\ \x82\x19\x32\x64\xc8\x8d\x07\x0e\x1c\x38\x70\xe0\xdd\xa7\x53\xa6\ \x51\xa2\x59\xb2\x79\xf2\xf9\xef\xc3\x9b\x2b\x56\xac\x45\x8a\x09\ \x12\x24\x48\x90\x3d\x7a\xf4\xf5\xf7\xf3\xfb\xeb\xcb\x8b\x0b\x16\ \x2c\x58\xb0\x7d\xfa\xe9\xcf\x83\x1b\x36\x6c\xd8\xad\x47\x8e\x01"; /// `LOG_TABLE` is the inverse function of `EXP_TABLE`. static LOG_TABLE: &[u8] = b"\ \xff\x00\x01\x19\x02\x32\x1a\xc6\x03\xdf\x33\xee\x1b\x68\xc7\x4b\ \x04\x64\xe0\x0e\x34\x8d\xef\x81\x1c\xc1\x69\xf8\xc8\x08\x4c\x71\ \x05\x8a\x65\x2f\xe1\x24\x0f\x21\x35\x93\x8e\xda\xf0\x12\x82\x45\ \x1d\xb5\xc2\x7d\x6a\x27\xf9\xb9\xc9\x9a\x09\x78\x4d\xe4\x72\xa6\ \x06\xbf\x8b\x62\x66\xdd\x30\xfd\xe2\x98\x25\xb3\x10\x91\x22\x88\ \x36\xd0\x94\xce\x8f\x96\xdb\xbd\xf1\xd2\x13\x5c\x83\x38\x46\x40\ \x1e\x42\xb6\xa3\xc3\x48\x7e\x6e\x6b\x3a\x28\x54\xfa\x85\xba\x3d\ \xca\x5e\x9b\x9f\x0a\x15\x79\x2b\x4e\xd4\xe5\xac\x73\xf3\xa7\x57\ \x07\x70\xc0\xf7\x8c\x80\x63\x0d\x67\x4a\xde\xed\x31\xc5\xfe\x18\ \xe3\xa5\x99\x77\x26\xb8\xb4\x7c\x11\x44\x92\xd9\x23\x20\x89\x2e\ \x37\x3f\xd1\x5b\x95\xbc\xcf\xcd\x90\x87\x97\xb2\xdc\xfc\xbe\x61\ \xf2\x56\xd3\xab\x14\x2a\x5d\x9e\x84\x3c\x39\x53\x47\x6d\x41\xa2\ \x1f\x2d\x43\xd8\xb7\x7b\xa4\x76\xc4\x17\x49\xec\x7f\x0c\x6f\xf6\ \x6c\xa1\x3b\x52\x29\x9d\x55\xaa\xfb\x60\x86\xb1\xbb\xcc\x3e\x5a\ \xcb\x59\x5f\xb0\x9c\xa9\xa0\x51\x0b\xf5\x16\xeb\x7a\x75\x2c\xd7\ \x4f\xae\xd5\xe9\xe6\xe7\xad\xe8\x74\xd6\xf4\xea\xa8\x50\x58\xaf"; /// The generator polynomial list. /// /// `GENERATOR_POLYNOMIALS[i]` is the polynomial for `i` error correction code /// words. Each entry encodes the log coefficients of the expanded polynomial /// (x − 20)(x − 21)…(x − 2i-1). Each entry is /// used as the denominator for polynomial division to obtain the modulus which /// is the Reed-Solomon error correction code. /// /// A partial list can be found from ISO/IEC 18004:2006 Annex A. #[rustfmt::skip] // ^ this attribute is currently useless, see rust-lang-nursery/rustfmt#1080 and 1298 static GENERATOR_POLYNOMIALS: [&[u8]; 70] = [ b"", b"\x00", b"\x19\x01", b"\xc6\xc7\x03", b"\x4b\xf9\x4e\x06", b"\x71\xa4\xa6\x77\x0a", b"\xa6\x00\x86\x05\xb0\x0f", b"\x57\xe5\x92\x95\xee\x66\x15", b"\xaf\xee\xd0\xf9\xd7\xfc\xc4\x1c", b"\x5f\xf6\x89\xe7\xeb\x95\x0b\x7b\x24", b"\xfb\x43\x2e\x3d\x76\x46\x40\x5e\x20\x2d", b"\xdc\xc0\x5b\xc2\xac\xb1\xd1\x74\xe3\x0a\x37", b"\x66\x2b\x62\x79\xbb\x71\xc6\x8f\x83\x57\x9d\x42", b"\x4a\x98\xb0\x64\x56\x64\x6a\x68\x82\xda\xce\x8c\x4e", b"\xc7\xf9\x9b\x30\xbe\x7c\xda\x89\xd8\x57\xcf\x3b\x16\x5b", b"\x08\xb7\x3d\x5b\xca\x25\x33\x3a\x3a\xed\x8c\x7c\x05\x63\x69", b"\x78\x68\x6b\x6d\x66\xa1\x4c\x03\x5b\xbf\x93\xa9\xb6\xc2\xe1\x78", b"\x2b\x8b\xce\x4e\x2b\xef\x7b\xce\xd6\x93\x18\x63\x96\x27\xf3\xa3\x88", b"\xd7\xea\x9e\x5e\xb8\x61\x76\xaa\x4f\xbb\x98\x94\xfc\xb3\x05\x62\x60\x99", b"\x43\x03\x69\x99\x34\x5a\x53\x11\x96\x9f\x2c\x80\x99\x85\xfc\xde\x8a\xdc\xab", b"\x11\x3c\x4f\x32\x3d\xa3\x1a\xbb\xca\xb4\xdd\xe1\x53\xef\x9c\xa4\xd4\xd4\xbc\xbe", b"\xf0\xe9\x68\xf7\xb5\x8c\x43\x62\x55\xc8\xd2\x73\x94\x89\xe6\x24\x7a\xfe\x94\xaf\xd2", b"\xd2\xab\xf7\xf2\x5d\xe6\x0e\x6d\xdd\x35\xc8\x4a\x08\xac\x62\x50\xdb\x86\xa0\x69\xa5\xe7", b"\xab\x66\x92\x5b\x31\x67\x41\x11\xc1\x96\x0e\x19\xb7\xf8\x5e\xa4\xe0\xc0\x01\x4e\x38\x93\xfd", b"\xe5\x79\x87\x30\xd3\x75\xfb\x7e\x9f\xb4\xa9\x98\xc0\xe2\xe4\xda\x6f\x00\x75\xe8\x57\x60\xe3\x15", b"\xe7\xb5\x9c\x27\xaa\x1a\x0c\x3b\x0f\x94\xc9\x36\x42\xed\xd0\x63\xa7\x90\xb6\x5f\xf3\x81\xb2\xfc\x2d", b"\xad\x7d\x9e\x02\x67\xb6\x76\x11\x91\xc9\x6f\x1c\xa5\x35\xa1\x15\xf5\x8e\x0d\x66\x30\xe3\x99\x91\xda\x46", b"\x4f\xe4\x08\xa5\xe3\x15\xb4\x1d\x09\xed\x46\x63\x2d\x3a\x8a\x87\x49\x7e\xac\x5e\xd8\xc1\x9d\x1a\x11\x95\x60", b"\xa8\xdf\xc8\x68\xe0\xea\x6c\xb4\x6e\xbe\xc3\x93\xcd\x1b\xe8\xc9\x15\x2b\xf5\x57\x2a\xc3\xd4\x77\xf2\x25\x09\x7b", b"\x9c\x2d\xb7\x1d\x97\xdb\x36\x60\xf9\x18\x88\x05\xf1\xaf\xbd\x1c\x4b\xea\x96\x94\x17\x09\xca\xa2\x44\xfa\x8c\x18\x97", b"\x29\xad\x91\x98\xd8\x1f\xb3\xb6\x32\x30\x6e\x56\xef\x60\xde\x7d\x2a\xad\xe2\xc1\xe0\x82\x9c\x25\xfb\xd8\xee\x28\xc0\xb4", b"\x14\x25\xfc\x5d\x3f\x4b\xe1\x1f\x73\x53\x71\x27\x2c\x49\x7a\x89\x76\x77\x90\xf8\xf8\x37\x01\xe1\x69\x7b\xb7\x75\xbb\xc8\xd2", b"\x0a\x06\x6a\xbe\xf9\xa7\x04\x43\xd1\x8a\x8a\x20\xf2\x7b\x59\x1b\x78\xb9\x50\x9c\x26\x45\xab\x3c\x1c\xde\x50\x34\xfe\xb9\xdc\xf1", b"\xf5\xe7\x37\x18\x47\x4e\x4c\x51\xe1\xd4\xad\x25\xd7\x2e\x77\xe5\xf5\xa7\x7e\x48\xb5\x5e\xa5\xd2\x62\x7d\x9f\xb8\xa9\xe8\xb9\xe7\x12", b"\x6f\x4d\x92\x5e\x1a\x15\x6c\x13\x69\x5e\x71\xc1\x56\x8c\xa3\x7d\x3a\x9e\xe5\xef\xda\x67\x38\x46\x72\x3d\xb7\x81\xa7\x0d\x62\x3e\x81\x33", b"\x07\x5e\x8f\x51\xf7\x7f\xca\xca\xc2\x7d\x92\x1d\x8a\xa2\x99\x41\x69\x7a\x74\xee\x1a\x24\xd8\x70\x7d\xe4\x0f\x31\x08\xa2\x1e\x7e\x6f\x3a\x55", b"\xc8\xb7\x62\x10\xac\x1f\xf6\xea\x3c\x98\x73\x00\xa7\x98\x71\xf8\xee\x6b\x12\x3f\xda\x25\x57\xd2\x69\xb1\x78\x4a\x79\xc4\x75\xfb\x71\xe9\x1e\x78", b"\x9a\x4b\x8d\xb4\x3d\xa5\x68\xe8\x2e\xe3\x60\xb2\x5c\x87\x39\xa2\x78\xc2\xd4\xae\xfc\xb7\x2a\x23\x9d\x6f\x17\x85\x64\x08\x69\x25\xc0\xbd\x9f\x13\x9c", b"\x9f\x22\x26\xe4\xe6\x3b\xf3\x5f\x31\xda\xb0\xa4\x14\x41\x2d\x6f\x27\x51\x31\x76\x71\xde\xc1\xfa\xf2\xa8\xd9\x29\xa4\xf7\xb1\x1e\xee\x12\x78\x99\x3c\xc1", b"\x51\xd8\xae\x2f\xc8\x96\x3b\x9c\x59\x8f\x59\xa6\xb7\xaa\x98\x15\xa5\xb1\x71\x84\xea\x05\x9a\x44\x7c\xaf\xc4\x9d\xf9\xe9\x53\x18\x99\xf1\x7e\x24\x74\x13\xe7", b"\x3b\x74\x4f\xa1\xfc\x62\x80\xcd\x80\xa1\xf7\x39\xa3\x38\xeb\x6a\x35\x1a\xbb\xae\xe2\x68\xaa\x07\xaf\x23\xb5\x72\x58\x29\x2f\xa3\x7d\x86\x48\x14\xe8\x35\x23\x0f", b"\x84\xa7\x34\x8b\xb8\xdf\x95\x5c\xfa\x12\x53\x21\x7f\x6d\xc2\x07\xd3\xf2\x6d\x42\x56\xa9\x57\x60\xbb\x9f\x72\xac\x76\xd0\xb7\xc8\x52\xb3\x26\x27\x22\xf2\x8e\x93\x37", b"\xfa\x67\xdd\xe6\x19\x12\x89\xe7\x00\x03\x3a\xf2\xdd\xbf\x6e\x54\xe6\x08\xbc\x6a\x60\x93\x0f\x83\x8b\x22\x65\xdf\x27\x65\xd5\xc7\xed\xfe\xc9\x7b\xab\xa2\xc2\x75\x32\x60", b"\x60\x43\x03\xf5\xd9\xd7\x21\x41\xf0\x6d\x90\x3f\x15\x83\x26\x65\x99\x80\x37\x1f\xed\x03\x5e\xa0\x14\x57\x4d\x38\xbf\x7b\xcf\x4b\x52\x00\x7a\x84\x65\x91\xd7\x0f\x79\xc0\x8a", b"\xbe\x07\x3d\x79\x47\xf6\x45\x37\xa8\xbc\x59\xf3\xbf\x19\x48\x7b\x09\x91\x0e\xf7\x01\xee\x2c\x4e\x8f\x3e\xe0\x7e\x76\x72\x44\xa3\x34\xc2\xd9\x93\xcc\xa9\x25\x82\x71\x66\x49\xb5", b"\x06\xac\x48\xfa\x12\xab\xab\xa2\xe5\xbb\xef\x04\xbb\x0b\x25\xe4\x66\x48\x66\x16\x21\x49\x5f\x63\x84\x01\x0f\x59\x04\x70\x82\x5f\xd3\xeb\xe3\x3a\x23\x58\x84\x17\x2c\xa5\x36\xbb\xe1", b"\x70\x5e\x58\x70\xfd\xe0\xca\x73\xbb\x63\x59\x05\x36\x71\x81\x2c\x3a\x10\x87\xd8\xa9\xd3\x24\x01\x04\x60\x3c\xf1\x49\x68\xea\x08\xf9\xf5\x77\xae\x34\x19\x9d\xe0\x2b\xca\xdf\x13\x52\x0f", b"\x4c\xa4\xe5\x5c\x4f\xa8\xdb\x6e\x68\x15\xdc\x4a\x13\xc7\xc3\x64\x5d\xbf\x2b\xd5\x48\x38\x8a\xa1\x7d\xbb\x77\xfa\xbd\x89\xbe\x4c\x7e\xf7\x5d\x1e\x84\x06\x3a\xd5\xd0\xa5\xe0\x98\x85\x5b\x3d", b"\xe4\x19\xc4\x82\xd3\x92\x3c\x18\xfb\x5a\x27\x66\xf0\x3d\xb2\x3f\x2e\x7b\x73\x12\xdd\x6f\x87\xa0\xb6\xcd\x6b\xce\x5f\x96\x78\xb8\x5b\x15\xf7\x9c\x8c\xee\xbf\x0b\x5e\xe3\x54\x32\xa3\x27\x22\x6c", b"\xac\x79\x01\x29\xc1\xde\xed\x40\x6d\xb5\x34\x78\xd4\xe2\xef\xf5\xd0\x14\xf6\x22\xe1\xcc\x86\x65\x7d\xce\x45\x8a\xfa\x00\x4d\x3a\x8f\xb9\xdc\xfe\xd2\xbe\x70\x58\x5b\x39\x5a\x6d\x05\x0d\xb5\x19\x9c", b"\xe8\x7d\x9d\xa1\xa4\x09\x76\x2e\xd1\x63\xcb\xc1\x23\x03\xd1\x6f\xc3\xf2\xcb\xe1\x2e\x0d\x20\xa0\x7e\xd1\x82\xa0\xf2\xd7\xf2\x4b\x4d\x2a\xbd\x20\x71\x41\x7c\x45\xe4\x72\xeb\xaf\x7c\xaa\xd7\xe8\x85\xcd", b"\xd5\xa6\x8e\x2b\x0a\xd8\x8d\xa3\xac\xb4\x66\x46\x59\x3e\xde\x3e\x2a\xd2\x97\xa3\xda\x46\x4d\x27\xa6\xbf\x72\xca\xf5\xbc\xb7\xdd\x4b\xd4\x1b\xed\x7f\xcc\xeb\x3e\xbe\xe8\x12\x2e\xab\x0f\x62\xf7\x42\xa3\x00", b"\x74\x32\x56\xba\x32\xdc\xfb\x59\xc0\x2e\x56\x7f\x7c\x13\xb8\xe9\x97\xd7\x16\x0e\x3b\x91\x25\xf2\xcb\x86\xfe\x59\xbe\x5e\x3b\x41\x7c\x71\x64\xe9\xeb\x79\x16\x4c\x56\x61\x27\xf2\xc8\xdc\x65\x21\xef\xfe\x74\x33", b"\x7a\xd6\xe7\x88\xc7\x0b\x06\xcd\x7c\x48\xd5\x75\xbb\x3c\x93\xc9\x49\x4b\x21\x92\xab\xf7\x76\xd0\x9d\xb1\xcb\xeb\x53\x2d\xe2\xca\xe5\xa8\x07\x39\xed\xeb\xc8\x7c\x6a\xfe\xa5\x0e\x93\x00\x39\x2a\x1f\xb2\xd5\xad\x67", b"\xb7\x1a\xc9\x57\xd2\xdd\x71\x15\x2e\x41\x2d\x32\xee\xb8\xf9\xe1\x66\x3a\xd1\xda\x6d\xa5\x1a\x5f\xb8\xc0\x34\xf5\x23\xfe\xee\xaf\xac\x4f\x7b\x19\x7a\x2b\x78\x6c\xd7\x50\x80\xc9\xeb\x08\x99\x3b\x65\x1f\xc6\x4c\x1f\x9c", b"\x26\xc5\x7b\xa7\x10\x57\xb2\xee\xe3\x61\x94\xf7\x1a\x5a\xe4\xb6\xec\xc5\x2f\xf9\x24\xd5\x36\x71\xb5\x4a\xb1\xcc\x9b\x3d\x2f\x2a\x00\x84\x90\xfb\xc8\x26\x26\x8a\x36\x2c\x40\x13\x16\xce\x10\x0a\xe4\xd3\xa1\xab\x2c\xc2\xd2", b"\x6a\x78\x6b\x9d\xa4\xd8\x70\x74\x02\x5b\xf8\xa3\x24\xc9\xca\xe5\x06\x90\xfe\x9b\x87\xd0\xaa\xd1\x0c\x8b\x7f\x8e\xb6\xf9\xb1\xae\xbe\x1c\x0a\x55\xef\xb8\x65\x7c\x98\xce\x60\x17\xa3\x3d\x1b\xc4\xf7\x97\x9a\xca\xcf\x14\x3d\x0a", b"\x3a\x8c\xed\x5d\x6a\x3d\xc1\x02\x57\x49\xc2\xd7\x9f\xa3\x0a\x9b\x05\x79\x99\x3b\xf8\x04\x75\x16\x3c\xb1\x90\x2c\x48\xe4\x3e\x01\x13\xaa\x71\x9e\x19\xaf\xc7\x8b\x5a\x01\xd2\x07\x77\x9a\x59\x9f\x82\x7a\x2e\x93\xbe\x87\x5e\x44\x42", b"\x52\x74\x1a\xf7\x42\x1b\x3e\x6b\xfc\xb6\xc8\xb9\xeb\x37\xfb\xf2\xd2\x90\x9a\xed\xb0\x8d\xc0\xf8\x98\xf9\xce\x55\xfd\x8e\x41\xa5\x7d\x17\x18\x1e\x7a\xf0\xd6\x06\x81\xda\x1d\x91\x7f\x86\xce\xf5\x75\x1d\x29\x3f\x9f\x8e\xe9\x7d\x94\x7b", b"\x39\x73\xe8\x0b\xc3\xd9\x03\xce\x4d\x43\x1d\xa6\xb4\x6a\x76\xcb\x11\x45\x98\xd5\x4a\x2c\x31\x2b\x62\x3d\xfd\x7a\x0e\x2b\xd1\x8f\x09\x68\x6b\xab\xe0\x39\xfe\xfb\xe2\xe8\xdd\xc2\xf0\x75\xa1\x52\xb2\xf6\xb2\x21\x32\x56\xd7\xef\xb4\xb4\xb5", b"\x6b\x8c\x1a\x0c\x09\x8d\xf3\xc5\xe2\xc5\xdb\x2d\xd3\x65\xdb\x78\x1c\xb5\x7f\x06\x64\xf7\x02\xcd\xc6\x39\x73\xdb\x65\x6d\xa0\x52\x25\x26\xee\x31\xa0\xd1\x79\x56\x0b\x7c\x1e\xb5\x54\x19\xc2\x57\x41\x66\xbe\xdc\x46\x1b\xd1\x10\x59\x07\x21\xf0", b"\xa1\xf4\x69\x73\x40\x09\xdd\xec\x10\x91\x94\x22\x90\xba\x0d\x14\xfe\xf6\x26\x23\xca\x48\x04\xd4\x9f\xd3\xa5\x87\xfc\xfa\x19\x57\x1e\x78\xe2\xea\x5c\xc7\x48\x07\x9b\xda\xe7\x2c\x7d\xb2\x9c\xae\x7c\x2b\x64\x1f\x38\x65\xcc\x40\xaf\xe1\xa9\x92\x2d", b"\x41\xca\x71\x62\x47\xdf\xf8\x76\xd6\x5e\x00\x7a\x25\x17\x02\xe4\x3a\x79\x07\x69\x87\x4e\xf3\x76\x46\x4c\xdf\x59\x48\x32\x46\x6f\xc2\x11\xd4\x7e\xb5\x23\xdd\x75\xeb\x0b\xe5\x95\x93\x7b\xd5\x28\x73\x06\xc8\x64\x1a\xf6\xb6\xda\x7f\xd7\x24\xba\x6e\x6a", b"\x1e\x47\x24\x47\x13\xc3\xac\x6e\x3d\x02\xa9\xc2\x5a\x88\x3b\xb6\xe7\x91\x66\x27\xaa\xe7\xd6\x43\xc4\xcf\x35\x70\xf6\x5a\x5a\x79\xb7\x92\x4a\x4d\x26\x59\x16\xe7\x37\x38\xf2\x70\xd9\x6e\x7b\x3e\xc9\xd9\x80\xa5\x3c\xb5\x25\xa1\xf6\x84\xf6\x12\x73\x88\xa8", b"\x2d\x33\xaf\x09\x07\x9e\x9f\x31\x44\x77\x5c\x7b\xb1\xcc\xbb\xfe\xc8\x4e\x8d\x95\x77\x1a\x7f\x35\xa0\x5d\xc7\xd4\x1d\x18\x91\x9c\xd0\x96\xda\xd1\x04\xd8\x5b\x2f\xb8\x92\x2f\x8c\xc3\xc3\x7d\xf2\xee\x3f\x63\x6c\x8c\xe6\xf2\x1f\xcc\x0b\xb2\xf3\xd9\x9c\xd5\xe7", b"\x89\x9e\xf7\xf0\x25\xee\xd6\x80\x63\xda\x2e\x8a\xc6\x80\x5c\xdb\x6d\x8b\xa6\x19\x42\x43\x0e\x3a\xee\x95\xb1\xc3\xdd\x9a\xab\x30\x50\x0c\x3b\xbe\xe4\x13\x37\xd0\x5c\x70\xe5\x25\x3c\x0a\x2f\x51\x00\xc0\x25\xab\xaf\x93\x80\x49\xa6\x3d\x95\x0c\x18\x5f\x46\x71\x28", b"\x05\x76\xde\xb4\x88\x88\xa2\x33\x2e\x75\x0d\xd7\x51\x11\x8b\xf7\xc5\xab\x5f\xad\x41\x89\xb2\x44\x6f\x5f\x65\x29\x48\xd6\xa9\xc5\x5f\x07\x2c\x9a\x4d\x6f\xec\x28\x79\x8f\x3f\x57\x50\xfd\xf0\x7e\xd9\x4d\x22\xe8\x6a\x32\xa8\x52\x4c\x92\x43\x6a\xab\x19\x84\x5d\x2d\x69", b"\xbf\xac\x71\x56\x07\xa6\xf6\xb9\x9b\xfa\x62\x71\x59\x56\xd6\xe1\x9c\xbe\x3a\x21\x90\x43\xb3\xa3\x34\x9a\xe9\x97\x68\xfb\xa0\x7e\xaf\xd0\xe1\x46\xe3\x92\x04\x98\x8b\x67\x19\x6b\x3d\xcc\x9f\xfa\xc1\xe1\x69\xa0\x62\xa7\x02\x35\x10\xf2\x53\xd2\xc4\x67\xf8\x56\xd3\x29\xab", b"\xf7\x9f\xdf\x21\xe0\x5d\x4d\x46\x5a\xa0\x20\xfe\x2b\x96\x54\x65\xbe\xcd\x85\x34\x3c\xca\xa5\xdc\xcb\x97\x5d\x54\x0f\x54\xfd\xad\xa0\x59\xe3\x34\xc7\x61\x5f\xe7\x34\xb1\x29\x7d\x89\xf1\xa6\xe1\x76\x02\x36\x20\x52\xd7\xaf\xc6\x2b\xee\xeb\x1b\x65\xb8\x7f\x03\x05\x08\xa3\xee", b"\x69\x49\x44\x01\x1d\xa8\x75\x0e\x58\xd0\x37\x2e\x2a\xd9\x06\x54\xb3\x61\x06\xf0\xc0\xe7\x9e\x40\x76\xa0\xcb\x39\x3d\x6c\xc7\x7c\x41\xbb\xdd\xa7\x27\xb6\x9f\xb4\xf4\xcb\xe4\xfe\x0d\xaf\x3d\x5a\xce\x28\xc7\x5e\x43\x39\x51\xe5\x2e\x7b\x59\x25\x1f\xca\x42\xfa\x23\xaa\xf3\x58\x33", ]; //}}} //------------------------------------------------------------------------------ //{{{ Tables for error correction sizes /// `EC_BYTES_PER_BLOCK` provides the number of codewords (bytes) used for error /// correction per block in each version. /// /// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9 (The 4th column divide /// by the sum of the 6th column). static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [ // Normal versions. [7, 10, 13, 17], // 1 [10, 16, 22, 28], // 2 [15, 26, 18, 22], // 3 [20, 18, 26, 16], // 4 [26, 24, 18, 22], // 5 [18, 16, 24, 28], // 6 [20, 18, 18, 26], // 7 [24, 22, 22, 26], // 8 [30, 22, 20, 24], // 9 [18, 26, 24, 28], // 10 [20, 30, 28, 24], // 11 [24, 22, 26, 28], // 12 [26, 22, 24, 22], // 13 [30, 24, 20, 24], // 14 [22, 24, 30, 24], // 15 [24, 28, 24, 30], // 16 [28, 28, 28, 28], // 17 [30, 26, 28, 28], // 18 [28, 26, 26, 26], // 19 [28, 26, 30, 28], // 20 [28, 26, 28, 30], // 21 [28, 28, 30, 24], // 22 [30, 28, 30, 30], // 23 [30, 28, 30, 30], // 24 [26, 28, 30, 30], // 25 [28, 28, 28, 30], // 26 [30, 28, 30, 30], // 27 [30, 28, 30, 30], // 28 [30, 28, 30, 30], // 29 [30, 28, 30, 30], // 30 [30, 28, 30, 30], // 31 [30, 28, 30, 30], // 32 [30, 28, 30, 30], // 33 [30, 28, 30, 30], // 34 [30, 28, 30, 30], // 35 [30, 28, 30, 30], // 36 [30, 28, 30, 30], // 37 [30, 28, 30, 30], // 38 [30, 28, 30, 30], // 39 [30, 28, 30, 30], // 40 // Micro versions. [2, 0, 0, 0], // M1 [5, 6, 0, 0], // M2 [6, 8, 0, 0], // M3 [8, 10, 14, 0], // M4 ]; /// `DATA_BYTES_PER_BLOCK` provides the number of codewords (bytes) used for /// real data per block in each version. /// /// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9 (The value "k" of the /// 7th column, followed by the 6th column). /// /// Every entry is a 4-tuple. Take `DATA_BYTES_PER_BLOCK[39][3] == (15, 20, 16, 61)` /// as an example, this means in version 40 with correction level H, there are /// 20 blocks with 15 bytes in size, and 61 blocks with 16 bytes in size. static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [ // Normal versions. [(19, 1, 0, 0), (16, 1, 0, 0), (13, 1, 0, 0), (9, 1, 0, 0)], // 1 [(34, 1, 0, 0), (28, 1, 0, 0), (22, 1, 0, 0), (16, 1, 0, 0)], // 2 [(55, 1, 0, 0), (44, 1, 0, 0), (17, 2, 0, 0), (13, 2, 0, 0)], // 3 [(80, 1, 0, 0), (32, 2, 0, 0), (24, 2, 0, 0), (9, 4, 0, 0)], // 4 [(108, 1, 0, 0), (43, 2, 0, 0), (15, 2, 16, 2), (11, 2, 12, 2)], // 5 [(68, 2, 0, 0), (27, 4, 0, 0), (19, 4, 0, 0), (15, 4, 0, 0)], // 6 [(78, 2, 0, 0), (31, 4, 0, 0), (14, 2, 15, 4), (13, 4, 14, 1)], // 7 [(97, 2, 0, 0), (38, 2, 39, 2), (18, 4, 19, 2), (14, 4, 15, 2)], // 8 [(116, 2, 0, 0), (36, 3, 37, 2), (16, 4, 17, 4), (12, 4, 13, 4)], // 9 [(68, 2, 69, 2), (43, 4, 44, 1), (19, 6, 20, 2), (15, 6, 16, 2)], // 10 [(81, 4, 0, 0), (50, 1, 51, 4), (22, 4, 23, 4), (12, 3, 13, 8)], // 11 [(92, 2, 93, 2), (36, 6, 37, 2), (20, 4, 21, 6), (14, 7, 15, 4)], // 12 [(107, 4, 0, 0), (37, 8, 38, 1), (20, 8, 21, 4), (11, 12, 12, 4)], // 13 [(115, 3, 116, 1), (40, 4, 41, 5), (16, 11, 17, 5), (12, 11, 13, 5)], // 14 [(87, 5, 88, 1), (41, 5, 42, 5), (24, 5, 25, 7), (12, 11, 13, 7)], // 15 [(98, 5, 99, 1), (45, 7, 46, 3), (19, 15, 20, 2), (15, 3, 16, 13)], // 16 [(107, 1, 108, 5), (46, 10, 47, 1), (22, 1, 23, 15), (14, 2, 15, 17)], // 17 [(120, 5, 121, 1), (43, 9, 44, 4), (22, 17, 23, 1), (14, 2, 15, 19)], // 18 [(113, 3, 114, 4), (44, 3, 45, 11), (21, 17, 22, 4), (13, 9, 14, 16)], // 19 [(107, 3, 108, 5), (41, 3, 42, 13), (24, 15, 25, 5), (15, 15, 16, 10)], // 20 [(116, 4, 117, 4), (42, 17, 0, 0), (22, 17, 23, 6), (16, 19, 17, 6)], // 21 [(111, 2, 112, 7), (46, 17, 0, 0), (24, 7, 25, 16), (13, 34, 0, 0)], // 22 [(121, 4, 122, 5), (47, 4, 48, 14), (24, 11, 25, 14), (15, 16, 16, 14)], // 23 [(117, 6, 118, 4), (45, 6, 46, 14), (24, 11, 25, 16), (16, 30, 17, 2)], // 24 [(106, 8, 107, 4), (47, 8, 48, 13), (24, 7, 25, 22), (15, 22, 16, 13)], // 25 [(114, 10, 115, 2), (46, 19, 47, 4), (22, 28, 23, 6), (16, 33, 17, 4)], // 26 [(122, 8, 123, 4), (45, 22, 46, 3), (23, 8, 24, 26), (15, 12, 16, 28)], // 27 [(117, 3, 118, 10), (45, 3, 46, 23), (24, 4, 25, 31), (15, 11, 16, 31)], // 28 [(116, 7, 117, 7), (45, 21, 46, 7), (23, 1, 24, 37), (15, 19, 16, 26)], // 29 [(115, 5, 116, 10), (47, 19, 48, 10), (24, 15, 25, 25), (15, 23, 16, 25)], // 30 [(115, 13, 116, 3), (46, 2, 47, 29), (24, 42, 25, 1), (15, 23, 16, 28)], // 31 [(115, 17, 0, 0), (46, 10, 47, 23), (24, 10, 25, 35), (15, 19, 16, 35)], // 32 [(115, 17, 116, 1), (46, 14, 47, 21), (24, 29, 25, 19), (15, 11, 16, 46)], // 33 [(115, 13, 116, 6), (46, 14, 47, 23), (24, 44, 25, 7), (16, 59, 17, 1)], // 34 [(121, 12, 122, 7), (47, 12, 48, 26), (24, 39, 25, 14), (15, 22, 16, 41)], // 35 [(121, 6, 122, 14), (47, 6, 48, 34), (24, 46, 25, 10), (15, 2, 16, 64)], // 36 [(122, 17, 123, 4), (46, 29, 47, 14), (24, 49, 25, 10), (15, 24, 16, 46)], // 37 [(122, 4, 123, 18), (46, 13, 47, 32), (24, 48, 25, 14), (15, 42, 16, 32)], // 38 [(117, 20, 118, 4), (47, 40, 48, 7), (24, 43, 25, 22), (15, 10, 16, 67)], // 39 [(118, 19, 119, 6), (47, 18, 48, 31), (24, 34, 25, 34), (15, 20, 16, 61)], // 40 // Micro versions. [(3, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M1 [(5, 1, 0, 0), (4, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M2 [(11, 1, 0, 0), (9, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M3 [(16, 1, 0, 0), (14, 1, 0, 0), (10, 1, 0, 0), (0, 0, 0, 0)], // M4 ]; //}}} qrencode-0.14.0/src/lib.rs000064400000000000000000000311641046102023000134160ustar 00000000000000//! QRCode encoder //! //! This crate provides a QR code and Micro QR code encoder for binary data. //! #![cfg_attr(feature = "image", doc = "```rust")] #![cfg_attr(not(feature = "image"), doc = "```ignore")] //! use qrencode::QrCode; //! use image::Luma; //! //! // Encode some data into bits. //! let code = QrCode::new(b"01234567").unwrap(); //! //! // Render the bits into an image. //! let image = code.render::>().build(); //! //! // Save the image. //! # if cfg!(unix) { //! image.save("/tmp/qrcode.png").unwrap(); //! # } //! //! // You can also render it into a string. //! let string = code.render() //! .light_color(' ') //! .dark_color('#') //! .build(); //! println!("{}", string); //! ``` #![cfg_attr(feature = "bench", feature(test, external_doc))] // Unstable libraries #![deny(warnings, clippy::pedantic)] #![allow( clippy::must_use_candidate, // This is just annoying. )] #![cfg_attr(feature = "bench", doc(include = "../README.md"))] // ^ make sure we can test our README.md. use std::ops::Index; pub mod bits; pub mod canvas; mod cast; pub mod ec; pub mod optimize; pub mod render; pub mod types; pub use crate::types::{Color, EcLevel, QrResult, Version}; use crate::cast::As; use crate::render::{Pixel, Renderer}; use checked_int_cast::CheckedIntCast; /// The encoded QR code symbol. #[derive(Clone)] pub struct QrCode { content: Vec, version: Version, ec_level: EcLevel, width: usize, } impl QrCode { /// Constructs a new QR code which automatically encodes the given data. /// /// This method uses the "medium" error correction level and automatically /// chooses the smallest QR code. /// /// use qrencode::QrCode; /// /// let code = QrCode::new(b"Some data").unwrap(); /// /// # Errors /// /// Returns error if the QR code cannot be constructed, e.g. when the data /// is too long. pub fn new>(data: D) -> QrResult { Self::with_error_correction_level(data, EcLevel::M) } /// Constructs a new QR code which automatically encodes the given data at a /// specific error correction level. /// /// This method automatically chooses the smallest QR code. /// /// use qrencode::{QrCode, EcLevel}; /// /// let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap(); /// /// # Errors /// /// Returns error if the QR code cannot be constructed, e.g. when the data /// is too long. pub fn with_error_correction_level>(data: D, ec_level: EcLevel) -> QrResult { let bits = bits::encode_auto(data.as_ref(), ec_level)?; Self::with_bits(bits, ec_level) } /// Constructs a new QR code for the given version and error correction /// level. /// /// use qrencode::{QrCode, Version, EcLevel}; /// /// let code = QrCode::with_version(b"Some data", Version::Normal(5), EcLevel::M).unwrap(); /// /// This method can also be used to generate Micro QR code. /// /// use qrencode::{QrCode, Version, EcLevel}; /// /// let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap(); /// /// # Errors /// /// Returns error if the QR code cannot be constructed, e.g. when the data /// is too long, or when the version and error correction level are /// incompatible. pub fn with_version>(data: D, version: Version, ec_level: EcLevel) -> QrResult { let mut bits = bits::Bits::new(version); bits.push_optimal_data(data.as_ref())?; bits.push_terminator(ec_level)?; Self::with_bits(bits, ec_level) } /// Constructs a new QR code with encoded bits. /// /// Use this method only if there are very special need to manipulate the /// raw bits before encoding. Some examples are: /// /// * Encode data using specific character set with ECI /// * Use the FNC1 modes /// * Avoid the optimal segmentation algorithm /// /// See the `Bits` structure for detail. /// /// #![allow(unused_must_use)] /// /// use qrencode::{QrCode, Version, EcLevel}; /// use qrencode::bits::Bits; /// /// let mut bits = Bits::new(Version::Normal(1)); /// bits.push_eci_designator(9); /// bits.push_byte_data(b"\xca\xfe\xe4\xe9\xea\xe1\xf2 QR"); /// bits.push_terminator(EcLevel::L); /// let qrcode = QrCode::with_bits(bits, EcLevel::L); /// /// # Errors /// /// Returns error if the QR code cannot be constructed, e.g. when the bits /// are too long, or when the version and error correction level are /// incompatible. pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult { let version = bits.version(); let data = bits.into_bytes(); let (encoded_data, ec_data) = ec::construct_codewords(&*data, version, ec_level)?; let mut canvas = canvas::Canvas::new(version, ec_level); canvas.draw_all_functional_patterns(); canvas.draw_data(&*encoded_data, &*ec_data); let canvas = canvas.apply_best_mask(); Ok(Self { content: canvas.into_colors(), version, ec_level, width: version.width().as_usize() }) } /// Gets the version of this QR code. pub fn version(&self) -> Version { self.version } /// Gets the error correction level of this QR code. pub fn error_correction_level(&self) -> EcLevel { self.ec_level } /// Gets the number of modules per side, i.e. the width of this QR code. /// /// The width here does not contain the quiet zone paddings. pub fn width(&self) -> usize { self.width } /// Gets the maximum number of allowed erratic modules can be introduced /// before the data becomes corrupted. Note that errors should not be /// introduced to functional modules. pub fn max_allowed_errors(&self) -> usize { ec::max_allowed_errors(self.version, self.ec_level).expect("invalid version or ec_level") } /// Checks whether a module at coordinate (x, y) is a functional module or /// not. pub fn is_functional(&self, x: usize, y: usize) -> bool { let x = x.as_i16_checked().expect("coordinate is too large for QR code"); let y = y.as_i16_checked().expect("coordinate is too large for QR code"); canvas::is_functional(self.version, self.version.width(), x, y) } /// Converts the QR code into a human-readable string. This is mainly for /// debugging only. pub fn to_debug_str(&self, on_char: char, off_char: char) -> String { self.render().quiet_zone(false).dark_color(on_char).light_color(off_char).build() } /// Converts the QR code to a vector of booleans. Each entry represents the /// color of the module, with "true" means dark and "false" means light. #[deprecated(since = "0.4.0", note = "use `to_colors()` instead")] pub fn to_vec(&self) -> Vec { self.content.iter().map(|c| *c != Color::Light).collect() } /// Converts the QR code to a vector of booleans. Each entry represents the /// color of the module, with "true" means dark and "false" means light. #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")] pub fn into_vec(self) -> Vec { self.content.into_iter().map(|c| c != Color::Light).collect() } /// Converts the QR code to a vector of colors. pub fn to_colors(&self) -> Vec { self.content.clone() } /// Converts the QR code to a vector of colors. pub fn into_colors(self) -> Vec { self.content } /// Renders the QR code into an image. The result is an image builder, which /// you may do some additional configuration before copying it into a /// concrete image. /// /// # Examples /// #[cfg_attr(feature = "image", doc = " ```rust")] #[cfg_attr(not(feature = "image"), doc = " ```ignore")] /// # use qrencode::QrCode; /// # use image::Rgb; /// /// let image = QrCode::new(b"hello").unwrap() /// .render() /// .dark_color(Rgb([0, 0, 128])) /// .light_color(Rgb([224, 224, 224])) // adjust colors /// .quiet_zone(false) // disable quiet zone (white border) /// .min_dimensions(300, 300) // sets minimum image size /// .build(); /// ``` /// /// Note: the `image` crate itself also provides method to rotate the image, /// or overlay a logo on top of the QR code. pub fn render(&self) -> Renderer

{ let quiet_zone = if self.version.is_micro() { 2 } else { 4 }; Renderer::new(&self.content, self.width, quiet_zone) } } impl Index<(usize, usize)> for QrCode { type Output = Color; fn index(&self, (x, y): (usize, usize)) -> &Color { let index = y * self.width + x; &self.content[index] } } #[cfg(test)] mod tests { use crate::{EcLevel, QrCode, Version}; #[test] fn test_annex_i_qr() { // This uses the ISO Annex I as test vector. let code = QrCode::with_version(b"01234567", Version::Normal(1), EcLevel::M).unwrap(); assert_eq!( &*code.to_debug_str('#', '.'), "\ #######..#.##.#######\n\ #.....#..####.#.....#\n\ #.###.#.#.....#.###.#\n\ #.###.#.##....#.###.#\n\ #.###.#.#.###.#.###.#\n\ #.....#.#...#.#.....#\n\ #######.#.#.#.#######\n\ ........#..##........\n\ #.#####..#..#.#####..\n\ ...#.#.##.#.#..#.##..\n\ ..#...##.#.#.#..#####\n\ ....#....#.....####..\n\ ...######..#.#..#....\n\ ........#.#####..##..\n\ #######..##.#.##.....\n\ #.....#.#.#####...#.#\n\ #.###.#.#...#..#.##..\n\ #.###.#.##..#..#.....\n\ #.###.#.#.##.#..#.#..\n\ #.....#........##.##.\n\ #######.####.#..#.#.." ); } #[test] fn test_annex_i_micro_qr() { let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); assert_eq!( &*code.to_debug_str('#', '.'), "\ #######.#.#.#\n\ #.....#.###.#\n\ #.###.#..##.#\n\ #.###.#..####\n\ #.###.#.###..\n\ #.....#.#...#\n\ #######..####\n\ .........##..\n\ ##.#....#...#\n\ .##.#.#.#.#.#\n\ ###..#######.\n\ ...#.#....##.\n\ ###.#..##.###" ); } } #[cfg(all(test, feature = "image"))] mod image_tests { use crate::{EcLevel, QrCode, Version}; use image::{load_from_memory, Luma, Rgb}; #[test] fn test_annex_i_qr_as_image() { let code = QrCode::new(b"01234567").unwrap(); let image = code.render::>().build(); let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma8(); assert_eq!(image.dimensions(), expected.dimensions()); assert_eq!(image.into_raw(), expected.into_raw()); } #[test] fn test_annex_i_micro_qr_as_image() { let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); let image = code .render() .min_dimensions(200, 200) .dark_color(Rgb([128, 0, 0])) .light_color(Rgb([255, 255, 128])) .build(); let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png")).unwrap().to_rgb8(); assert_eq!(image.dimensions(), expected.dimensions()); assert_eq!(image.into_raw(), expected.into_raw()); } } #[cfg(all(test, feature = "svg"))] mod svg_tests { use crate::render::svg::Color as SvgColor; use crate::{EcLevel, QrCode, Version}; #[test] fn test_annex_i_qr_as_svg() { let code = QrCode::new(b"01234567").unwrap(); let image = code.render::().build(); let expected = include_str!("test_annex_i_qr_as_svg.svg"); assert_eq!(&image, expected); } #[test] fn test_annex_i_micro_qr_as_svg() { let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); let image = code .render() .min_dimensions(200, 200) .dark_color(SvgColor("#800000")) .light_color(SvgColor("#ffff80")) .build(); let expected = include_str!("test_annex_i_micro_qr_as_svg.svg"); assert_eq!(&image, expected); } } qrencode-0.14.0/src/optimize.rs000064400000000000000000000574501046102023000145160ustar 00000000000000#![allow(clippy::unicode_not_nfc)] //! Find the optimal data mode sequence to encode a piece of data. use crate::types::{Mode, Version}; use std::slice::Iter; #[cfg(feature = "bench")] extern crate test; //------------------------------------------------------------------------------ //{{{ Segment /// A segment of data committed to an encoding mode. #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub struct Segment { /// The encoding mode of the segment of data. pub mode: Mode, /// The start index of the segment. pub begin: usize, /// The end index (exclusive) of the segment. pub end: usize, } impl Segment { /// Compute the number of bits (including the size of the mode indicator and /// length bits) when this segment is encoded. pub fn encoded_len(&self, version: Version) -> usize { let byte_size = self.end - self.begin; let chars_count = if self.mode == Mode::Kanji { byte_size / 2 } else { byte_size }; let mode_bits_count = version.mode_bits_count(); let length_bits_count = self.mode.length_bits_count(version); let data_bits_count = self.mode.data_bits_count(chars_count); mode_bits_count + length_bits_count + data_bits_count } } //}}} //------------------------------------------------------------------------------ //{{{ Parser /// This iterator is basically equivalent to /// /// ```ignore /// data.map(|c| ExclCharSet::from_u8(*c)) /// .chain(Some(ExclCharSet::End).move_iter()) /// .enumerate() /// ``` /// /// But the type is too hard to write, thus the new type. /// struct EcsIter { base: I, index: usize, ended: bool, } impl<'a, I: Iterator> Iterator for EcsIter { type Item = (usize, ExclCharSet); fn next(&mut self) -> Option<(usize, ExclCharSet)> { if self.ended { return None; } match self.base.next() { None => { self.ended = true; Some((self.index, ExclCharSet::End)) } Some(c) => { let old_index = self.index; self.index += 1; Some((old_index, ExclCharSet::from_u8(*c))) } } } } /// QR code data parser to classify the input into distinct segments. pub struct Parser<'a> { ecs_iter: EcsIter>, state: State, begin: usize, pending_single_byte: bool, } impl<'a> Parser<'a> { /// Creates a new iterator which parse the data into segments that only /// contains their exclusive subsets. No optimization is done at this point. /// /// use qrencode::optimize::{Parser, Segment}; /// use qrencode::types::Mode::{Alphanumeric, Numeric, Byte}; /// /// let parse_res = Parser::new(b"ABC123abcd").collect::>(); /// assert_eq!(parse_res, vec![Segment { mode: Alphanumeric, begin: 0, end: 3 }, /// Segment { mode: Numeric, begin: 3, end: 6 }, /// Segment { mode: Byte, begin: 6, end: 10 }]); /// pub fn new(data: &[u8]) -> Parser { Parser { ecs_iter: EcsIter { base: data.iter(), index: 0, ended: false }, state: State::Init, begin: 0, pending_single_byte: false, } } } impl<'a> Iterator for Parser<'a> { type Item = Segment; fn next(&mut self) -> Option { if self.pending_single_byte { self.pending_single_byte = false; self.begin += 1; return Some(Segment { mode: Mode::Byte, begin: self.begin - 1, end: self.begin }); } loop { let (i, ecs) = match self.ecs_iter.next() { None => return None, Some(a) => a, }; let (next_state, action) = STATE_TRANSITION[self.state as usize + ecs as usize]; self.state = next_state; let old_begin = self.begin; let push_mode = match action { Action::Idle => continue, Action::Numeric => Mode::Numeric, Action::Alpha => Mode::Alphanumeric, Action::Byte => Mode::Byte, Action::Kanji => Mode::Kanji, Action::KanjiAndSingleByte => { let next_begin = i - 1; if self.begin == next_begin { Mode::Byte } else { self.pending_single_byte = true; self.begin = next_begin; return Some(Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin }); } } }; self.begin = i; return Some(Segment { mode: push_mode, begin: old_begin, end: i }); } } } #[cfg(test)] mod parse_tests { use crate::optimize::{Parser, Segment}; use crate::types::Mode; fn parse(data: &[u8]) -> Vec { Parser::new(data).collect() } #[test] fn test_parse_1() { let segs = parse(b"01049123451234591597033130128%10ABC123"); assert_eq!( segs, vec![ Segment { mode: Mode::Numeric, begin: 0, end: 29 }, Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 }, Segment { mode: Mode::Numeric, begin: 30, end: 32 }, Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 }, Segment { mode: Mode::Numeric, begin: 35, end: 38 }, ] ); } #[test] fn test_parse_shift_jis_example_1() { let segs = parse(b"\x82\xa0\x81\x41\x41\xb1\x81\xf0"); // "あ、AアÅ" assert_eq!( segs, vec![ Segment { mode: Mode::Kanji, begin: 0, end: 4 }, Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 }, Segment { mode: Mode::Byte, begin: 5, end: 6 }, Segment { mode: Mode::Kanji, begin: 6, end: 8 }, ] ); } #[test] fn test_parse_utf_8() { // Mojibake? let segs = parse(b"\xe3\x81\x82\xe3\x80\x81A\xef\xbd\xb1\xe2\x84\xab"); assert_eq!( segs, vec![ Segment { mode: Mode::Kanji, begin: 0, end: 4 }, Segment { mode: Mode::Byte, begin: 4, end: 5 }, Segment { mode: Mode::Kanji, begin: 5, end: 7 }, Segment { mode: Mode::Byte, begin: 7, end: 10 }, Segment { mode: Mode::Kanji, begin: 10, end: 12 }, Segment { mode: Mode::Byte, begin: 12, end: 13 }, ] ); } #[test] fn test_not_kanji_1() { let segs = parse(b"\x81\x30"); assert_eq!( segs, vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Numeric, begin: 1, end: 2 },] ); } #[test] fn test_not_kanji_2() { // Note that it's implementation detail that the byte seq is split into // two. Perhaps adjust the test to check for this. let segs = parse(b"\xeb\xc0"); assert_eq!( segs, vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },] ); } #[test] fn test_not_kanji_3() { let segs = parse(b"\x81\x7f"); assert_eq!( segs, vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },] ); } #[test] fn test_not_kanji_4() { let segs = parse(b"\x81\x40\x81"); assert_eq!( segs, vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 },] ); } } //}}} //------------------------------------------------------------------------------ //{{{ Optimizer pub struct Optimizer { parser: I, last_segment: Segment, last_segment_size: usize, version: Version, ended: bool, } impl> Optimizer { /// Optimize the segments by combining adjacent segments when possible. /// /// Currently this method uses a greedy algorithm by combining segments from /// left to right until the new segment is longer than before. This method /// does *not* use Annex J from the ISO standard. /// pub fn new(mut segments: I, version: Version) -> Self { match segments.next() { None => Self { parser: segments, last_segment: Segment { mode: Mode::Numeric, begin: 0, end: 0 }, last_segment_size: 0, version, ended: true, }, Some(segment) => Self { parser: segments, last_segment: segment, last_segment_size: segment.encoded_len(version), version, ended: false, }, } } } impl<'a> Parser<'a> { pub fn optimize(self, version: Version) -> Optimizer> { Optimizer::new(self, version) } } impl> Iterator for Optimizer { type Item = Segment; fn next(&mut self) -> Option { if self.ended { return None; } loop { match self.parser.next() { None => { self.ended = true; return Some(self.last_segment); } Some(segment) => { let seg_size = segment.encoded_len(self.version); let new_segment = Segment { mode: self.last_segment.mode.max(segment.mode), begin: self.last_segment.begin, end: segment.end, }; let new_size = new_segment.encoded_len(self.version); if self.last_segment_size + seg_size >= new_size { self.last_segment = new_segment; self.last_segment_size = new_size; } else { let old_segment = self.last_segment; self.last_segment = segment; self.last_segment_size = seg_size; return Some(old_segment); } } } } } } /// Computes the total encoded length of all segments. pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize { segments.iter().map(|seg| seg.encoded_len(version)).sum() } #[cfg(test)] mod optimize_tests { use crate::optimize::{total_encoded_len, Optimizer, Segment}; use crate::types::{Mode, Version}; fn test_optimization_result(given: &[Segment], expected: &[Segment], version: Version) { let prev_len = total_encoded_len(&*given, version); let opt_segs = Optimizer::new(given.iter().copied(), version).collect::>(); let new_len = total_encoded_len(&*opt_segs, version); if given != opt_segs { assert!(prev_len > new_len, "{} > {}", prev_len, new_len); } assert!( opt_segs == expected, "Optimization gave something better: {} < {} ({:?})", new_len, total_encoded_len(&*expected, version), opt_segs ); } #[test] fn test_example_1() { test_optimization_result( &[ Segment { mode: Mode::Alphanumeric, begin: 0, end: 3 }, Segment { mode: Mode::Numeric, begin: 3, end: 6 }, Segment { mode: Mode::Byte, begin: 6, end: 10 }, ], &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 6 }, Segment { mode: Mode::Byte, begin: 6, end: 10 }], Version::Normal(1), ); } #[test] fn test_example_2() { test_optimization_result( &[ Segment { mode: Mode::Numeric, begin: 0, end: 29 }, Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 }, Segment { mode: Mode::Numeric, begin: 30, end: 32 }, Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 }, Segment { mode: Mode::Numeric, begin: 35, end: 38 }, ], &[ Segment { mode: Mode::Numeric, begin: 0, end: 29 }, Segment { mode: Mode::Alphanumeric, begin: 29, end: 38 }, ], Version::Normal(9), ); } #[test] fn test_example_3() { test_optimization_result( &[ Segment { mode: Mode::Kanji, begin: 0, end: 4 }, Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 }, Segment { mode: Mode::Byte, begin: 5, end: 6 }, Segment { mode: Mode::Kanji, begin: 6, end: 8 }, ], &[Segment { mode: Mode::Byte, begin: 0, end: 8 }], Version::Normal(1), ); } #[test] fn test_example_4() { test_optimization_result( &[Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }], &[Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }], Version::Normal(1), ); } #[test] fn test_annex_j_guideline_1a() { test_optimization_result( &[ Segment { mode: Mode::Numeric, begin: 0, end: 3 }, Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }, ], &[ Segment { mode: Mode::Numeric, begin: 0, end: 3 }, Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }, ], Version::Micro(2), ); } #[test] fn test_annex_j_guideline_1b() { test_optimization_result( &[ Segment { mode: Mode::Numeric, begin: 0, end: 2 }, Segment { mode: Mode::Alphanumeric, begin: 2, end: 4 }, ], &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }], Version::Micro(2), ); } #[test] fn test_annex_j_guideline_1c() { test_optimization_result( &[ Segment { mode: Mode::Numeric, begin: 0, end: 3 }, Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }, ], &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }], Version::Micro(3), ); } } #[cfg(feature = "bench")] #[bench] fn bench_optimize(bencher: &mut test::Bencher) { use crate::types::Version; let data = b"QR\x83R\x81[\x83h\x81i\x83L\x83\x85\x81[\x83A\x81[\x83\x8b\x83R\x81[\x83h\x81j\ \x82\xc6\x82\xcd\x81A1994\x94N\x82\xc9\x83f\x83\x93\x83\\\x81[\x82\xcc\x8aJ\ \x94\xad\x95\x94\x96\xe5\x81i\x8c\xbb\x8d\xdd\x82\xcd\x95\xaa\x97\xa3\x82\xb5\x83f\ \x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x81j\x82\xaa\x8aJ\x94\xad\x82\xb5\x82\xbd\ \x83}\x83g\x83\x8a\x83b\x83N\x83X\x8c^\x93\xf1\x8e\x9f\x8c\xb3\x83R\x81[\x83h\ \x82\xc5\x82\xa0\x82\xe9\x81B\x82\xc8\x82\xa8\x81AQR\x83R\x81[\x83h\x82\xc6\ \x82\xa2\x82\xa4\x96\xbc\x8f\xcc\x81i\x82\xa8\x82\xe6\x82\xd1\x92P\x8c\xea\x81j\ \x82\xcd\x83f\x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x82\xcc\x93o\x98^\x8f\xa4\ \x95W\x81i\x91\xe64075066\x8d\x86\x81j\x82\xc5\x82\xa0\x82\xe9\x81BQR\x82\xcd\ Quick Response\x82\xc9\x97R\x97\x88\x82\xb5\x81A\x8d\x82\x91\xac\x93\xc7\x82\xdd\ \x8e\xe6\x82\xe8\x82\xaa\x82\xc5\x82\xab\x82\xe9\x82\xe6\x82\xa4\x82\xc9\x8aJ\ \x94\xad\x82\xb3\x82\xea\x82\xbd\x81B\x93\x96\x8f\x89\x82\xcd\x8e\xa9\x93\xae\ \x8e\xd4\x95\x94\x95i\x8dH\x8f\xea\x82\xe2\x94z\x91\x97\x83Z\x83\x93\x83^\x81[\ \x82\xc8\x82\xc7\x82\xc5\x82\xcc\x8eg\x97p\x82\xf0\x94O\x93\xaa\x82\xc9\x8aJ\ \x94\xad\x82\xb3\x82\xea\x82\xbd\x82\xaa\x81A\x8c\xbb\x8d\xdd\x82\xc5\x82\xcd\x83X\ \x83}\x81[\x83g\x83t\x83H\x83\x93\x82\xcc\x95\x81\x8by\x82\xc8\x82\xc7\x82\xc9\ \x82\xe6\x82\xe8\x93\xfa\x96{\x82\xc9\x8c\xc0\x82\xe7\x82\xb8\x90\xa2\x8aE\x93I\ \x82\xc9\x95\x81\x8by\x82\xb5\x82\xc4\x82\xa2\x82\xe9\x81B"; bencher.iter(|| Parser::new(data).optimize(Version::Normal(15))); } //}}} //------------------------------------------------------------------------------ //{{{ Internal types and data for parsing /// All values of `u8` can be split into 9 different character sets when /// determining which encoding to use. This enum represents these groupings for /// parsing purpose. #[derive(Copy, Clone)] enum ExclCharSet { /// The end of string. End = 0, /// All symbols supported by the Alphanumeric encoding, i.e. space, `$`, `%`, /// `*`, `+`, `-`, `.`, `/` and `:`. Symbol = 1, /// All numbers (0–9). Numeric = 2, /// All uppercase letters (A–Z). These characters may also appear in the /// second byte of a Shift JIS 2-byte encoding. Alpha = 3, /// The first byte of a Shift JIS 2-byte encoding, in the range 0x81–0x9f. KanjiHi1 = 4, /// The first byte of a Shift JIS 2-byte encoding, in the range 0xe0–0xea. KanjiHi2 = 5, /// The first byte of a Shift JIS 2-byte encoding, of value 0xeb. This is /// different from the other two range that the second byte has a smaller /// range. KanjiHi3 = 6, /// The second byte of a Shift JIS 2-byte encoding, in the range 0x40–0xbf, /// excluding letters (covered by `Alpha`), 0x81–0x9f (covered by `KanjiHi1`), /// and the invalid byte 0x7f. KanjiLo1 = 7, /// The second byte of a Shift JIS 2-byte encoding, in the range 0xc0–0xfc, /// excluding the range 0xe0–0xeb (covered by `KanjiHi2` and `KanjiHi3`). /// This half of byte-pair cannot appear as the second byte leaded by /// `KanjiHi3`. KanjiLo2 = 8, /// Any other values not covered by the above character sets. Byte = 9, } impl ExclCharSet { /// Determines which character set a byte is in. fn from_u8(c: u8) -> Self { match c { 0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d..=0x2f | 0x3a => ExclCharSet::Symbol, 0x30..=0x39 => ExclCharSet::Numeric, 0x41..=0x5a => ExclCharSet::Alpha, 0x81..=0x9f => ExclCharSet::KanjiHi1, 0xe0..=0xea => ExclCharSet::KanjiHi2, 0xeb => ExclCharSet::KanjiHi3, 0x40 | 0x5b..=0x7e | 0x80 | 0xa0..=0xbf => ExclCharSet::KanjiLo1, 0xc0..=0xdf | 0xec..=0xfc => ExclCharSet::KanjiLo2, _ => ExclCharSet::Byte, } } } /// The current parsing state. #[derive(Copy, Clone)] enum State { /// Just initialized. Init = 0, /// Inside a string that can be exclusively encoded as Numeric. Numeric = 10, /// Inside a string that can be exclusively encoded as Alphanumeric. Alpha = 20, /// Inside a string that can be exclusively encoded as 8-Bit Byte. Byte = 30, /// Just encountered the first byte of a Shift JIS 2-byte sequence of the /// set `KanjiHi1` or `KanjiHi2`. KanjiHi12 = 40, /// Just encountered the first byte of a Shift JIS 2-byte sequence of the /// set `KanjiHi3`. KanjiHi3 = 50, /// Inside a string that can be exclusively encoded as Kanji. Kanji = 60, } /// What should the parser do after a state transition. #[derive(Copy, Clone)] enum Action { /// The parser should do nothing. Idle, /// Push the current segment as a Numeric string, and reset the marks. Numeric, /// Push the current segment as an Alphanumeric string, and reset the marks. Alpha, /// Push the current segment as a 8-Bit Byte string, and reset the marks. Byte, /// Push the current segment as a Kanji string, and reset the marks. Kanji, /// Push the current segment excluding the last byte as a Kanji string, then /// push the remaining single byte as a Byte string, and reset the marks. KanjiAndSingleByte, } static STATE_TRANSITION: [(State, Action); 70] = [ // STATE_TRANSITION[current_state + next_character] == (next_state, what_to_do) // Init state: (State::Init, Action::Idle), // End (State::Alpha, Action::Idle), // Symbol (State::Numeric, Action::Idle), // Numeric (State::Alpha, Action::Idle), // Alpha (State::KanjiHi12, Action::Idle), // KanjiHi1 (State::KanjiHi12, Action::Idle), // KanjiHi2 (State::KanjiHi3, Action::Idle), // KanjiHi3 (State::Byte, Action::Idle), // KanjiLo1 (State::Byte, Action::Idle), // KanjiLo2 (State::Byte, Action::Idle), // Byte // Numeric state: (State::Init, Action::Numeric), // End (State::Alpha, Action::Numeric), // Symbol (State::Numeric, Action::Idle), // Numeric (State::Alpha, Action::Numeric), // Alpha (State::KanjiHi12, Action::Numeric), // KanjiHi1 (State::KanjiHi12, Action::Numeric), // KanjiHi2 (State::KanjiHi3, Action::Numeric), // KanjiHi3 (State::Byte, Action::Numeric), // KanjiLo1 (State::Byte, Action::Numeric), // KanjiLo2 (State::Byte, Action::Numeric), // Byte // Alpha state: (State::Init, Action::Alpha), // End (State::Alpha, Action::Idle), // Symbol (State::Numeric, Action::Alpha), // Numeric (State::Alpha, Action::Idle), // Alpha (State::KanjiHi12, Action::Alpha), // KanjiHi1 (State::KanjiHi12, Action::Alpha), // KanjiHi2 (State::KanjiHi3, Action::Alpha), // KanjiHi3 (State::Byte, Action::Alpha), // KanjiLo1 (State::Byte, Action::Alpha), // KanjiLo2 (State::Byte, Action::Alpha), // Byte // Byte state: (State::Init, Action::Byte), // End (State::Alpha, Action::Byte), // Symbol (State::Numeric, Action::Byte), // Numeric (State::Alpha, Action::Byte), // Alpha (State::KanjiHi12, Action::Byte), // KanjiHi1 (State::KanjiHi12, Action::Byte), // KanjiHi2 (State::KanjiHi3, Action::Byte), // KanjiHi3 (State::Byte, Action::Idle), // KanjiLo1 (State::Byte, Action::Idle), // KanjiLo2 (State::Byte, Action::Idle), // Byte // KanjiHi12 state: (State::Init, Action::KanjiAndSingleByte), // End (State::Alpha, Action::KanjiAndSingleByte), // Symbol (State::Numeric, Action::KanjiAndSingleByte), // Numeric (State::Kanji, Action::Idle), // Alpha (State::Kanji, Action::Idle), // KanjiHi1 (State::Kanji, Action::Idle), // KanjiHi2 (State::Kanji, Action::Idle), // KanjiHi3 (State::Kanji, Action::Idle), // KanjiLo1 (State::Kanji, Action::Idle), // KanjiLo2 (State::Byte, Action::KanjiAndSingleByte), // Byte // KanjiHi3 state: (State::Init, Action::KanjiAndSingleByte), // End (State::Alpha, Action::KanjiAndSingleByte), // Symbol (State::Numeric, Action::KanjiAndSingleByte), // Numeric (State::Kanji, Action::Idle), // Alpha (State::Kanji, Action::Idle), // KanjiHi1 (State::KanjiHi12, Action::KanjiAndSingleByte), // KanjiHi2 (State::KanjiHi3, Action::KanjiAndSingleByte), // KanjiHi3 (State::Kanji, Action::Idle), // KanjiLo1 (State::Byte, Action::KanjiAndSingleByte), // KanjiLo2 (State::Byte, Action::KanjiAndSingleByte), // Byte // Kanji state: (State::Init, Action::Kanji), // End (State::Alpha, Action::Kanji), // Symbol (State::Numeric, Action::Kanji), // Numeric (State::Alpha, Action::Kanji), // Alpha (State::KanjiHi12, Action::Idle), // KanjiHi1 (State::KanjiHi12, Action::Idle), // KanjiHi2 (State::KanjiHi3, Action::Idle), // KanjiHi3 (State::Byte, Action::Kanji), // KanjiLo1 (State::Byte, Action::Kanji), // KanjiLo2 (State::Byte, Action::Kanji), // Byte ]; //}}} qrencode-0.14.0/src/render/image.rs000064400000000000000000000113201046102023000152010ustar 00000000000000#![cfg(feature = "image")] use crate::render::{Canvas, Pixel}; use crate::types::Color; use image::{ImageBuffer, Luma, LumaA, Pixel as ImagePixel, Primitive, Rgb, Rgba}; macro_rules! impl_pixel_for_image_pixel { ($p:ident<$s:ident>: $c:pat => $d:expr) => { impl<$s> Pixel for $p<$s> where $s: Primitive + 'static, Self: ImagePixel, { type Image = ImageBuffer::Subpixel>>; type Canvas = (Self, Self::Image); fn default_color(color: Color) -> Self { match color.select($s::zero(), $s::max_value()) { $c => $p($d), } } } }; } impl_pixel_for_image_pixel! { Luma: p => [p] } impl_pixel_for_image_pixel! { LumaA: p => [p, S::max_value()] } impl_pixel_for_image_pixel! { Rgb: p => [p, p, p] } impl_pixel_for_image_pixel! { Rgba: p => [p, p, p, S::max_value()] } impl Canvas for (P, ImageBuffer>) { type Pixel = P; type Image = ImageBuffer>; fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self { (dark_pixel, ImageBuffer::from_pixel(width, height, light_pixel)) } fn draw_dark_pixel(&mut self, x: u32, y: u32) { self.1.put_pixel(x, y, self.0); } fn into_image(self) -> ImageBuffer> { self.1 } } #[cfg(test)] mod render_tests { use crate::render::Renderer; use crate::types::Color; use image::{Luma, Rgba}; #[test] fn test_render_luma8_unsized() { let image = Renderer::>::new( &[ Color::Light, Color::Dark, Color::Dark, // Color::Dark, Color::Light, Color::Light, // Color::Light, Color::Dark, Color::Light, ], 3, 1, ) .module_dimensions(1, 1) .build(); #[rustfmt::skip] let expected = [ 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, ]; assert_eq!(image.into_raw(), expected); } #[test] fn test_render_rgba_unsized() { let image = Renderer::>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1) .module_dimensions(1, 1) .build(); #[rustfmt::skip] let expected: &[u8] = &[ 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 0, 0, 0,255, 255,255,255,255, 255,255,255,255, 0, 0, 0,255, 0, 0, 0,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, ]; assert_eq!(image.into_raw(), expected); } #[test] fn test_render_resized_min() { let image = Renderer::>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1) .min_dimensions(10, 10) .build(); #[rustfmt::skip] let expected: &[u8] = &[ 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, ]; assert_eq!(image.dimensions(), (12, 12)); assert_eq!(image.into_raw(), expected); } #[test] fn test_render_resized_max() { let image = Renderer::>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1) .max_dimensions(10, 5) .build(); #[rustfmt::skip] let expected: &[u8] = &[ 255,255, 255,255, 255,255, 255,255, 255,255, 0, 0, 255,255, 255,255, 255,255, 255,255, 0, 0, 255,255, 255,255, 255,255, 255,255, 255,255, ]; assert_eq!(image.dimensions(), (8, 4)); assert_eq!(image.into_raw(), expected); } } qrencode-0.14.0/src/render/mod.rs000064400000000000000000000154321046102023000147060ustar 00000000000000//! Render a QR code into image. use crate::cast::As; use crate::types::Color; use std::cmp::max; pub mod image; pub mod string; pub mod svg; pub mod unicode; //------------------------------------------------------------------------------ //{{{ Pixel trait /// Abstraction of an image pixel. pub trait Pixel: Copy + Sized { /// Type of the finalized image. type Image: Sized + 'static; /// The type that stores an intermediate buffer before finalizing to a /// concrete image type Canvas: Canvas; /// Obtains the default module size. The result must be at least 1×1. fn default_unit_size() -> (u32, u32) { (8, 8) } /// Obtains the default pixel color when a module is dark or light. fn default_color(color: Color) -> Self; } /// Rendering canvas of a QR code image. pub trait Canvas: Sized { type Pixel: Sized; type Image: Sized; /// Constructs a new canvas of the given dimensions. fn new(width: u32, height: u32, dark_pixel: Self::Pixel, light_pixel: Self::Pixel) -> Self; /// Draws a single dark pixel at the (x, y) coordinate. fn draw_dark_pixel(&mut self, x: u32, y: u32); fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u32) { for y in top..(top + height) { for x in left..(left + width) { self.draw_dark_pixel(x, y); } } } /// Finalize the canvas to a real image. fn into_image(self) -> Self::Image; } //}}} //------------------------------------------------------------------------------ //{{{ Renderer /// A QR code renderer. This is a builder type which converts a bool-vector into /// an image. pub struct Renderer<'a, P: Pixel> { content: &'a [Color], modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`. quiet_zone: u32, module_size: (u32, u32), dark_color: P, light_color: P, has_quiet_zone: bool, } impl<'a, P: Pixel> Renderer<'a, P> { /// Creates a new renderer. /// /// # Panics /// panics if content is not `modules_count` squared big pub fn new(content: &'a [Color], modules_count: usize, quiet_zone: u32) -> Renderer<'a, P> { assert!(modules_count * modules_count == content.len()); Renderer { content, modules_count: modules_count.as_u32(), quiet_zone, module_size: P::default_unit_size(), dark_color: P::default_color(Color::Dark), light_color: P::default_color(Color::Light), has_quiet_zone: true, } } /// Sets color of a dark module. Default is opaque black. pub fn dark_color(&mut self, color: P) -> &mut Self { self.dark_color = color; self } /// Sets color of a light module. Default is opaque white. pub fn light_color(&mut self, color: P) -> &mut Self { self.light_color = color; self } /// Whether to include the quiet zone in the generated image. pub fn quiet_zone(&mut self, has_quiet_zone: bool) -> &mut Self { self.has_quiet_zone = has_quiet_zone; self } /// Sets the size of each module in pixels. Default is 8px. #[deprecated(since = "0.4.0", note = "use `.module_dimensions(width, width)` instead")] pub fn module_size(&mut self, width: u32) -> &mut Self { self.module_dimensions(width, width) } /// Sets the size of each module in pixels. Default is 8×8. pub fn module_dimensions(&mut self, width: u32, height: u32) -> &mut Self { self.module_size = (max(width, 1), max(height, 1)); self } #[deprecated(since = "0.4.0", note = "use `.min_dimensions(width, width)` instead")] pub fn min_width(&mut self, width: u32) -> &mut Self { self.min_dimensions(width, width) } /// Sets the minimum total image size in pixels, including the quiet zone if /// applicable. The renderer will try to find the dimension as small as /// possible, such that each module in the QR code has uniform size (no /// distortion). /// /// For instance, a version 1 QR code has 19 modules across including the /// quiet zone. If we request an image of size ≥200×200, we get that each /// module's size should be 11×11, so the actual image size will be 209×209. pub fn min_dimensions(&mut self, width: u32, height: u32) -> &mut Self { let quiet_zone = if self.has_quiet_zone { 2 } else { 0 } * self.quiet_zone; let width_in_modules = self.modules_count + quiet_zone; let unit_width = (width + width_in_modules - 1) / width_in_modules; let unit_height = (height + width_in_modules - 1) / width_in_modules; self.module_dimensions(unit_width, unit_height) } /// Sets the maximum total image size in pixels, including the quiet zone if /// applicable. The renderer will try to find the dimension as large as /// possible, such that each module in the QR code has uniform size (no /// distortion). /// /// For instance, a version 1 QR code has 19 modules across including the /// quiet zone. If we request an image of size ≤200×200, we get that each /// module's size should be 10×10, so the actual image size will be 190×190. /// /// The module size is at least 1×1, so if the restriction is too small, the /// final image *can* be larger than the input. pub fn max_dimensions(&mut self, width: u32, height: u32) -> &mut Self { let quiet_zone = if self.has_quiet_zone { 2 } else { 0 } * self.quiet_zone; let width_in_modules = self.modules_count + quiet_zone; let unit_width = width / width_in_modules; let unit_height = height / width_in_modules; self.module_dimensions(unit_width, unit_height) } /// Renders the QR code into an image. #[deprecated(since = "0.4.0", note = "renamed to `.build()` to de-emphasize the image connection")] pub fn to_image(&self) -> P::Image { self.build() } /// Renders the QR code into an image. pub fn build(&self) -> P::Image { let w = self.modules_count; let qz = if self.has_quiet_zone { self.quiet_zone } else { 0 }; let width = w + 2 * qz; let (mw, mh) = self.module_size; let real_width = width * mw; let real_height = width * mh; let mut canvas = P::Canvas::new(real_width, real_height, self.dark_color, self.light_color); let mut i = 0; for y in 0..width { for x in 0..width { if qz <= x && x < w + qz && qz <= y && y < w + qz { if self.content[i] != Color::Light { canvas.draw_dark_rect(x * mw, y * mh, mw, mh); } i += 1; } } } canvas.into_image() } } //}}} qrencode-0.14.0/src/render/string.rs000064400000000000000000000057461046102023000154440ustar 00000000000000//! String rendering support. use crate::cast::As; use crate::render::{Canvas as RenderCanvas, Pixel}; use crate::types::Color; pub trait Element: Copy { fn default_color(color: Color) -> Self; fn strlen(self) -> usize; fn append_to_string(self, string: &mut String); } impl Element for char { fn default_color(color: Color) -> Self { color.select('\u{2588}', ' ') } fn strlen(self) -> usize { self.len_utf8() } fn append_to_string(self, string: &mut String) { string.push(self); } } impl<'a> Element for &'a str { fn default_color(color: Color) -> Self { color.select("\u{2588}", " ") } fn strlen(self) -> usize { self.len() } fn append_to_string(self, string: &mut String) { string.push_str(self); } } #[doc(hidden)] pub struct Canvas { buffer: Vec

, width: usize, dark_pixel: P, dark_cap_inc: isize, capacity: isize, } impl Pixel for P { type Canvas = Canvas; type Image = String; fn default_unit_size() -> (u32, u32) { (1, 1) } fn default_color(color: Color) -> Self { ::default_color(color) } } impl RenderCanvas for Canvas

{ type Pixel = P; type Image = String; fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self { let width = width.as_usize(); let height = height.as_isize(); let dark_cap = dark_pixel.strlen().as_isize(); let light_cap = light_pixel.strlen().as_isize(); Self { buffer: vec![light_pixel; width * height.as_usize()], width, dark_pixel, dark_cap_inc: dark_cap - light_cap, capacity: light_cap * width.as_isize() * height + (height - 1), } } fn draw_dark_pixel(&mut self, x: u32, y: u32) { let x = x.as_usize(); let y = y.as_usize(); self.capacity += self.dark_cap_inc; self.buffer[x + y * self.width] = self.dark_pixel; } fn into_image(self) -> String { let mut result = String::with_capacity(self.capacity.as_usize()); for (i, pixel) in self.buffer.into_iter().enumerate() { if i != 0 && i % self.width == 0 { result.push('\n'); } pixel.append_to_string(&mut result); } result } } #[test] fn test_render_to_string() { use crate::render::Renderer; let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark]; let image: String = Renderer::::new(colors, 2, 1).build(); assert_eq!(&image, " \n \u{2588} \n \u{2588} \n "); let image2 = Renderer::new(colors, 2, 1).light_color("A").dark_color("!B!").module_dimensions(2, 2).build(); assert_eq!( &image2, "AAAAAAAA\n\ AAAAAAAA\n\ AA!B!!B!AAAA\n\ AA!B!!B!AAAA\n\ AAAA!B!!B!AA\n\ AAAA!B!!B!AA\n\ AAAAAAAA\n\ AAAAAAAA" ); } qrencode-0.14.0/src/render/svg.rs000064400000000000000000000040661046102023000147270ustar 00000000000000//! SVG rendering support. //! //! # Example //! //! ``` //! use qrencode::QrCode; //! use qrencode::render::svg; //! //! let code = QrCode::new(b"Hello").unwrap(); //! let svg_xml = code.render::().build(); //! println!("{}", svg_xml); #![cfg(feature = "svg")] use std::fmt::Write; use std::marker::PhantomData; use crate::render::{Canvas as RenderCanvas, Pixel}; use crate::types::Color as ModuleColor; /// An SVG color. #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Color<'a>(pub &'a str); impl<'a> Pixel for Color<'a> { type Canvas = Canvas<'a>; type Image = String; fn default_color(color: ModuleColor) -> Self { Color(color.select("#000", "#fff")) } } #[doc(hidden)] pub struct Canvas<'a> { svg: String, marker: PhantomData>, } impl<'a> RenderCanvas for Canvas<'a> { type Pixel = Color<'a>; type Image = String; fn new(width: u32, height: u32, dark_pixel: Color<'a>, light_pixel: Color<'a>) -> Self { Canvas { svg: format!( concat!( r#""#, r#""#, r#""#, r#" String { self.svg.push_str(r#""/>"#); self.svg } } qrencode-0.14.0/src/render/unicode.rs000064400000000000000000000106401046102023000155510ustar 00000000000000//! UTF-8 rendering, with 2 pixels per symbol. use crate::render::{Canvas as RenderCanvas, Color, Pixel}; const CODEPAGE: [&str; 4] = [" ", "\u{2584}", "\u{2580}", "\u{2588}"]; #[derive(Copy, Clone, PartialEq)] pub enum Dense1x2 { Dark, Light, } impl Pixel for Dense1x2 { type Image = String; type Canvas = Canvas1x2; fn default_color(color: Color) -> Dense1x2 { color.select(Dense1x2::Dark, Dense1x2::Light) } fn default_unit_size() -> (u32, u32) { (1, 1) } } impl Dense1x2 { fn value(self) -> u8 { match self { Dense1x2::Dark => 1, Dense1x2::Light => 0, } } fn parse_2_bits(sym: u8) -> &'static str { CODEPAGE[usize::from(sym)] } } pub struct Canvas1x2 { canvas: Vec, width: u32, dark_pixel: u8, } impl RenderCanvas for Canvas1x2 { type Pixel = Dense1x2; type Image = String; fn new(width: u32, height: u32, dark_pixel: Dense1x2, light_pixel: Dense1x2) -> Self { let a = vec![light_pixel.value(); (width * height) as usize]; Canvas1x2 { width, canvas: a, dark_pixel: dark_pixel.value() } } fn draw_dark_pixel(&mut self, x: u32, y: u32) { self.canvas[(x + y * self.width) as usize] = self.dark_pixel; } fn into_image(self) -> String { self.canvas // Chopping array into 1-line sized fragments .chunks_exact(self.width as usize) .collect::>() // And then glueing every 2 lines. .chunks(2) .map(|rows| { { // Then zipping those 2 lines together into a single 2-bit number list. if rows.len() == 2 { rows[0].iter().zip(rows[1]).map(|(top, bot)| (top * 2 + bot)).collect::>() } else { rows[0].iter().map(|top| (top * 2)).collect::>() } } .into_iter() // Mapping those 2-bit numbers to corresponding pixels. .map(Dense1x2::parse_2_bits) .collect::>() .concat() }) .collect::>() .join("\n") } } #[test] fn test_render_to_utf8_string() { use crate::render::Renderer; let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark]; let image: String = Renderer::::new(colors, 2, 1).build(); assert_eq!(&image, " ▄ \n ▀ "); let image2 = Renderer::::new(colors, 2, 1).module_dimensions(2, 2).build(); assert_eq!(&image2, " \n ██ \n ██ \n "); } #[test] fn integration_render_utf8_1x2() { use crate::render::unicode::Dense1x2; use crate::{EcLevel, QrCode, Version}; let code = QrCode::with_version(b"09876542", Version::Micro(2), EcLevel::L).unwrap(); let image = code.render::().module_dimensions(1, 1).build(); assert_eq!( image, String::new() + " \n" + " █▀▀▀▀▀█ ▀ █ ▀ \n" + " █ ███ █ ▀ █ \n" + " █ ▀▀▀ █ ▀█ █ \n" + " ▀▀▀▀▀▀▀ ▄▀▀ █ \n" + " ▀█ ▀▀▀▀▀██▀▀▄ \n" + " ▀███▄ ▀▀ █ ██ \n" + " ▀▀▀ ▀ ▀▀ ▀ ▀ \n" + " " ); } #[test] fn integration_render_utf8_1x2_inverted() { use crate::render::unicode::Dense1x2; use crate::{EcLevel, QrCode, Version}; let code = QrCode::with_version(b"12345678", Version::Micro(2), EcLevel::L).unwrap(); let image = code .render::() .dark_color(Dense1x2::Light) .light_color(Dense1x2::Dark) .module_dimensions(1, 1) .build(); assert_eq!( image, "█████████████████\n\ ██ ▄▄▄▄▄ █▄▀▄█▄██\n\ ██ █ █ █ █ ██\n\ ██ █▄▄▄█ █▄▄██▀██\n\ ██▄▄▄▄▄▄▄█▄▄▄▀ ██\n\ ██▄ ▀ ▀ ▀▄▄ ████\n\ ██▄▄▀▄█ ▀▀▀ ▀▄▄██\n\ ██▄▄▄█▄▄█▄██▄█▄██\n\ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀" ); } qrencode-0.14.0/src/test_annex_i_micro_qr_as_image.png000064400000000000000000000002721046102023000212040ustar 00000000000000PNG  IHDRޱPLTEx4oIDATx^A Qoo 'էEI DtUk?=d~@P􆠜)&AYAPojn덉$W#HW 5- joh9C'Z{IENDB`qrencode-0.14.0/src/test_annex_i_micro_qr_as_svg.svg000064400000000000000000000040541046102023000207360ustar 00000000000000qrencode-0.14.0/src/test_annex_i_qr_as_image.png000064400000000000000000000003311046102023000200070ustar 00000000000000PNG  IHDRg:;PLTEٟIDATx^A P`~u+ӧ) etrگP+N[aj؋2Ȟjg`D e;m5 pHiuTiܜEպi56u!oIENDB`qrencode-0.14.0/src/test_annex_i_qr_as_svg.svg000064400000000000000000000101201046102023000175340ustar 00000000000000qrencode-0.14.0/src/types.rs000064400000000000000000000241441046102023000140140ustar 00000000000000use crate::cast::As; use std::cmp::{Ordering, PartialOrd}; use std::default::Default; use std::fmt::{Display, Error, Formatter}; use std::ops::Not; //------------------------------------------------------------------------------ //{{{ QrResult /// `QrError` encodes the error encountered when generating a QR code. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum QrError { /// The data is too long to encode into a QR code for the given version. DataTooLong, /// The provided version / error correction level combination is invalid. InvalidVersion, /// Some characters in the data cannot be supported by the provided QR code /// version. UnsupportedCharacterSet, /// The provided ECI designator is invalid. A valid designator should be /// between 0 and 999999. InvalidEciDesignator, /// A character not belonging to the character set is found. InvalidCharacter, } impl Display for QrError { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { let msg = match *self { QrError::DataTooLong => "data too long", QrError::InvalidVersion => "invalid version", QrError::UnsupportedCharacterSet => "unsupported character set", QrError::InvalidEciDesignator => "invalid ECI designator", QrError::InvalidCharacter => "invalid character", }; fmt.write_str(msg) } } impl ::std::error::Error for QrError {} /// `QrResult` is a convenient alias for a QR code generation result. pub type QrResult = Result; //}}} //------------------------------------------------------------------------------ //{{{ Color /// The color of a module. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Color { /// The module is light colored. Light, /// The module is dark colored. Dark, } impl Color { /// Selects a value according to color of the module. Equivalent to /// `if self != Color::Light { dark } else { light }`. /// /// # Examples /// /// ```rust /// # use qrencode::types::Color; /// assert_eq!(Color::Light.select(1, 0), 0); /// assert_eq!(Color::Dark.select("black", "white"), "black"); /// ``` pub fn select(self, dark: T, light: T) -> T { match self { Color::Light => light, Color::Dark => dark, } } } impl Not for Color { type Output = Self; fn not(self) -> Self { match self { Color::Light => Color::Dark, Color::Dark => Color::Light, } } } //}}} //------------------------------------------------------------------------------ //{{{ Error correction level /// The error correction level. It allows the original information be recovered /// even if parts of the code is damaged. #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] pub enum EcLevel { /// Low error correction. Allows up to 7% of wrong blocks. L = 0, /// Medium error correction (default). Allows up to 15% of wrong blocks. M = 1, /// "Quartile" error correction. Allows up to 25% of wrong blocks. Q = 2, /// High error correction. Allows up to 30% of wrong blocks. H = 3, } //}}} //------------------------------------------------------------------------------ //{{{ Version /// In QR code terminology, `Version` means the size of the generated image. /// Larger version means the size of code is larger, and therefore can carry /// more information. /// /// The smallest version is `Version::Normal(1)` of size 21×21, and the largest /// is `Version::Normal(40)` of size 177×177. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Version { /// A normal QR code version. The parameter should be between 1 and 40. Normal(i16), /// A Micro QR code version. The parameter should be between 1 and 4. Micro(i16), } impl Version { /// Get the number of "modules" on each size of the QR code, i.e. the width /// and height of the code. pub fn width(self) -> i16 { match self { Version::Normal(v) => v * 4 + 17, Version::Micro(v) => v * 2 + 9, } } /// Obtains an object from a hard-coded table. /// /// The table must be a 44×4 array. The outer array represents the content /// for each version. The first 40 entry corresponds to QR code versions 1 /// to 40, and the last 4 corresponds to Micro QR code version 1 to 4. The /// inner array represents the content in each error correction level, in /// the order [L, M, Q, H]. /// /// # Errors /// /// If the entry compares equal to the default value of `T`, this method /// returns `Err(QrError::InvalidVersion)`. pub fn fetch(self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult where T: PartialEq + Default + Copy, { match self { Version::Normal(v @ 1..=40) => { return Ok(table[(v - 1).as_usize()][ec_level as usize]); } Version::Micro(v @ 1..=4) => { let obj = table[(v + 39).as_usize()][ec_level as usize]; if obj != T::default() { return Ok(obj); } } _ => {} } Err(QrError::InvalidVersion) } /// The number of bits needed to encode the mode indicator. pub fn mode_bits_count(self) -> usize { match self { Version::Micro(a) => (a - 1).as_usize(), Version::Normal(_) => 4, } } /// Checks whether is version refers to a Micro QR code. pub fn is_micro(self) -> bool { match self { Version::Normal(_) => false, Version::Micro(_) => true, } } } //}}} //------------------------------------------------------------------------------ //{{{ Mode indicator /// The mode indicator, which specifies the character set of the encoded data. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Mode { /// The data contains only characters 0 to 9. Numeric, /// The data contains only uppercase letters (A–Z), numbers (0–9) and a few /// punctuations marks (space, `$`, `%`, `*`, `+`, `-`, `.`, `/`, `:`). Alphanumeric, /// The data contains arbitrary binary data. Byte, /// The data contains Shift-JIS-encoded double-byte text. Kanji, } impl Mode { /// Computes the number of bits needed to encode the data length. /// /// use qrencode::types::{Version, Mode}; /// /// assert_eq!(Mode::Numeric.length_bits_count(Version::Normal(1)), 10); /// /// This method will return `Err(QrError::UnsupportedCharacterSet)` if the /// mode is not supported in the given version. pub fn length_bits_count(self, version: Version) -> usize { match version { Version::Micro(a) => { let a = a.as_usize(); match self { Mode::Numeric => 2 + a, Mode::Alphanumeric | Mode::Byte => 1 + a, Mode::Kanji => a, } } Version::Normal(1..=9) => match self { Mode::Numeric => 10, Mode::Alphanumeric => 9, Mode::Byte | Mode::Kanji => 8, }, Version::Normal(10..=26) => match self { Mode::Numeric => 12, Mode::Alphanumeric => 11, Mode::Byte => 16, Mode::Kanji => 10, }, Version::Normal(_) => match self { Mode::Numeric => 14, Mode::Alphanumeric => 13, Mode::Byte => 16, Mode::Kanji => 12, }, } } /// Computes the number of bits needed to some data of a given raw length. /// /// use qrencode::types::Mode; /// /// assert_eq!(Mode::Numeric.data_bits_count(7), 24); /// /// Note that in Kanji mode, the `raw_data_len` is the number of Kanjis, /// i.e. half the total size of bytes. pub fn data_bits_count(self, raw_data_len: usize) -> usize { match self { Mode::Numeric => (raw_data_len * 10 + 2) / 3, Mode::Alphanumeric => (raw_data_len * 11 + 1) / 2, Mode::Byte => raw_data_len * 8, Mode::Kanji => raw_data_len * 13, } } /// Find the lowest common mode which both modes are compatible with. /// /// use qrencode::types::Mode; /// /// let a = Mode::Numeric; /// let b = Mode::Kanji; /// let c = a.max(b); /// assert!(a <= c); /// assert!(b <= c); /// #[must_use] pub fn max(self, other: Self) -> Self { match self.partial_cmp(&other) { Some(Ordering::Less | Ordering::Equal) => other, Some(Ordering::Greater) => self, None => Mode::Byte, } } } impl PartialOrd for Mode { /// Defines a partial ordering between modes. If `a <= b`, then `b` contains /// a superset of all characters supported by `a`. fn partial_cmp(&self, other: &Self) -> Option { match (self, other) { (Mode::Numeric, Mode::Alphanumeric) | (Mode::Numeric | Mode::Alphanumeric | Mode::Kanji, Mode::Byte) => { Some(Ordering::Less) } (Mode::Alphanumeric, Mode::Numeric) | (Mode::Byte, Mode::Numeric | Mode::Alphanumeric | Mode::Kanji) => { Some(Ordering::Greater) } (a, b) if a == b => Some(Ordering::Equal), _ => None, } } } #[cfg(test)] mod mode_tests { use crate::types::Mode::{Alphanumeric, Byte, Kanji, Numeric}; #[test] fn test_mode_order() { assert!(Numeric < Alphanumeric); assert!(Byte > Kanji); assert!(Numeric.partial_cmp(&Kanji).is_none()); } #[test] fn test_max() { assert_eq!(Byte.max(Kanji), Byte); assert_eq!(Numeric.max(Alphanumeric), Alphanumeric); assert_eq!(Alphanumeric.max(Alphanumeric), Alphanumeric); assert_eq!(Numeric.max(Kanji), Byte); assert_eq!(Kanji.max(Numeric), Byte); assert_eq!(Alphanumeric.max(Numeric), Alphanumeric); assert_eq!(Kanji.max(Kanji), Kanji); } } //}}}