qr2term-0.3.2/.cargo_vcs_info.json0000644000000001360000000000100124320ustar { "git": { "sha1": "08289926c9890d1536bbede302019bece81aa21d" }, "path_in_vcs": "" }qr2term-0.3.2/.github/FUNDING.yml000064400000000000000000000001611046102023000143750ustar 00000000000000# Funding links github: - timvisee custom: - "https://timvisee.com/donate" patreon: timvisee ko_fi: timvisee qr2term-0.3.2/.github/dependabot.yml000064400000000000000000000002211046102023000154050ustar 00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily time: "04:00" open-pull-requests-limit: 10 qr2term-0.3.2/.gitignore000064400000000000000000000000731046102023000132120ustar 00000000000000/target **/*.rs.bk Cargo.lock # Vim swap files .*.sw[pom] qr2term-0.3.2/.gitlab-ci.yml000064400000000000000000000023351046102023000136610ustar 00000000000000image: "rust:slim" stages: - check - test - release - trigger # Variable defaults variables: RUST_VERSION: stable # Cache rust/cargo/build artifacts cache: key: "$CI_PIPELINE_ID-$RUST_VERSION" paths: - /usr/local/cargo/registry/ - /usr/local/rustup/toolchains/ - /usr/local/rustup/update-hashes/ - target/ # Install selected Rust version before_script: - | rustup install $RUST_VERSION rustup default $RUST_VERSION - | rustc --version cargo --version # Check on stable, beta and nightly .check-base: &check-base stage: check script: - cargo check --verbose check-stable: <<: *check-base check-beta: <<: *check-base variables: RUST_VERSION: beta check-nightly: <<: *check-base variables: RUST_VERSION: nightly check-msrv: <<: *check-base variables: RUST_VERSION: "1.67.1" # Run the unit tests through Cargo cargo-test: stage: test needs: - check-stable script: - cargo test --verbose # Cargo crate release crate: stage: release only: - /^v(\d+\.)*\d+.*$/ script: - echo "Creating release crate on crates.io..." - echo $CARGO_TOKEN | cargo login - echo "Publishing crate to crates.io..." - cargo publish --verbose qr2term-0.3.2/Cargo.lock0000644000000154420000000000100104130ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossterm" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags", "parking_lot", "rustix", ] [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys", ] [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "qr2term" version = "0.3.2" dependencies = [ "crossterm", "qrcode", "regex", ] [[package]] name = "qrcode" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" [[package]] name = "redox_syscall" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustix" version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" qr2term-0.3.2/Cargo.toml0000644000000031400000000000100104260ustar # 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" rust-version = "1.67.1" name = "qr2term" version = "0.3.2" authors = ["Tim Visée <3a4fb3964f@sinenomine.email>"] build = false autobins = false autoexamples = false autotests = false autobenches = false description = "Stupidly simple Rust crate to render a QR code in the terminal." homepage = "https://github.com/timvisee/qr2term-rs" documentation = "https://docs.rs/qr2term" readme = "README.md" keywords = [ "qrcode", "terminal", "qr", "code", ] categories = [ "algorithms", "rendering", "visualization", ] license = "MPL-2.0" repository = "https://github.com/timvisee/qr2term-rs" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [lib] name = "qr2term" path = "src/lib.rs" [[example]] name = "example" path = "examples/example.rs" [[example]] name = "example-read" path = "examples/example-read.rs" [[example]] name = "example-wifi" path = "examples/example-wifi.rs" [dependencies.crossterm] version = "0.28" default-features = false [dependencies.qrcode] version = "0.14" default-features = false [dev-dependencies.regex] version = "1" features = ["std"] default-features = false qr2term-0.3.2/Cargo.toml.orig000064400000000000000000000015411046102023000141120ustar 00000000000000[package] name = "qr2term" version = "0.3.2" authors = ["Tim Visée <3a4fb3964f@sinenomine.email>"] license = "MPL-2.0" readme = "README.md" homepage = "https://github.com/timvisee/qr2term-rs" repository = "https://github.com/timvisee/qr2term-rs" documentation = "https://docs.rs/qr2term" description = "Stupidly simple Rust crate to render a QR code in the terminal." keywords = ["qrcode", "terminal", "qr", "code"] categories = [ "algorithms", "rendering", "visualization", ] edition = "2021" rust-version = "1.67.1" [lib] name = "qr2term" path = "src/lib.rs" [dependencies] crossterm = { version = "0.28", default-features = false } qrcode = { version = "0.14", default-features = false } [dev-dependencies] regex = { version = "1", default-features = false, features = ["std"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] qr2term-0.3.2/LICENSE000064400000000000000000000405251046102023000122350ustar 00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. qr2term-0.3.2/README.md000064400000000000000000000031501046102023000125000ustar 00000000000000[![Build status on GitLab CI][gitlab-ci-master-badge]][gitlab-ci-link] [![Newest release on crates.io][crate-version-badge]][crate-link] [![Documentation][docs-badge]][docs] [![Number of downloads on crates.io][crate-download-badge]][crate-link] [![Project license][crate-license-badge]](LICENSE) [crate-download-badge]: https://img.shields.io/crates/d/qr2term.svg [crate-license-badge]: https://img.shields.io/crates/l/qr2term.svg [crate-link]: https://crates.io/crates/qr2term [crate-version-badge]: https://img.shields.io/crates/v/qr2term.svg [docs-badge]: https://docs.rs/qr2term/badge.svg [docs]: https://docs.rs/qr2term [gitlab-ci-link]: https://gitlab.com/timvisee/qr2term-rs/pipelines [gitlab-ci-master-badge]: https://gitlab.com/timvisee/qr2term-rs/badges/master/pipeline.svg # Rust library: qr2term A stupidly simple QR code renderer, that prints text as QR code to the terminal, and nothing else. [`example.rs`](./examples/example.rs): ```rust fn main() { qr2term::print_qr("https://rust-lang.org/"); } ``` ![qr2term example screenshot](./res/qr2term-example.png) This library is based on [`qair`](https://code.willemp.be/willem/qair), which didn't provide the renderer as a library on it's own. Credits for the actual renderer go to it's developer. To read a text from the command line and encode it in QR form, run: ```bash $ echo HelloWorld | cargo run --example example-read ``` To create WiFi credentials in QR form, run: ```bash $ echo HelloWorld | cargo run --example example-wifi ``` ## License This project is licensed under the MPL 2.0 license. Check out the [LICENSE](LICENSE) file for more information. qr2term-0.3.2/examples/example-read.rs000064400000000000000000000001661046102023000157550ustar 00000000000000fn main() { let line = std::io::stdin().lines().next().unwrap().unwrap(); qr2term::print_qr(line).unwrap(); } qr2term-0.3.2/examples/example-wifi.rs000064400000000000000000000011701046102023000157740ustar 00000000000000fn main() { println!("WiFi network name: "); let wifi_network = std::io::stdin().lines().next().unwrap().unwrap(); println!("\nPassword: "); let pass = std::io::stdin().lines().next().unwrap().unwrap(); println!("\nType (WEP or [WPA - hit Enter as default]): "); let _network_type = std::io::stdin().lines().next().unwrap().unwrap(); let network_type = if _network_type.is_empty() { "WPA".to_string() } else { _network_type }; let input = "WIFI:S:".to_string() + &wifi_network + ";T:" + &network_type + ";P:" + &pass + ";;"; qr2term::print_qr(input).unwrap(); } qr2term-0.3.2/examples/example.rs000064400000000000000000000001101046102023000150310ustar 00000000000000fn main() { qr2term::print_qr("https://rust-lang.org/").unwrap(); } qr2term-0.3.2/res/qr2term-example.png000064400000000000000000000676261046102023000155670ustar 00000000000000PNG  IHDR3QQsBIT|dtEXtSoftwaregnome-screenshot> IDATxwx׀RnzH!@B3T!tR SA@T){J$@HRH7D}>On̙3gfϞ(^ZuiFS[{2,gLkiii["""MGj|gq0fdY~8+(((((((@Tj5:Nz֭TTrw_3LHp%VPPPPPPP($I LFNV2 ^UfhtxB*(((((((Xl&3++[T>U*Uׇ-6 dZ-jtψja `- Rja `- QPPPPPPPx[>^ZoM/&(Ό?Vf[ OMxLRUlHPmJ26 7c:-J` {ǔϡQ+s3\Ybdw:H{ԴO[mi1 QY0fcԹۼ/o|aCs3؇e((gKyӦ^S52`: Á j; @ݺ9-'ٱvIqf? xui^go:Ս0%zE"kT63lb.gxtœ] '6|UH]x?y 'g u#&F.ovgi:+,dPU){*H7{,bɟȼXFԕKޣ}0Y!ܗ.vӢ cki|6#a3v rBx6^ I{7k.a[ jh~d/8Iky=2js@t ʀ4Ԓq.eƋʀu:''CoNYť:@p${E;{w$y ӖB\dW|쵗0h RlK* MN`t4ژJ|-B|NjG5N֍U*Đ_xwԷ,\-y{~;TuK~JS禴fߵ2d)fX>l G֡,a<QZa:4fl̽ܥ(@!NF0ER̬ʛNOR^ƐDw3 ٜIJGz<5~ܓӮ5͞dwCG*BpL[;)CCKv tW,ƐLTl[1hV\rd zbh X:>ۃ%CpCT-K]+zw@oba1  R{6 YF1qnAޏ/楗T5%Cc(,\Z?۷;j̪rj=zhvx:tfЧGI?E<bi1kcelULCt|s5>5۵NZwz~ Ҿ;{؝ڝ}PQly?;"k?lHI=&Z9sеkw #YjOztnG?q C#@+(#E6SVuU%f-G$@C5+v54E$`3`ĩtoBi-L*#(Gㅪh5q7/GoHf 1ĤkSNdd[Xm5)t'}6[#$ Ҙo (ҢaC\3qk$u/4*?MA'[3O'&#-ݚLsc v׻&47AG^aubz4Rns7vz{4dLiQQtuT&o"{kt &vҭm79]1w3=,ɧ4ے)#/8"uet-/r:!bƶ|_$dRdf>OT9M޹kd m<u^R荦iO +D)GndUKZM,_~okQBJ*[ah*դnm/ v| v$#I;זllD2fgt9^LA7]Tv9({Ofm>apzf?Cz. !.jŜ͂SKy;҄klQ[\>uT;Z}n aRV_"+h"0x}(9x~AQYd>&0y%Y3lNJblajg5Ԁ1]{#s#hR;K6Y HHFcob[ŗX2z#wn%Z!]qU }*Tv)-+<7mZ`ĈLȜ?=f 6criZk}E9hRAG[o4+ Ϝ͚LDjk'|S_fʈ /CO݋ Yrxƪ2ǦxkeG)LL*(U 93A xsy_`ܲ?p. :ŀhFed\BHUĚtZ_\:k#ӛdX w2ϳyU+RPPP( j2ݭ;giWjG.3#{h!cS}ѽm3hHNj"ՋNӍ~j<?#ؓ}x{6&v0X7[\b I 8ScTŇlj.48AͲ,ǹ-~sdgpT z?S#UwkѤ Aٿ1V\+ؠ!666ĶXCT=vsҤ{-MD2BzOt : znERtx%?~'"t%SP9r+O8~Q"52 "gO6 Ͳ,E{xHJ 1tT} sEZxx3{%ú4b~ ]/ƿZb2) } uƏN”E莝_{UCl:a+`,649/W|~jn'U`S Nѓmއ{}7On!9*0D$E7 8 ."jؓ2vMU؋wgr'3w"9cfVtz>Ggeo uqp K"3w2 K<Ɔipss8H4nZOT#d$ vI_-_mG[:A.n)skdеWZc ж2-v9ErW n#Rm-Q97LD|M3&ٲw\i>$kp>ޚ@ -eL]'SyCζtrot;ɷi;Y~T'7>'3'.F8Ny_')RUūTm{'䤑pp-dTU1ך5sq@Q!礒H?JZgRqF ߩïFU{~z(n^z4S"H:g6ֿty0 WrEe&z: q$l]ĥH*_Zt|K9J{w<;cDf-}/*`ٯ#Ia',1sGХ]#W933`WaHjOZ6G=d$p%v}$ڬڋSf¨IpMgh8ʔGUcr#|۬Y$8|^Sp1|aH3c14}C_/೥gHA܋/I8a/204<O.ݦ|r4jɉ8YK6u*vx}UqA'r>6?m # Ec$&LFwLD1r{Ld>jP5~j<PzJ7d٨:EGe;c"[]K .yq!_Me:kYYUfrD  7AWGD] ͇z:L⬒H8k&QMtu,HcID95<ޑA;GsnqL K"%DeW =ͻ>*3Re--?Ԣw}-zfXXwQA&-LF][z ,l{ӼK-kҺ]uhVKU/93A7ѓʣ?AV8ItL;l6 09MRL22Rk.">(:+I/mHqL=UqrrmTk GOh#6B6@""oLe@6l̂~@ށUhW^ou9B#se'wB+ڸBt9*=7 %mDyFvy9vJi4צ08ޛ#;NDl+?{dX,=H_2^NǓ} 1sG~̚]w釫X?wVb3/1u62y=i;=7jd: 7Lmg:$;|۴~N>}q,Ϧ; zܱ-fw}&uvYa'|0:jуn}@oAnS?~p84v4x0d4ukj%Ƭ#?c%7goƮZ^~*B?6jӉl)tt$C wڼ4B5]^RDvs};GO]n=8 s0[R(\WDegp`h+ f&xYb Ml:uFs?-Uv_h&>XR[Af5. ,v͕Ag#tyEg q ř5-]e& .6ѨFN 6^) ڂy~Js\zNSC;G0799hvka;Y?;ӤS~ 6r{q*iT8<=`ΗI*Q=w@ȹLȂ9܌p귐]f.AT),Vjΐ_Oxdfbc+ekyu'Em_h3CΩC?z-n)u\ƙQtv}6GW6YF08}0o*rś,j˥åŠM1GIBF@KX?f;?,h/UQϣN!g^*s!pd3 y6IñKռ|`J&APIjjqil:ʈycbgF #I$cQJ"`^@#tG"Dȁࡥŧ:f~UFIjBe5@buu=q "#dimQ:":sZxv|*-`+&z $Unrqg.v"e,[dceR<0SQF3UP#GI˖VdD2 %{N,A~MЯ߲L8G/KH$2Uz%U?pj [;Ưv/b*5*\ ^ !IX<(!A(fU"f.uyQb. H#`"S*UӪ=Ce_qGT6c6KK#`|_PO4gvyueiލ@Ns*{/ 9sI\E<.TCE |l"z., Z.0pA-3ˁT~NųFdWUd)wHdA ! drL p= *:c\]a 6: (\'KKuLlW;":,A2=Ѡ] r("6ȉ8{$y|gMw;.sgSqyv SĆʘ"ɒb_ vK3rE7l\D40nI2!7; 2ZCi1D$S)$j7pF _6V'P91Hq QWrqBN-yTH  ޱWrUod+ )"WTu..:K6,U綍֕l*gB [x!.~݊r4mdhicEB+L])x }급'[ )ӥ \5qc~ "d`[{&A0l&bĴäXݦ3;{[BGB@kWV&+1d=vOU~o 93fr$m]Gfӝ3y7ĝb&x7TxvF",q'#i9,Ō-\OmGpl" 7sljhEEo.e"~ϔM \5G#H\8FJ|kAO߸S7ʼF#njSsxlJٷ#0~h뎢ù6 bsʖG OtlGyތ/$bi?w/Fm]j|+7S07b̡[q5OTĥx&GcLW9w0ZJFt bȐn;^u\Z{&w@~_ iqb =" l %._ap:Gf!:ʝ ?Y} w'p 4SrV}7%o-ba ۃEj=*dSmV)9[`X0ӓXw0kcceFu܈9cwڎ~|W2r]40qP#>}'0y;n#(v%!~>#NpM[B0[T/E?G‘#ٜVI*W%̶כ\~ pH$0Y"{G4D}S_ie$2IK]5Lmkr{9)INpqU,d4ʒ4{ĿfK͡";gg$RgA&#LFb̔,i:iZ,P3ΕӶ.fsnlP'PcKQ(:-$?Ʊ䄙m~9;> /ߞ96h wOr<ѫ%U<#f#UJ:H"ÿt[?~͐xT^@zpf|e=\k폝{UT9D&"iKʒ̍Kīd%fls} a"UqD> 㯓}A:JFeß~1`"5"G?¬xS"jT^{1cԗqȊsK)p~s'2oyY93 Yc]^|}uD]0&ߛ̗.NBwKY5hJBAwo,&â:⮞bWHfOjU =0nx[)k'Ysdy1HYO8YAmlplڐ~?_y/&ѡEL/^s\Y5&]/E?G!֣)*穑"[r(YPKɷzt[ [8yш:42Tf2Ñ/<7Es>Viw*{Xm+O#atT!*y~nĽAaFяUco3"mVIȭ뉪--Gѕjz1kx9k1~b;s-b%m(((Qk+;+((((((?EqfkgZh9\wZWG 5>vgˋ]hc] mGæb@]h2ukPcVm tz4pf=)DJEû ˉd{|hK'VmGpyC/Riޘ<]15vdy}:RjrjTf6 ְtSԫlMPNͶ{vr}GәQiϙ}Zpk^/ICyGG"LW2v ]jͣk*ht^Rw懏 u=ޒD**k/'o0'7K˵+vg5aA6tH[mɬwg}I˶^-1Vl[_~{x~QϿ'/xY[#dE>Z0|_qmgPI;c"%%_R#dawCEΞlʻxE`LcH"4\z> ^ba8^HF\<#2݇5%zPlޑ!?ǽI=8VEOrv&ʹۖj|Tn2~K9|㑇ٴw9;;#`a{Ybwm8j2|ϕv {(,yR;~qW8|+s}GvHC,Pb=e2#F_/X쎺ޟ gLȣl7b99+F"OYf?K9;g3Gwnfȏ+c؋u,!Q7&uQXwxG=[,^/}HQf"h+JU AĥW/3hpR9s|̰e_)L E눨9]SLj88VS]{8sJC=c$WSm'm:}n¬W+;j)LJSr(Hp3 lui0 &ьU|5i{|Gi}2Tfwc᱋G#|i׻6Y{Wp)^viK>J4:cV/ pֆ=⋑&v~8WDj0Vg;OJXIV˓* bL0^^=d4 WXdd)ј9q;>y[э_ϋň'?>0tV Msٳw,̄.ˀԾ1~nݧT6E*V&E}3qا=γ) {~c͝g3Fz{,i/Klˎ[' 칢+?m\7t/kYx"wQILhBz^eKBQUMڤR5g,aƳ7q @tZ cA˅I3ѡ?{WVXP OIqG`L=%: Yƒ}'-̵yxY݈IsZ=[ƣ̨DsFgzs6Ndsttf{iH38{^vIŹSfEL 0X46(IV,st<1N&6:}ùJM$j rCd.P}#ΈUf7.?_B7KC1ѯb=@Aȑ's 71^pt r67HqM(I%ZĜF43H(-N,%pϰS>&Ben[*=N%6%mSmT5βwMmLЋ(-xd -{3Թ<,_?;۪L6&Xb-yc'7Ez%Ȇ7lBnd׮IDdZԩ ?])aOgHDž++W4CLOو i]\lvXT&BJhirrCh;3Lyw̘ rW:W,=l&rzuxHA&no7pc),5*n)r*HM}*@[Z(6SbS7 #_ j b7D6%sF熋 >V2#"2]7[E䷰)S"?~y !wCPI, (Z{&C [ +cI&X`I ~5_5 ¢W3<ଏ .nsx$PC]^ ulJE/+j{Wы3Wө.^." DZ>hš^+Q޳9\}؉s[ϛؾ'ʐHMs+k6c?2g0O+pHA)-vf$38{tw[ԂdM.gyMۃ4=JG ~t.-ޤ%MN!N~f$eDR:hO dލ̷}8~Td77¤Ȟo61+<;&y3bMB@,%$3ZrK2BݗO#wә1%[PfoG’-iSKl̗WZhPY_Z9#$"-=l#^{OؘJ #&KVZV-| R/ VX^MApkӬYg Ǩ2eI' HF&{r??tEOь;.Lq+|E{Y{0G%QvBm@pr\>WT>P=[t tW|k O0#mR8^ϩ-.++L* f7Hq d!b UDL.pPk_no7! ~e`x LCq .US+R" q{4]"P|ӢƠt+\v6Aޱ4rΒq(e1I lK+g>?.FЯy2lIZb+|7S1Sz=bKjQ45x A̡!D>4neA߶rPkҸ !k`զ\t/mM=[eSS(׃1 `Lr'8&V6u/sbq"#ǝP][WܚD"'Py@SklvdR^ju7VўYD[RQQoڎYuE2nJ{.Ъz8P=\",`WE y~{JpZH0m \wߎ׿bMOE|[XpM]WN+uU&eZܼa8LL {4?EIB'qb 0cz`v-,EDmaw#Y"f=X2M6ٖ OVC8NT<C[z`B\$ΪM0v5 b,̆?Y1#RyLƶJcăj֡w¸lM-U4mxl >9mcR>f~;e W8FsW{`JyS(t q>2 ѱ>V6ji2G΄ul Zg_{Eq3[ . + ܫ+VD^{*V׎^ 6?EQ P$g3?z6=z$3眙Ny+Qm]|t\bM83? -~չϏ#5opoZukJƩ@t+dmX;ީ^Эqj{[i{sI IDATX _`+keu$ 5Ku}reL}lS\n5îԈ)Wz{{6}zkzU0[hpna/(W[Eo\[߭^hۂI3q'?$u iճշ?R0A/-ydL-x~bw.ЫF§^ԙMZ͗K+5PW=H%y|0z|Lp}ci$F2>ՓwZv@i(JǪS5fhՐ׆YO_waEpYګݺQ/T̲M{_5UhMJy:])ͧpQr7fh 8GiX+~[SH~5sϙM+^nA]"U~vf>ySjn}@GM?6snH[M}=}n9ZBXUdqwTMVmvO lm}r qY=QZ 5ĭ}1GW]qm:o8Wjq^{ ;Vw qwQLI}1:?n V:"q̀Փ멓ӕqme IPZv);/ֿ-~ur:j"ۨuW ?POUbTŹ,_t095ަ'_~[CuߧTzCWKdba5**IrӮτW8~ I| gioQIuwn=ZBZ~p۳?k|%~0]]{]\mZ8Iwi'Cp f6 0a֋Ws밽Zr)#֥GRL.ߢۯ hEx݀Y3Q64QKU;=f ?GB=jUצ$6U~'sXhpfWn4PB:uBjT:t>ٮ5(~8Ls M{w@Z1@$@ 17̤xuT0M.Jyo$irR$YQb>^%w6h>Ig "=:9CVAaOߤXhmuՎ~9ӹG^ft bưBnܙqz\r7;tk/oo‡Gk,VJ?D5>K>C;9+mw;2r}F~Ֆ~sqqjE5e +݀Qy+^PXn(i{KgIyu4]8?Y]ۗ-^]8M(HKmNRRt4]0?Ug#q!e|u4 2A.|H%In)Q/UC2tތ96IG^l"=Rw,^~J-uϋ˧h‹?~?;m&nYY9o[c:gn\M]iыh 4ѷ=iiZ;a=%mW\:5ik&Pv^{ !ԷS~;c/?Lhdh⫫t~ѵWY45'CWw^q;Qç.QwOOl[7kZ_i=tzdqEwUww5jdw8 9]|z~YizTX3}o =~_|"VRg z-}rf.Ԕ);;U2;T sgf*`˟tqσKzTT*쐥?QUy53eae(]jp[^fd[nڍJ'Xry-Ogwݒ5V+Æi5}z;#$Q8wӮ/۾H?qYUEV:]xn}y-^V4rzTO\!ySZY^*Q=GsWYʬmRS7.e]mtU|~27_uL7? ;6Vjˏzzn++]'=FM_UOCtѻ?6XPG[Cj>Z]7 %柩JE2>+6oV\S<3gVVZ`ܒOŪctuM5Ge'YK:5xm#l.:uPKmzvr5.<yelIS'#מC4#8;~Z"oot?o*AI"CG??7}Vwwщի}_ϋ${VΞ_2TxYVO[m Ҽo˳3k HmbiX]r3SER5~y0Mʙgjֲbϕ1__3.KǗOێ6<p.ꖿKjq$඼\wK6Fr}:QKEYE1>9x9TO+*2sO꒘W~ѴwxZX]:U~;kLpwvrzF=z͝)#md|"Wmhɳk w#G,$ۖ#K.W%tA﮶O-ﲈ_%#>3npq +Oaec~) izB^WUxIؒ,]K.XU\rI*ɔ}ֳSKeSys59}M7ި)Kre=^׾K3q{VPP1Ӳz}q5zw^ {hN^u|l3zwU,"mOLjUXgGmٶVtd|"W5p}W!|2 wz +D.){bZV|DدecuQiY/_Yٻ71_i3$G[_+'qzlP3~q$QID;Y?F6QБ䶔HKV@].]VAث>U ,%Vy* JJTj%))Y&oGu=1cWGKjZ㜡G4 "`K6|3ki^:vN_}/U=Q'4Up^%)[۶JjJu]*|T_ms|]:,1]~[zx.W9~p6,~Um$W38‹i'P'RGVR,)ӵZ"q_o COZk\ȏg$H j!Q|Z<%PXluȥ&';r5u3ae-wje)!9)),,* >׭CI!f[˅W/::5=UٞjX|D -Tyhnf\)]԰_oCWݼ҆eM_WG(;z+5yS|m._wi_OXq6ӛo\n}IOnP jլ;iK)!GRWiĝ9`f칭HgIt=Ohx qZ%=|͇twDi=|]w+j:~6}7=9yZhܗalT5z+Nnc'kLnj h=fêg4'H*]Qn~u1CWU0oJ ݭKABeɔ$9"} _wvF\VOvۓ?͎$쾪k]jֽuwۓi˒nَ_qf r20{^:i+֨;reL_^T'~#]W'Kфn1=8jcS^)MRkАq*^=K_]}^!ezPowGg.٤Ecw+߉`_XrSuĕ+ܵK4ɛG[wc`GB;˒?M K[z,O?'6mvey3,U/W]qm:obc:jfVH㕾.m[uYrrZ?_\ZH6}}9e/HǼ~}31Jp7V!nkkIr~.ղJrnણа7QO,J]~o*1_11j#GB;Yv!C{{3_a0FF#f3h`4 0a0FF#f3h`4 0'+h\Q{gtTF{p_ 33h`4 0a0FF#fѢZ4/&"l*mXjff3h`4 0a0FF#xѼHX-W$mVa='Zjq 33h`4 0a0FF#fbh_Y E"֊Q8p F#f3h`4 0a0FR8Wռ4t)E{͟$ >Ny ߃5Jٟpp5H٨bW=%=Ami!wjպ]N\q:W_W9RmD5@HoP?Վ I:ǧAM>POsRZ[keu5^tSV G =JtBVS)z~NMm-[dz\ϒm-i]EZ|KMS׳Jo 7鋀02u}~GOE}lIR7Na|j|Hx˫z.y}Jׅ^V#OH/T )m{٧MRF8Z#^](XҚ7JuX!'}4k ϼC\?|M~Js+瑊w9 -kwURZ`[*7d׮Yg3Y쵌]Cp61VU\\Qb_ +mr'Eɑ%wުӦғT3eVS4 +s帛OmץV۷_]_uOHT¹k3S-~Je=) uKIڤ˶߶-6nZ8A^9IDAT“ oOQY[N%Iư2 j*G2 jA)eO Ԯxe޶5`)4B[NvK+*s~5IR-*|^Q%u#ۖ,KF$ȋJ6=mk%%-32I'^SֶaRq$+ťͅ$iBG#L*1aM|:rOIu:~a-DYRgupғriU'\";yZ픚FJ誖h$Y CrV^QwSu%9rri뼙ںxr^Zy35c{YeɕsÕKUTfUy·:RJty`KQURGlZ+sH$'9JU TV;Ky+W+F ܦCag=.yuRZT7,WDuiަ@KeSPc/50GBKt΍:ZBK˽!q^(_jשī^ekPKVszPפ~.%Փ³JaOmzԴuTOn臠p$r%qet~~VXoU\ɯCtIK5cX $W+ݯ>!-w0]jbv2B 4(=Ery˻>X*k?AJ$I}vao\Ch E虤'RBG91^~u;ђyV%^5گc`_hm s5#UrihZVߠN'w`NP۵:O6֬j[cԠKN,e-5 b<]-;*O< ٖyA4d?S= ^[g<5Sx'xon3Iu?,+P˟|Xk7JzmXz셯i /_orQsnQn}sr#nռY_UK^xW9%aun:Ii_/Un*k_\mam=y蝣M>_V ⒶlѸձc9&ևLJbg`^;ToM$\VXnUpX?ƽ'2DžԩGJѠ!!T+ǖjKyQ[M2Bu-)VϣV,9+J4RGv-tjݧͭ=?$CiX*QOոd/*պ&[nɞԺ̲Mj[ȫ&ݪDڰlm^].R=WXN\595cd25R{)QpTm'KwIv\eP5o]֞5Sysp )pJLM.K/gZ'`,ZuTKҎS{ωu[AGbɊg+TT"G^ʟ ?m&ۙgiC41:t#ʦ 6fvS_ KR|-_Up_)|jRFRxnV.޶r^/Է^=ӫf'yz\ׂ7ۑY^OU{cl[9h.I!IuI[!1s`5gkZđ8qξ'I_ /XM`vc;tؽpH>?rKX/qTpU~d)Wzu=ϻ;֤&+1`0..;x䳤geg)pʦݖIZ#Y~ &G٣񨲟sVGWK*鉪eRb;KJ5ozy,5/Y' q͟TⰊ%6w+D+'e/q⼎J’+eJ$%Y; $WKR|=j5v+/9YA-yTK:~:g>Y|:QCZV<:8e]Rưf9P5,MRR?y$gsX#e\{yrKGY;ޙ*fO۱BmPVݾZrT֊OBUlTbcդ/ZΧo+*),媫tez`.-[N=y-ԑ,_ҒGjO 9mCuԦ<`p*4٫?/ @m_RUb#m\SWo|TH_ݦ$ҏj٠6}dlX mSf ݊?&^RB~;PkwLq熕Tjգ'e䠦/VIPW%gU@ճmmr4:ISlU\b)K#- $Mnuz=YV*[Jhfi-;e r+NMqd}׭@]g?{uHy~%7.mYjYVgyRռM#43Kԣ_G\w-[Ug4<ɫLQMRb[rqt@Y~Jy{W6Ҁ|,UqJu3Y7^k2NVr_]URnnjs3j?>C |M9aIU~N[:^#;]Rig{)$hx:xVs\kܰyQ{˒j}Z5RyZ9u>_fWNR\4Lʮn*j~\ ~ѼUh'qC5cP ޟ< Q,&mae-. WW,-'֒T8nam[+n)1A,ZҒ#MB+}juS)2{HpjӘ5ʜ6I'UONz{umXUv|#%qdFw;‹>sUX`[+)[ϊ=Z9?ZdO$cMW\K%o]ۣzsmvhӘeo̓N %Om-NAg ~6+}<]=tmS-zU8GB;އ헥']:ёmm_zzܨc'϶5{[&: Vwc5)oOo쟶l{i/k4Bx`˛5!}7??L-jRqz]Ό"}ҿ V:LVܩWM8FG^kT^%)Mnj L¶6P_n)[u-deX?v?L ;'Ȳ7j˜hUl7Sj8$[ &*soЉv+2Y\f;LAF#f3h`4 0a0FF#f3 fJd 3 fYr߭Zb=5Z0{$yrZrcGB;`4 FFݕtݷIENDB`qr2term-0.3.2/src/lib.rs000064400000000000000000000053431046102023000131320ustar 00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #![warn(missing_debug_implementations, missing_docs)] //! A stupidly simple QR code renderer, that prints text as QR code to the terminal, //! and nothing else. //! //! # Examples //! [`example.rs`](./example/example.rs): //! ```rust //! qr2term::print_qr("https://rust-lang.org/").unwrap(); //! ``` //! //! ![qr2term example screenshot](./res/qr2term-example.png) //! //! # Based on //! This library is based on [`qair`](https://code.willemp.be/willem/qair), //! which didn't provide the renderer as a library on it's own. //! Credits for the actual renderer go to it's developer. //! //! - [https://crates.io/crates/qair](https://crates.io/crates/qair) //! - [https://code.willemp.be/willem/qair/src/branch/master/src/console_barcode_renderer.rs](https://code.willemp.be/willem/qair/src/branch/master/src/console_barcode_renderer.rs) pub mod matrix; pub mod qr; pub mod render; pub(crate) mod util; pub use qrcode::types::QrError; use crate::matrix::Matrix; use crate::render::Renderer; /// Quiet zone size in pixels around QR code. /// /// Should be 4, but using 2 for small terminals: /// https://qrworld.wordpress.com/2011/08/09/the-quiet-zone/ const QUIET_ZONE_WIDTH: usize = 2; /// Print the given `data` as QR code in the terminal. /// /// Returns an error if generating the QR code failed. /// /// # Examples /// /// ```rust /// qr2term::print_qr("https://rust-lang.org/").unwrap(); /// ``` /// /// # Panics /// /// Panics if printing the QR code to the terminal failed. pub fn print_qr>(data: D) -> Result<(), QrError> { // Generate QR code pixel matrix let mut matrix = qr::Qr::from(data)?.to_matrix(); matrix.surround(QUIET_ZONE_WIDTH, render::QrLight); // Render QR code to stdout Renderer::default().print_stdout(&matrix); Ok(()) } /// Generate `String` from the given `data` as QR code. /// /// Returns an error if generating the QR code failed. /// /// # Examples /// /// ```rust /// let qr_string = qr2term::generate_qr_string("https://rust-lang.org/").unwrap(); /// print!("{}", qr_string); /// ``` /// /// # Panics /// /// Panics if generating the QR code string failed. pub fn generate_qr_string>(data: D) -> Result { // Generate QR code pixel matrix let mut matrix = qr::Qr::from(data)?.to_matrix(); matrix.surround(QUIET_ZONE_WIDTH, render::QrLight); // Render QR code to a String let mut buf = Vec::new(); Renderer::default() .render(&matrix, &mut buf) .expect("failed to generate QR code string"); Ok(String::from_utf8(buf).unwrap()) } qr2term-0.3.2/src/matrix.rs000064400000000000000000000055171046102023000136730ustar 00000000000000//! Matrix types representing 2D barcode. use crate::util; /// A square 2D matrix representing a barcode. #[derive(Debug)] pub struct Matrix { pixels: Vec, } impl Matrix { /// Construct a new QR matrix from given pixels. /// /// # Panics /// /// Panics if given pixel map does not have a length that is a multiple of 2. pub fn new(pixels: Vec) -> Self { // Assert pixels being multiple of 2 util::usize_sqrt(pixels.len()); Self { pixels } } /// Get the width and height of the QR code in pixels. pub fn size(&self) -> usize { util::usize_sqrt(self.pixels.len()) } /// Get the pixel matrix. pub fn pixels(&self) -> &[T] { &self.pixels } /// Surround this matrix with `quiet` pixels having the specified `thickness`. pub fn surround(&mut self, thickness: usize, quiet: T) where T: Copy, { // Calculate widths let width = self.size(); let out_width = width + thickness * 2; // Build the new pixel matrix, move given matrix in the center let mut out = vec![quiet; out_width.pow(2)]; for vec_row in 0..width { for vec_col in 0..width { let vec_pos = width * vec_row + vec_col; let out_row = vec_row + thickness; let out_col = vec_col + thickness; let out_pos = out_row * out_width + out_col; out[out_pos] = self.pixels[vec_pos]; } } self.pixels = out; } } #[cfg(test)] mod tests { use qrcode::types::Color::{Dark as QrDark, Light as QrLight}; use super::*; /// Printing a matrix with the number of pixels not being a multiple of 2 fails. #[test] #[should_panic] fn matrix_incorrect_size() { Matrix::new(vec![QrDark, QrDark, QrLight, QrLight, QrLight, QrDark]); } #[test] fn surround_quiet_normal() { let input = vec![ 0, 1, 2, // 3, 4, 5, // 6, 7, 8, ]; let expected = vec![ 9, 9, 9, 9, 9, 9, 9, 9, 9, // 9, 9, 9, 9, 9, 9, 9, 9, 9, // 9, 9, 9, 9, 9, 9, 9, 9, 9, // 9, 9, 9, 0, 1, 2, 9, 9, 9, // 9, 9, 9, 3, 4, 5, 9, 9, 9, // 9, 9, 9, 6, 7, 8, 9, 9, 9, // 9, 9, 9, 9, 9, 9, 9, 9, 9, // 9, 9, 9, 9, 9, 9, 9, 9, 9, // 9, 9, 9, 9, 9, 9, 9, 9, 9, ]; let mut matrix = Matrix::new(input); matrix.surround(3, 9); let actual = matrix.pixels(); assert_eq!(expected, actual); } #[test] fn surround_quiet_empty() { let mut matrix = Matrix::new(vec![]); matrix.surround(3, 7); let actual = matrix.pixels(); let expected = vec![7; (3 * 2) * (3 * 2)]; assert_eq!(expected, actual); } } qr2term-0.3.2/src/qr.rs000064400000000000000000000014701046102023000130030ustar 00000000000000//! QR code type. use qrcode::{types::Color, QrCode}; use super::QrError; use crate::Matrix; /// Raw QR code. #[allow(missing_debug_implementations)] pub struct Qr { code: QrCode, } impl Qr { /// Construct a new QR code. pub fn from>(data: D) -> Result { Ok(Self { // TODO: error handle here! code: QrCode::new(data.as_ref())?, }) } /// Create pixel matrix from this QR code. pub fn to_matrix(&self) -> Matrix { Matrix::new(self.code.to_colors()) } } #[cfg(test)] mod tests { use super::*; /// Generating QR codes for text that is too large should fail. #[test] #[should_panic] fn print_qr_too_long() { Qr::from(String::from_utf8(vec![b'a'; 8000]).unwrap()).unwrap(); } } qr2term-0.3.2/src/render.rs000064400000000000000000000157211046102023000136440ustar 00000000000000//! Rendering utilities. use std::io::{self, Result as IoResult, Write}; use crossterm::style::Stylize; pub use qrcode::types::Color::{self, Dark as QrDark, Light as QrLight}; use crate::matrix::Matrix; /// QR barcode terminal renderer intended for terminals. #[derive(Debug, Default)] pub struct Renderer {} impl Renderer { /// Print a matrix describing a 2D barcode to the given writer. pub fn render(&self, matrix: &Matrix, target: &mut W) -> IoResult<()> { let width = matrix.size(); let pixels = matrix.pixels(); for row in 0..width / 2 { for col in 0..width { let vec_pos = (row * 2) * width + col; let vec_pos_below = (row * 2 + 1) * width + col; match (pixels[vec_pos], pixels[vec_pos_below]) { (QrDark, QrDark) => self.black_above_black(target)?, (QrDark, QrLight) => self.black_above_white(target)?, (QrLight, QrDark) => self.white_above_black(target)?, (QrLight, QrLight) => self.white_above_white(target)?, }; } self.newline(target)?; } // Because one character is two "pixels" above each other, the last pixel-line // has only white ("empty") "pixels" in case of an odd number of pixelrows. if width % 2 == 1 { for col in 0..width { let vec_pos = width * (width - 1) + col; match pixels[vec_pos] { QrDark => self.black_above_white(target)?, QrLight => self.white_above_white(target)?, }; } self.newline(target)?; } Ok(()) } /// Print a matrix describing a 2D barcode to the terminal. pub fn print_stdout(&self, matrix: &Matrix) { self.render(matrix, &mut io::stdout()) .expect("failed to print QR code to stdout"); } /// How many horizontal characters or columns in the terminal it takes to render `matrix`. pub fn width(&self, matrix: &Matrix) -> usize { matrix.size() } /// How many vertical characters or rows or lines in the terminal it takes to render `matrix`. pub fn height(&self, matrix: &Matrix) -> usize { matrix.size() / 2 + matrix.size() % 2 } /// Terminal-format and print one character that show a black pixel above a white pixel. /// /// The naive approach would be to use "█", "▀", "▄", and " ". /// Unfortunately, "█" and "▀" are rendered on some terminals/fonts with a gap /// above it, so putting them under each other results in /// a gap between the lines. Luckily "▄" seems to be rendered /// without gap under it, so we workaround the problem by /// using color inversion (so "█" = " " inverted, and "▀" = "▄" inverted). /// "▄" seems to render better than "▅". fn black_above_white(&self, target: &mut W) -> IoResult<()> { write!(target, "{}", "▄".white().on_black()) } /// Similar to `black_above_white` fn white_above_black(&self, target: &mut W) -> IoResult<()> { write!(target, "{}", "▄".black().on_white()) } /// Similar to `black_above_white` fn black_above_black(&self, target: &mut W) -> IoResult<()> { write!(target, "{}", " ".white().on_black()) } /// Similar to `black_above_white` fn white_above_white(&self, target: &mut W) -> IoResult<()> { write!(target, "{}", " ".black().on_white()) } /// Print newline that does not mess up colors. fn newline(&self, target: &mut W) -> IoResult<()> { writeln!(target) } } #[cfg(test)] mod tests { use super::*; mod size_tracker { //! Tracks how many newlines and character per line are written use regex::Regex; use std::io::Write; pub struct SizeTracker { data: Vec, } impl Write for SizeTracker { fn write(&mut self, data: &[u8]) -> std::result::Result { self.data.extend(data); Ok(data.len()) } fn flush(&mut self) -> std::result::Result<(), std::io::Error> { Ok(()) } } impl SizeTracker { pub fn new() -> Self { SizeTracker { data: vec![] } } fn without_ansi_codes(text: &str) -> String { let regex = Regex::new("\x1B\\[.*?m").unwrap(); regex.replace_all(text, "").to_string() } /// Length of longest line in visible characters. /// /// Panics if data seen by tracker is not valid UTF-8. pub fn width(&self) -> usize { if self.data.is_empty() { return 0; } let data_str = std::str::from_utf8(&self.data).unwrap(); let without_ansi_codes = Self::without_ansi_codes(data_str); without_ansi_codes .split("\n") .map(|line| line.chars().count()) .max() .unwrap() } pub fn height(&self) -> usize { let newline = 10; self.data.iter().filter(|&elem| *elem == newline).count() } } } /// Checks that the expected, promised, and actual width and height match /// when rendering `pixels` to a terminal QR code. fn helper_width_and_height(pixels: Vec, expected_width: usize, expected_height: usize) { // Given: a matrix, and a renderer for that matrix. let matrix = Matrix::new(pixels); let renderer = Renderer::default(); let mut writer = size_tracker::SizeTracker::new(); // When: rendering the matrix let promised_width = renderer.width(&matrix); let promised_height = renderer.height(&matrix); renderer.render(&matrix, &mut writer).unwrap(); let actual_height = writer.height(); let actual_width = writer.width(); // Then: the width & height promised by the renderer is the expected width & height, // and the width & height delivered by the renderer is the expected width & height. assert_eq!(expected_width, promised_width); assert_eq!(expected_height, promised_height); assert_eq!(expected_width, actual_width); assert_eq!(expected_height, actual_height); } #[test] fn width_and_height() { helper_width_and_height(vec![], 0, 0); helper_width_and_height(vec![QrDark], 1, 1); helper_width_and_height(vec![QrDark, QrLight, QrLight, QrDark], 2, 1); helper_width_and_height(vec![QrDark; 3 * 3], 3, 2); helper_width_and_height(vec![QrLight; 4 * 4], 4, 2); helper_width_and_height(vec![QrLight; 5 * 5], 5, 3); helper_width_and_height(vec![QrDark; 21 * 21], 21, 11); } } qr2term-0.3.2/src/util.rs000064400000000000000000000013221046102023000133320ustar 00000000000000/// Take the square root of the given usize. /// /// # Panics /// /// Panics if the given number isn't a perfect square. #[inline(always)] pub fn usize_sqrt(num: usize) -> usize { let sqrt = (num as f64).sqrt() as usize; assert_eq!(num, sqrt * sqrt, "given number isn't a perfect square"); sqrt } #[cfg(test)] mod tests { use super::*; #[test] fn usize_sqrt_squared() { assert_eq!(usize_sqrt(0), 0); assert_eq!(usize_sqrt(1), 1); assert_eq!(usize_sqrt(4), 2); assert_eq!(usize_sqrt(25), 5); } /// Taking the integer square root of a non-square number fails. #[test] #[should_panic] fn usize_sqrt_not_squared() { usize_sqrt(3); } }