Showing preview only (252K chars total). Download the full file or copy to clipboard to get everything.
Repository: kennytm/qrcode-rust
Branch: master
Commit: c7780e8549ac
Files: 33
Total size: 239.3 KB
Directory structure:
gitextract_xeat1q94/
├── .github/
│ └── workflows/
│ └── rust.yml
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE.txt
├── LICENSE-MIT.txt
├── README.md
├── examples/
│ ├── encode_eps.rs
│ ├── encode_image.rs
│ ├── encode_pic.roff
│ ├── encode_pic.rs
│ ├── encode_string.rs
│ ├── encode_svg.rs
│ └── encode_unicode.rs
├── rustfmt.toml
└── src/
├── bin/
│ └── qrencode.rs
├── bits.rs
├── canvas.rs
├── cast.rs
├── ec.rs
├── lib.rs
├── optimize.rs
├── render/
│ ├── eps.rs
│ ├── image.rs
│ ├── mod.rs
│ ├── pic.rs
│ ├── string.rs
│ ├── svg.rs
│ └── unicode.rs
├── test_annex_i_micro_qr_as_eps.eps
├── test_annex_i_micro_qr_as_pic.pic
├── test_annex_i_qr_as_eps.eps
├── test_annex_i_qr_as_pic.pic
└── types.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/rust.yml
================================================
name: Rust
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
check:
name: Check
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
fail-fast: true
matrix:
rustc: [1.70.0, stable] # MSVR and current stable rustc
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rustc }}
override: true
- uses: actions-rs/cargo@v1
with:
command: check
test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
no_std:
name: Test Suite (no_std)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: clippy
- name: Run cargo clippy
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
# args: --all-features # TODO use `criterion` instead for benchmarks.
================================================
FILE: .gitignore
================================================
/target
*.swp
*.swo
.DS_Store
*.o
__pycache__
Cargo.lock
================================================
FILE: Cargo.toml
================================================
[package]
name = "qrcode"
description = "QR code encoder in Rust"
license = "MIT OR Apache-2.0"
version = "0.14.1"
edition = "2021"
rust-version = "1.70.0"
authors = ["kennytm <kennytm@gmail.com>"]
keywords = ["qrcode"]
categories = ["encoding", "multimedia::images"]
repository = "https://github.com/kennytm/qrcode-rust"
readme = "README.md"
documentation = "http://docs.rs/qrcode"
exclude = [
".travis.yml", ".gitignore", "test-data/**"
]
[badges]
maintenance = { status = "passively-maintained" }
[dependencies]
image = { version = "0.25", default-features = false, optional = true }
[dev-dependencies]
image = "0.25"
[features]
default = ["std", "image", "svg", "pic", "eps"]
image = ["dep:image", "std"]
std = []
bench = []
svg = []
pic = []
eps = []
[[bin]]
name = "qrencode"
[[example]]
name = "encode_image"
required-features = ["image"]
[[example]]
name = "encode_string"
[[example]]
name = "encode_svg"
required-features = ["svg"]
[[example]]
name = "encode_pic"
required-features = ["pic"]
[[example]]
name = "encode_eps"
required-features = ["eps"]
================================================
FILE: LICENSE-APACHE.txt
================================================
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.
================================================
FILE: LICENSE-MIT.txt
================================================
Copyright (c) 2016 kennytm
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.
================================================
FILE: README.md
================================================
qrcode-rust
===========
[](https://github.com/kennytm/qrcode-rust/actions?query=workflow%3ARust)
[](https://crates.io/crates/qrcode)
[](./LICENSE-APACHE.txt)
QR code and Micro QR code encoder in Rust. [Documentation](https://docs.rs/qrcode).
Cargo.toml
----------
```toml
[dependencies]
qrcode = "0.14.1"
```
The default settings will depend on the `image` crate. If you don't need image generation capability, disable the `default-features`:
```toml
[dependencies]
qrcode = { version = "0.14.1", default-features = false, features = ["std"] }
```
Example
-------
## Image generation
```rust
use qrcode::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::<Luma<u8>>().build();
// Save the image.
image.save("/tmp/qrcode.png").unwrap();
}
```
Generates this image:

## String generation
```rust
use qrcode::QrCode;
fn main() {
let code = QrCode::new(b"Hello").unwrap();
let string = code.render::<char>()
.dark_color('#')
.quiet_zone(false)
.module_dimensions(2, 1)
.build();
println!("{string}");
}
```
Generates this output:
```none
############## ######## ##############
## ## ## ## ##
## ###### ## ## ## ## ## ###### ##
## ###### ## ## ## ## ###### ##
## ###### ## #### ## ## ###### ##
## ## #### ## ## ##
############## ## ## ## ##############
## ##
## ########## ## ## ##########
## ## ######## #### ##
########## #### ## #### ######
## ## #### ########## ####
###### ########## ## ## ##
## ## ## ##
############## ## ## ## ## ####
## ## ## ## ##########
## ###### ## ## ## ## ## ##
## ###### ## #### ########## ##
## ###### ## #### ## #### ##
## ## ## ######## ######
############## #### ## ## ##
```
## SVG generation
```rust
use qrcode::{QrCode, Version, EcLevel};
use qrcode::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:
[](src/test_annex_i_micro_qr_as_svg.svg)
## Unicode string generation
```rust
use qrcode::QrCode;
use qrcode::render::unicode;
fn main() {
let code = QrCode::new("mow mow").unwrap();
let image = code.render::<unicode::Dense1x2>()
.dark_color(unicode::Dense1x2::Light)
.light_color(unicode::Dense1x2::Dark)
.build();
println!("{image}");
}
```
Generates this output:
```text
█████████████████████████████
█████████████████████████████
████ ▄▄▄▄▄ █ ▀▀▀▄█ ▄▄▄▄▄ ████
████ █ █ █▀ ▀ ▀█ █ █ ████
████ █▄▄▄█ ██▄ ▀█ █▄▄▄█ ████
████▄▄▄▄▄▄▄█ ▀▄▀ █▄▄▄▄▄▄▄████
████▄▀ ▄▀ ▄ █▄█ ▀ ▀█ █▄ ████
████▄██▄▄▀▄▄▀█▄ ██▀▀█▀▄▄▄████
█████▄▄▄█▄▄█ ▀▀▄█▀▀▀▄█▄▄████
████ ▄▄▄▄▄ █ ▄▄██▄ ▄ ▀▀████
████ █ █ █▀▄▄▀▄▄ ▄▄▄▄ ▄████
████ █▄▄▄█ █▄ █▄▀▄▀██▄█▀████
████▄▄▄▄▄▄▄█▄████▄█▄██▄██████
█████████████████████████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
```
## PIC generation
```rust
use qrcode::render::pic;
use qrcode::QrCode;
fn main() {
let code = QrCode::new(b"01234567").unwrap();
let image = code
.render::<pic::Color>()
.min_dimensions(1, 1)
.build();
println!("{image}");
}
```
Generates [PIC](https://en.wikipedia.org/wiki/PIC_(markup_language))
output that renders as follows:
```pic
maxpswid=29;maxpsht=29;movewid=0;moveht=1;boxwid=1;boxht=1
define p { box wid $3 ht $4 fill 1 thickness 0.1 with .nw at $1,-$2 }
box wid maxpswid ht maxpsht with .nw at 0,0
p(4,4,1,1)
p(5,4,1,1)
p(6,4,1,1)
p(7,4,1,1)
p(8,4,1,1)
p(9,4,1,1)
…
```
See [`test_annex_i_micro_qr_as_pic.pic`](src/test_annex_i_micro_qr_as_pic.pic) for a full example.
## EPS generation
```rust
use qrcode::render::eps;
use qrcode::{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(eps::Color([0.5, 0.0, 0.0]))
.light_color(eps::Color([1.0, 1.0, 0.5]))
.build();
println!("{image}");
}
```
Generates [EPS](https://en.wikipedia.org/wiki/Encapsulated_PostScript)
output that renders as follows:
```postscript
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 204 204
%%Pages: 1
%%EndComments
gsave
1 1 0.5 setrgbcolor
0 0 204 204 rectfill
grestore
0.5 0 0 setrgbcolor
24 180 12 12 rectfill
36 180 12 12 rectfill
48 180 12 12 rectfill
60 180 12 12 rectfill
72 180 12 12 rectfill
84 180 12 12 rectfill
…
```
See [`test_annex_i_micro_qr_as_eps.eps`](src/test_annex_i_micro_qr_as_eps.eps) for a full example.
================================================
FILE: examples/encode_eps.rs
================================================
use qrcode::render::eps;
use qrcode::{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(eps::Color([0.5, 0.0, 0.0]))
.light_color(eps::Color([1.0, 1.0, 0.5]))
.build();
println!("{image}");
}
================================================
FILE: examples/encode_image.rs
================================================
use image::Luma;
use qrcode::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::<Luma<u8>>().build();
// Save the image.
image.save("/tmp/qrcode.png").unwrap();
}
================================================
FILE: examples/encode_pic.roff
================================================
.\" To convert this file to pdf use:
.\" groff -Tpdf -P-p14.5c,14.5c -p encode_pic.roff > encode_pic.pdf
.
.po -1i
.vs 0
.
.\" For most flexibility include the QR-Code using copy
.\" and define your preferred picture scale, e.g.:
.PS
# To make the QR-Code smaller make scale a larger number
# To make the QR-Code bigger make scale a smaller number
scale=2.54*2
# To generate encode_pic.pic run: cargo run --example encode_pic > encode_pic.pic
copy "encode_pic.pic"
.PE
.ex
================================================
FILE: examples/encode_pic.rs
================================================
use qrcode::render::pic;
use qrcode::QrCode;
fn main() {
let code = QrCode::new(b"01234567").unwrap();
let image = code.render::<pic::Color>().min_dimensions(1, 1).build();
println!("{image}");
}
================================================
FILE: examples/encode_string.rs
================================================
use qrcode::QrCode;
fn main() {
let code = QrCode::new(b"Hello").unwrap();
let string = code.render::<char>().quiet_zone(false).module_dimensions(2, 1).build();
println!("{string}");
}
================================================
FILE: examples/encode_svg.rs
================================================
use qrcode::render::svg;
use qrcode::{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}");
}
================================================
FILE: examples/encode_unicode.rs
================================================
use qrcode::render::unicode;
use qrcode::QrCode;
fn main() {
let code = QrCode::new(b"Hello").unwrap();
let string = code.render::<unicode::Dense1x2>().quiet_zone(false).build();
println!("{string}");
}
================================================
FILE: rustfmt.toml
================================================
max_width = 120
use_small_heuristics = "Max"
use_field_init_shorthand = true
================================================
FILE: src/bin/qrencode.rs
================================================
use std::env;
pub fn main() {
let arg = env::args().nth(1).unwrap();
let code = qrcode::QrCode::new(arg.as_bytes()).unwrap();
print!("{}", code.render().dark_color("\x1b[7m \x1b[0m").light_color("\x1b[49m \x1b[0m").build());
}
================================================
FILE: src/bits.rs
================================================
//! The `bits` module encodes binary data into raw bits used in a QR code.
use alloc::vec::Vec;
use core::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<u8>,
bit_offset: usize,
version: Version,
}
impl Bits {
/// Constructs a new, empty bits structure.
pub const 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), "{number} is too big as a {n}-bit number");
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<u8> {
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<usize> {
self.version.fetch(ec_level, &DATA_LENGTHS)
}
/// Version of the QR code.
pub const fn version(&self) -> Version {
self.version
}
}
#[test]
fn test_push_number() {
use alloc::vec;
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 qrcode::bits::Bits;
/// use qrcode::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
/// <http://strokescribe.com/en/ECI.html>. 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};
use alloc::vec;
#[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};
use alloc::vec;
#[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};
use alloc::vec;
#[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};
use alloc::vec;
#[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};
use alloc::vec;
#[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 qrcode::bits::Bits;
/// use qrcode::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 qrcode::bits::Bits;
/// use qrcode::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 = if let Version::Micro(a) = self.version { a.as_usize() * 2 + 1 } else { 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};
use alloc::vec;
#[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<I>(&mut self, data: &[u8], segments_iter: I) -> QrResult<()>
where
I: Iterator<Item = Segment>,
{
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};
use alloc::vec;
use alloc::vec::Vec;
fn encode(data: &[u8], version: Version, ec_level: EcLevel) -> QrResult<Vec<u8>> {
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.
#[allow(clippy::missing_panics_doc)] // the panic caused by the expect() will never actually happen since the `version`s are known good constants.
pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
let segments = Parser::new(data).collect::<Vec<Segment>>();
for version in &[Version::Normal(9), Version::Normal(26), Version::Normal(40)] {
let opt_segments = Optimizer::new(segments.iter().copied(), *version).collect::<Vec<_>>();
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));
})
}
//}}}
//------------------------------------------------------------------------------
================================================
FILE: src/canvas.rs
================================================
//! The `canvas` module puts raw bits into the QR code canvas.
//!
//! ```
//! use qrcode::canvas::{Canvas, MaskPattern};
//! use qrcode::types::{EcLevel, Version};
//!
//! 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 alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use core::{cmp::max, iter};
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<Module> for Color {
fn from(module: Module) -> Self {
match module {
Module::Empty => Self::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 qrcode::canvas::Module;
/// use qrcode::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) {
(Self::Empty, true) => Self::Masked(Color::Dark),
(Self::Empty, false) => Self::Masked(Color::Light),
(Self::Unmasked(c), true) => Self::Masked(!c),
(Self::Unmasked(c), false) | (Self::Masked(c), _) => Self::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<Module>,
}
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) -> alloc::string::String {
let width = self.width;
let mut res = alloc::string::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 {
for y in positions {
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(0b10101101, 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
match a {
_ if non_alignment_test => true,
1 => false,
2..=6 => (width - 7 - x).abs() <= 2 && (width - 7 - y).abs() <= 2,
_ => {
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 {
const 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;
use alloc::vec::Vec;
use alloc::vec;
#[test]
fn test_qr() {
let res = DataModuleIter::new(Version::Normal(1)).collect::<Vec<(i16, i16)>>();
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::<Vec<(i16, i16)>>();
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::<Vec<(i16, i16)>>();
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<I>(&mut self, codewords: &[u8], is_half_codeword_at_end: bool, coords: &mut I)
where
I: Iterator<Item = (i16, i16)>,
{
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 const fn checkerboard(x: i16, y: i16) -> bool {
(x + y) % 2 == 0
}
pub const fn horizontal_lines(_: i16, y: i16) -> bool {
y % 2 == 0
}
pub const fn vertical_lines(x: i16, _: i16) -> bool {
x % 3 == 0
}
pub const fn diagonal_lines(x: i16, y: i16) -> bool {
(x + y) % 3 == 0
}
pub const fn large_checkerboard(x: i16, y: i16) -> bool {
((y / 2) + (x / 3)) % 2 == 0
}
pub const fn fields(x: i16, y: i16) -> bool {
(x * y) % 2 + (x * y) % 3 == 0
}
pub const fn diamonds(x: i16, y: i16) -> bool {
((x * y) % 2 + (x * y) % 3) % 2 == 0
}
pub const 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(iter::once(Module::Empty));
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<dyn Fn(i16) -> 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;
ratio.abs_diff(100).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::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.
#[allow(clippy::missing_panics_doc)] // the expect() only panics when the input iterators (ALL_PATTERNS_QR, ALL_PATTERNS_MICRO_QR) are empty
#[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<bool> {
self.modules.iter().map(|m| m.is_dark()).collect()
}
/// Convert the modules into a vector of colors.
pub fn into_colors(self) -> Vec<Color> {
self.modules.into_iter().map(Color::from).collect()
}
}
//}}}
//------------------------------------------------------------------------------
================================================
FILE: src/cast.rs
================================================
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;
}
macro_rules! impl_as {
($ty:ty) => {
#[cfg(debug_assertions)]
impl As for $ty {
fn as_u16(self) -> u16 {
u16::try_from(self).unwrap()
}
fn as_i16(self) -> i16 {
i16::try_from(self).unwrap()
}
fn as_u32(self) -> u32 {
u32::try_from(self).unwrap()
}
fn as_usize(self) -> usize {
usize::try_from(self).unwrap()
}
fn as_isize(self) -> isize {
isize::try_from(self).unwrap()
}
}
#[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);
================================================
FILE: src/ec.rs
================================================
//! The `ec` module applies the Reed-Solomon error correction codes.
use alloc::vec::Vec;
use core::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\] x<sup>m+n</sup> + a\[1\] x<sup>m+n-1</sup> + … + a\[m\] x<sup>n</sup>)
/// in GF(2<sup>8</sup>), 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<u8> {
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<T: Copy, V: Deref<Target = [T]>>(blocks: &[V]) -> Vec<T> {
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<u8>, Vec<u8>)> {
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::<Vec<Vec<u8>>>();
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<usize> {
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 2<sup>n</sup> 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 − 2<sup>0</sup>)(x − 2<sup>1</sup>)…(x − 2<sup>i-1</sup>). 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
];
//}}}
================================================
FILE: src/lib.rs
================================================
//! QR Code encoder
//!
//! This crate provides a QR code and Micro QR code encoder for binary data.
//!
//! ```
//! # #[cfg(feature = "image")]
//! # {
//! use image::Luma;
//! use qrcode::QrCode;
//!
//! // Encode some data into bits.
//! let code = QrCode::new(b"01234567").unwrap();
//!
//! // Render the bits into an image.
//! let image = code.render::<Luma<u8>>().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(not(feature = "std"), no_std)]
#![cfg_attr(feature = "bench", feature(test))] // Unstable libraries
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![allow(
clippy::must_use_candidate, // This is just annoying.
)]
#![cfg_attr(feature = "bench", doc = include_str!("../README.md"))]
// ^ make sure we can test our README.md.
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use core::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};
/// The encoded QR code symbol.
#[derive(Clone)]
pub struct QrCode {
content: Vec<Color>,
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 qrcode::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<D: AsRef<[u8]>>(data: D) -> QrResult<Self> {
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 qrcode::{EcLevel, QrCode};
///
/// 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<D: AsRef<[u8]>>(data: D, ec_level: EcLevel) -> QrResult<Self> {
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 qrcode::{EcLevel, QrCode, Version};
///
/// 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 qrcode::{EcLevel, QrCode, Version};
///
/// 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<D: AsRef<[u8]>>(data: D, version: Version, ec_level: EcLevel) -> QrResult<Self> {
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 qrcode::bits::Bits;
/// use qrcode::{EcLevel, QrCode, Version};
///
/// 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<Self> {
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 const fn version(&self) -> Version {
self.version
}
/// Gets the error correction level of this QR code.
pub const 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 const 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.
#[allow(clippy::missing_panics_doc)] // the version and ec_level should have been checked when calling `.with_version()`.
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.
///
/// # Panics
///
/// Panics if `x` or `y` is beyond the size of the QR code.
pub fn is_functional(&self, x: usize, y: usize) -> bool {
let x = x.try_into().expect("coordinate is too large for QR code");
let y = y.try_into().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<bool> {
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<bool> {
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<Color> {
self.content.clone()
}
/// Converts the QR code to a vector of colors.
pub fn into_colors(self) -> Vec<Color> {
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(feature = "image")]
/// # {
/// # use qrcode::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<P: Pixel>(&self) -> Renderer<'_, P> {
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::<Luma<u8>>().build();
let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().into_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().into_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::<SvgColor>().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);
}
}
#[cfg(all(test, feature = "pic"))]
mod pic_tests {
use crate::render::pic::Color as PicColor;
use crate::{EcLevel, QrCode, Version};
#[test]
fn test_annex_i_qr_as_pic() {
let code = QrCode::new(b"01234567").unwrap();
let image = code.render::<PicColor>().build();
let expected = include_str!("test_annex_i_qr_as_pic.pic");
assert_eq!(&image, expected);
}
#[test]
fn test_annex_i_micro_qr_as_pic() {
let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
let image = code.render::<PicColor>().min_dimensions(1, 1).build();
let expected = include_str!("test_annex_i_micro_qr_as_pic.pic");
assert_eq!(&image, expected);
}
}
#[cfg(all(test, feature = "eps"))]
mod eps_tests {
use crate::render::eps::Color as EpsColor;
use crate::{EcLevel, QrCode, Version};
#[test]
fn test_annex_i_qr_as_eps() {
let code = QrCode::new(b"01234567").unwrap();
let image = code.render::<EpsColor>().build();
let expected = include_str!("test_annex_i_qr_as_eps.eps");
assert_eq!(&image, expected);
}
#[test]
fn test_annex_i_micro_qr_as_eps() {
let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
let image = code
.render()
.min_dimensions(200, 200)
.dark_color(EpsColor([0.5, 0.0, 0.0]))
.light_color(EpsColor([1.0, 1.0, 0.5]))
.build();
let expected = include_str!("test_annex_i_micro_qr_as_eps.eps");
assert_eq!(&image, expected);
}
}
================================================
FILE: src/optimize.rs
================================================
//! Find the optimal data mode sequence to encode a piece of data.
use crate::types::{Mode, Version};
use core::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<I> {
base: I,
index: usize,
ended: bool,
}
impl<'a, I: Iterator<Item = &'a u8>> Iterator for EcsIter<I> {
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<Iter<'a, u8>>,
state: State,
begin: usize,
pending_single_byte: bool,
}
impl Parser<'_> {
/// Creates a new iterator which parse the data into segments that only
/// contains their exclusive subsets. No optimization is done at this point.
///
/// ```
/// use qrcode::optimize::{Parser, Segment};
/// use qrcode::types::Mode::{Alphanumeric, Byte, Numeric};
///
/// let parse_res = Parser::new(b"ABC123abcd").collect::<Vec<Segment>>();
/// assert_eq!(
/// parse_res,
/// &[
/// 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 Iterator for Parser<'_> {
type Item = Segment;
fn next(&mut self) -> Option<Segment> {
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) = self.ecs_iter.next()?;
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;
use alloc::vec::Vec;
fn parse(data: &[u8]) -> Vec<Segment> {
Parser::new(data).collect()
}
#[test]
fn test_parse_1() {
let segs = parse(b"01049123451234591597033130128%10ABC123");
assert_eq!(
segs,
&[
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,
&[
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,
&[
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,
&[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,
&[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,
&[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,
&[Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 },]
);
}
}
//}}}
//------------------------------------------------------------------------------
//{{{ Optimizer
/// QR code data optimizer.
pub struct Optimizer<I> {
parser: I,
last_segment: Segment,
last_segment_size: usize,
version: Version,
ended: bool,
}
impl<I: Iterator<Item = Segment>> Optimizer<I> {
/// 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 Parser<'_> {
/// Creates a new `Optimizer` based on this parser.
pub fn optimize(self, version: Version) -> Optimizer<Self> {
Optimizer::new(self, version)
}
}
impl<I: Iterator<Item = Segment>> Iterator for Optimizer<I> {
type Item = Segment;
fn next(&mut self) -> Option<Segment> {
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};
use alloc::vec::Vec;
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::<Vec<_>>();
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} < {} ({opt_segs:?})",
total_encoded_len(expected, version)
);
}
#[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.
const fn from_u8(c: u8) -> Self {
match c {
0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d..=0x2f | 0x3a => Self::Symbol,
0x30..=0x39 => Self::Numeric,
0x41..=0x5a => Self::Alpha,
0x81..=0x9f => Self::KanjiHi1,
0xe0..=0xea => Self::KanjiHi2,
0xeb => Self::KanjiHi3,
0x40 | 0x5b..=0x7e | 0x80 | 0xa0..=0xbf => Self::KanjiLo1,
0xc0..=0xdf | 0xec..=0xfc => Self::KanjiLo2,
_ => Self::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
];
//}}}
================================================
FILE: src/render/eps.rs
================================================
//! EPS rendering support.
//!
//! # Example
//!
gitextract_xeat1q94/
├── .github/
│ └── workflows/
│ └── rust.yml
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE.txt
├── LICENSE-MIT.txt
├── README.md
├── examples/
│ ├── encode_eps.rs
│ ├── encode_image.rs
│ ├── encode_pic.roff
│ ├── encode_pic.rs
│ ├── encode_string.rs
│ ├── encode_svg.rs
│ └── encode_unicode.rs
├── rustfmt.toml
└── src/
├── bin/
│ └── qrencode.rs
├── bits.rs
├── canvas.rs
├── cast.rs
├── ec.rs
├── lib.rs
├── optimize.rs
├── render/
│ ├── eps.rs
│ ├── image.rs
│ ├── mod.rs
│ ├── pic.rs
│ ├── string.rs
│ ├── svg.rs
│ └── unicode.rs
├── test_annex_i_micro_qr_as_eps.eps
├── test_annex_i_micro_qr_as_pic.pic
├── test_annex_i_qr_as_eps.eps
├── test_annex_i_qr_as_pic.pic
└── types.rs
SYMBOL INDEX (358 symbols across 21 files)
FILE: examples/encode_eps.rs
function main (line 4) | fn main() {
FILE: examples/encode_image.rs
function main (line 4) | fn main() {
FILE: examples/encode_pic.rs
function main (line 4) | fn main() {
FILE: examples/encode_string.rs
function main (line 3) | fn main() {
FILE: examples/encode_svg.rs
function main (line 4) | fn main() {
FILE: examples/encode_unicode.rs
function main (line 4) | fn main() {
FILE: src/bin/qrencode.rs
function main (line 3) | pub fn main() {
FILE: src/bits.rs
type Bits (line 17) | pub struct Bits {
method new (line 25) | pub const fn new(version: Version) -> Self {
method push_number (line 34) | fn push_number(&mut self, n: usize, number: u16) {
method push_number_checked (line 67) | fn push_number_checked(&mut self, n: usize, number: usize) -> QrResult...
method reserve (line 77) | fn reserve(&mut self, n: usize) {
method into_bytes (line 83) | pub fn into_bytes(self) -> Vec<u8> {
method len (line 88) | pub fn len(&self) -> usize {
method is_empty (line 97) | pub fn is_empty(&self) -> bool {
method max_len (line 109) | pub fn max_len(&self, ec_level: EcLevel) -> QrResult<usize> {
method version (line 114) | pub const fn version(&self) -> Version {
method push_mode_indicator (line 194) | pub fn push_mode_indicator(&mut self, mode: ExtendedMode) -> QrResult<...
method push_eci_designator (line 260) | pub fn push_eci_designator(&mut self, eci_designator: u32) -> QrResult...
method push_header (line 327) | fn push_header(&mut self, mode: Mode, raw_data_len: usize) -> QrResult...
method push_numeric_data (line 342) | pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> {
method push_alphanumeric_data (line 451) | pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> {
method push_byte_data (line 501) | pub fn push_byte_data(&mut self, data: &[u8]) -> QrResult<()> {
method push_kanji_data (line 563) | pub fn push_kanji_data(&mut self, data: &[u8]) -> QrResult<()> {
method push_fnc1_first_position (line 630) | pub fn push_fnc1_first_position(&mut self) -> QrResult<()> {
method push_fnc1_second_position (line 661) | pub fn push_fnc1_second_position(&mut self, application_indicator: u8)...
method push_terminator (line 732) | pub fn push_terminator(&mut self, ec_level: EcLevel) -> QrResult<()> {
method push_segments (line 837) | pub fn push_segments<I>(&mut self, data: &[u8], segments_iter: I) -> Q...
method push_optimal_data (line 858) | pub fn push_optimal_data(&mut self, data: &[u8]) -> QrResult<()> {
function test_push_number (line 120) | fn test_push_number() {
function bench_push_splitted_bytes (line 152) | fn bench_push_splitted_bytes(bencher: &mut test::Bencher) {
type ExtendedMode (line 170) | pub enum ExtendedMode {
function test_9 (line 289) | fn test_9() {
function test_899 (line 296) | fn test_899() {
function test_999999 (line 303) | fn test_999999() {
function test_invalid_designator (line 310) | fn test_invalid_designator() {
function test_unsupported_character_set (line 316) | fn test_unsupported_character_set() {
function test_iso_18004_2006_example_1 (line 360) | fn test_iso_18004_2006_example_1() {
function test_iso_18004_2000_example_2 (line 370) | fn test_iso_18004_2000_example_2() {
function test_iso_18004_2006_example_2 (line 390) | fn test_iso_18004_2006_example_2() {
function test_data_too_long_error (line 409) | fn test_data_too_long_error() {
function alphanumeric_digit (line 425) | fn alphanumeric_digit(character: u8) -> u16 {
function test_iso_18004_2006_example (line 469) | fn test_iso_18004_2006_example() {
function test_micro_qr_unsupported (line 479) | fn test_micro_qr_unsupported() {
function test_data_too_long (line 485) | fn test_data_too_long() {
function test (line 517) | fn test() {
function test_micro_qr_unsupported (line 538) | fn test_micro_qr_unsupported() {
function test_data_too_long (line 544) | fn test_data_too_long() {
function test_iso_18004_example (line 585) | fn test_iso_18004_example() {
function test_micro_qr_unsupported (line 592) | fn test_micro_qr_unsupported() {
function test_data_too_long (line 598) | fn test_data_too_long() {
function test_hello_world (line 771) | fn test_hello_world() {
function test_too_long (line 785) | fn test_too_long() {
function test_no_terminator (line 792) | fn test_no_terminator() {
function test_no_padding (line 800) | fn test_no_padding() {
function test_micro_version_1_half_byte_padding (line 808) | fn test_micro_version_1_half_byte_padding() {
function test_micro_version_1_full_byte_padding (line 816) | fn test_micro_version_1_full_byte_padding() {
function encode (line 871) | fn encode(data: &[u8], version: Version, ec_level: EcLevel) -> QrResult<...
function test_alphanumeric (line 879) | fn test_alphanumeric() {
function test_auto_mode_switch (line 891) | fn test_auto_mode_switch() {
function test_too_long (line 897) | fn test_too_long() {
function encode_auto (line 917) | pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
function find_min_version (line 937) | fn find_min_version(length: usize, ec_level: EcLevel) -> Version {
function test_find_min_version (line 960) | fn test_find_min_version() {
function test_alpha_q (line 971) | fn test_alpha_q() {
function test_alpha_h (line 977) | fn test_alpha_h() {
function test_mixed (line 983) | fn test_mixed() {
function bench_find_min_version (line 991) | fn bench_find_min_version(bencher: &mut test::Bencher) {
FILE: src/canvas.rs
type Module (line 27) | pub enum Module {
method is_dark (line 50) | pub fn is_dark(self) -> bool {
method mask (line 67) | pub fn mask(self, should_invert: bool) -> Self {
method from (line 40) | fn from(module: Module) -> Self {
type Canvas (line 84) | pub struct Canvas {
method new (line 101) | pub fn new(version: Version, ec_level: EcLevel) -> Self {
method to_debug_str (line 108) | fn to_debug_str(&self) -> alloc::string::String {
method coords_to_index (line 126) | fn coords_to_index(&self, x: i16, y: i16) -> usize {
method get (line 134) | pub fn get(&self, x: i16, y: i16) -> Module {
method get_mut (line 140) | pub fn get_mut(&mut self, x: i16, y: i16) -> &mut Module {
method put (line 147) | pub fn put(&mut self, x: i16, y: i16, color: Color) {
method draw_finder_pattern_at (line 223) | fn draw_finder_pattern_at(&mut self, x: i16, y: i16) {
method draw_finder_patterns (line 248) | fn draw_finder_patterns(&mut self) {
method draw_alignment_pattern_at (line 325) | fn draw_alignment_pattern_at(&mut self, x: i16, y: i16) {
method draw_alignment_patterns (line 347) | fn draw_alignment_patterns(&mut self) {
method draw_line (line 551) | fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16, color_even...
method draw_timing_patterns (line 572) | fn draw_timing_patterns(&mut self) {
method draw_number (line 652) | fn draw_number(&mut self, number: u32, bits: u32, on_color: Color, off...
method draw_format_info_patterns_with_number (line 662) | fn draw_format_info_patterns_with_number(&mut self, format_info: u16) {
method draw_reserved_format_info_patterns (line 677) | fn draw_reserved_format_info_patterns(&mut self) {
method draw_version_info_patterns (line 682) | fn draw_version_info_patterns(&mut self) {
method draw_all_functional_patterns (line 973) | pub fn draw_all_functional_patterns(&mut self) {
method draw_codewords (line 1364) | fn draw_codewords<I>(&mut self, codewords: &[u8], is_half_codeword_at_...
method draw_data (line 1387) | pub fn draw_data(&mut self, data: &[u8], ec: &[u8]) {
method apply_mask (line 1539) | pub fn apply_mask(&mut self, pattern: MaskPattern) {
method draw_format_info_patterns (line 1556) | fn draw_format_info_patterns(&mut self, pattern: MaskPattern) {
method compute_adjacent_penalty_score (line 1704) | fn compute_adjacent_penalty_score(&self, is_horizontal: bool) -> u16 {
method compute_block_penalty_score (line 1735) | fn compute_block_penalty_score(&self) -> u16 {
method compute_finder_penalty_score (line 1758) | fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
method compute_balance_penalty_score (line 1795) | fn compute_balance_penalty_score(&self) -> u16 {
method compute_light_side_penalty_score (line 1809) | fn compute_light_side_penalty_score(&self) -> u16 {
method compute_total_penalty_scores (line 1818) | fn compute_total_penalty_scores(&self) -> u16 {
method apply_best_mask (line 1980) | pub fn apply_best_mask(&self) -> Self {
method to_bools (line 1996) | pub fn to_bools(&self) -> Vec<bool> {
method into_colors (line 2001) | pub fn into_colors(self) -> Vec<Color> {
function test_index (line 158) | fn test_index() {
function test_debug_str (line 173) | fn test_debug_str() {
function test_qr (line 267) | fn test_qr() {
function test_micro_qr (line 298) | fn test_micro_qr() {
function test_draw_alignment_patterns_1 (line 369) | fn test_draw_alignment_patterns_1() {
function test_draw_alignment_patterns_3 (line 401) | fn test_draw_alignment_patterns_3() {
function test_draw_alignment_patterns_7 (line 441) | fn test_draw_alignment_patterns_7() {
function test_draw_timing_patterns_qr (line 589) | fn test_draw_timing_patterns_qr() {
function test_draw_timing_patterns_micro_qr (line 620) | fn test_draw_timing_patterns_micro_qr() {
function test_draw_number (line 700) | fn test_draw_number() {
function test_draw_version_info_1 (line 721) | fn test_draw_version_info_1() {
function test_draw_version_info_7 (line 752) | fn test_draw_version_info_7() {
function test_draw_reserved_format_info_patterns_qr (line 808) | fn test_draw_reserved_format_info_patterns_qr() {
function test_draw_reserved_format_info_patterns_micro_qr (line 839) | fn test_draw_reserved_format_info_patterns_micro_qr() {
function is_functional (line 984) | pub fn is_functional(version: Version, width: i16, x: i16, y: i16) -> bo...
function test_all_functional_patterns_qr (line 1027) | fn test_all_functional_patterns_qr() {
function test_all_functional_patterns_micro_qr (line 1062) | fn test_all_functional_patterns_micro_qr() {
function test_is_functional_qr_1 (line 1083) | fn test_is_functional_qr_1() {
function test_is_functional_qr_3 (line 1097) | fn test_is_functional_qr_3() {
function test_is_functional_qr_7 (line 1108) | fn test_is_functional_qr_7() {
function test_is_functional_micro (line 1121) | fn test_is_functional_micro() {
type DataModuleIter (line 1136) | struct DataModuleIter {
method new (line 1144) | const fn new(version: Version) -> Self {
type Item (line 1159) | type Item = (i16, i16);
method next (line 1161) | fn next(&mut self) -> Option<(i16, i16)> {
function test_qr (line 1200) | fn test_qr() {
function test_micro_qr (line 1286) | fn test_micro_qr() {
function test_micro_qr_2 (line 1317) | fn test_micro_qr_2() {
function test_micro_qr_1 (line 1402) | fn test_micro_qr_1() {
function test_qr_2 (line 1424) | fn test_qr_2() {
type MaskPattern (line 1470) | pub enum MaskPattern {
function checkerboard (line 1497) | pub const fn checkerboard(x: i16, y: i16) -> bool {
function horizontal_lines (line 1500) | pub const fn horizontal_lines(_: i16, y: i16) -> bool {
function vertical_lines (line 1503) | pub const fn vertical_lines(x: i16, _: i16) -> bool {
function diagonal_lines (line 1506) | pub const fn diagonal_lines(x: i16, y: i16) -> bool {
function large_checkerboard (line 1509) | pub const fn large_checkerboard(x: i16, y: i16) -> bool {
function fields (line 1512) | pub const fn fields(x: i16, y: i16) -> bool {
function diamonds (line 1515) | pub const fn diamonds(x: i16, y: i16) -> bool {
function meadow (line 1518) | pub const fn meadow(x: i16, y: i16) -> bool {
function get_mask_function (line 1523) | fn get_mask_function(pattern: MaskPattern) -> fn(i16, i16) -> bool {
function test_apply_mask_qr (line 1595) | fn test_apply_mask_qr() {
function test_draw_format_info_patterns_qr (line 1628) | fn test_draw_format_info_patterns_qr() {
function test_draw_format_info_patterns_micro_qr (line 1659) | fn test_draw_format_info_patterns_micro_qr() {
function create_test_canvas (line 1839) | fn create_test_canvas() -> Canvas {
function check_penalty_canvas (line 1851) | fn check_penalty_canvas() {
function test_penalty_score_adjacent (line 1881) | fn test_penalty_score_adjacent() {
function test_penalty_score_block (line 1888) | fn test_penalty_score_block() {
function test_penalty_score_finder (line 1894) | fn test_penalty_score_finder() {
function test_penalty_score_balance (line 1901) | fn test_penalty_score_balance() {
function test_penalty_score_light_sides (line 1907) | fn test_penalty_score_light_sides() {
FILE: src/cast.rs
type Truncate (line 1) | pub trait Truncate {
method truncate_as_u8 (line 2) | fn truncate_as_u8(self) -> u8;
method truncate_as_u8 (line 7) | fn truncate_as_u8(self) -> u8 {
type As (line 13) | pub trait As {
method as_u16 (line 14) | fn as_u16(self) -> u16;
method as_i16 (line 15) | fn as_i16(self) -> i16;
method as_u32 (line 16) | fn as_u32(self) -> u32;
method as_usize (line 17) | fn as_usize(self) -> usize;
method as_isize (line 18) | fn as_isize(self) -> isize;
FILE: src/ec.rs
function create_error_correction_code (line 20) | pub fn create_error_correction_code(data: &[u8], ec_code_size: usize) ->...
function test_poly_mod_1 (line 48) | fn test_poly_mod_1() {
function test_poly_mod_2 (line 54) | fn test_poly_mod_2() {
function test_poly_mod_3 (line 60) | fn test_poly_mod_3() {
function interleave (line 77) | fn interleave<T: Copy, V: Deref<Target = [T]>>(blocks: &[V]) -> Vec<T> {
function test_interleave (line 91) | fn test_interleave() {
function construct_codewords (line 108) | pub fn construct_codewords(rawbits: &[u8], version: Version, ec_level: E...
function test_add_ec_simple (line 140) | fn test_add_ec_simple() {
function test_add_ec_complex (line 148) | fn test_add_ec_complex() {
function max_allowed_errors (line 178) | pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResu...
function test_low_versions (line 202) | fn test_low_versions() {
function test_high_versions (line 237) | fn test_high_versions() {
FILE: src/lib.rs
type QrCode (line 60) | pub struct QrCode {
method new (line 83) | pub fn new<D: AsRef<[u8]>>(data: D) -> QrResult<Self> {
method with_error_correction_level (line 102) | pub fn with_error_correction_level<D: AsRef<[u8]>>(data: D, ec_level: ...
method with_version (line 129) | pub fn with_version<D: AsRef<[u8]>>(data: D, version: Version, ec_leve...
method with_bits (line 165) | pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult<Self> {
method version (line 177) | pub const fn version(&self) -> Version {
method error_correction_level (line 182) | pub const fn error_correction_level(&self) -> EcLevel {
method width (line 189) | pub const fn width(&self) -> usize {
method max_allowed_errors (line 197) | pub fn max_allowed_errors(&self) -> usize {
method is_functional (line 207) | pub fn is_functional(&self, x: usize, y: usize) -> bool {
method to_debug_str (line 215) | pub fn to_debug_str(&self, on_char: char, off_char: char) -> String {
method to_vec (line 222) | pub fn to_vec(&self) -> Vec<bool> {
method into_vec (line 229) | pub fn into_vec(self) -> Vec<bool> {
method to_colors (line 234) | pub fn to_colors(&self) -> Vec<Color> {
method into_colors (line 239) | pub fn into_colors(self) -> Vec<Color> {
method render (line 268) | pub fn render<P: Pixel>(&self) -> Renderer<'_, P> {
type Output (line 275) | type Output = Color;
method index (line 277) | fn index(&self, (x, y): (usize, usize)) -> &Color {
function test_annex_i_qr (line 288) | fn test_annex_i_qr() {
function test_annex_i_micro_qr (line 319) | fn test_annex_i_micro_qr() {
function test_annex_i_qr_as_image (line 347) | fn test_annex_i_qr_as_image() {
function test_annex_i_micro_qr_as_image (line 356) | fn test_annex_i_micro_qr_as_image() {
function test_annex_i_qr_as_svg (line 376) | fn test_annex_i_qr_as_svg() {
function test_annex_i_micro_qr_as_svg (line 384) | fn test_annex_i_micro_qr_as_svg() {
function test_annex_i_qr_as_pic (line 403) | fn test_annex_i_qr_as_pic() {
function test_annex_i_micro_qr_as_pic (line 411) | fn test_annex_i_micro_qr_as_pic() {
function test_annex_i_qr_as_eps (line 425) | fn test_annex_i_qr_as_eps() {
function test_annex_i_micro_qr_as_eps (line 433) | fn test_annex_i_micro_qr_as_eps() {
FILE: src/optimize.rs
type Segment (line 13) | pub struct Segment {
method encoded_len (line 27) | pub fn encoded_len(&self, version: Version) -> usize {
type EcsIter (line 52) | struct EcsIter<I> {
type Item (line 59) | type Item = (usize, ExclCharSet);
method next (line 61) | fn next(&mut self) -> Option<(usize, ExclCharSet)> {
type Parser (line 81) | pub struct Parser<'a> {
function new (line 106) | pub fn new(data: &[u8]) -> Parser<'_> {
type Item (line 117) | type Item = Segment;
method next (line 119) | fn next(&mut self) -> Option<Segment> {
function parse (line 162) | fn parse(data: &[u8]) -> Vec<Segment> {
function test_parse_1 (line 167) | fn test_parse_1() {
function test_parse_shift_jis_example_1 (line 182) | fn test_parse_shift_jis_example_1() {
function test_parse_utf_8 (line 196) | fn test_parse_utf_8() {
function test_not_kanji_1 (line 213) | fn test_not_kanji_1() {
function test_not_kanji_2 (line 222) | fn test_not_kanji_2() {
function test_not_kanji_3 (line 233) | fn test_not_kanji_3() {
function test_not_kanji_4 (line 242) | fn test_not_kanji_4() {
type Optimizer (line 256) | pub struct Optimizer<I> {
function new (line 270) | pub fn new(mut segments: I, version: Version) -> Self {
function optimize (line 292) | pub fn optimize(self, version: Version) -> Optimizer<Self> {
type Item (line 298) | type Item = Segment;
method next (line 300) | fn next(&mut self) -> Option<Segment> {
function total_encoded_len (line 337) | pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize {
function test_optimization_result (line 347) | fn test_optimization_result(given: &[Segment], expected: &[Segment], ver...
function test_example_1 (line 362) | fn test_example_1() {
function test_example_2 (line 375) | fn test_example_2() {
function test_example_3 (line 393) | fn test_example_3() {
function test_example_4 (line 407) | fn test_example_4() {
function test_annex_j_guideline_1a (line 416) | fn test_annex_j_guideline_1a() {
function test_annex_j_guideline_1b (line 431) | fn test_annex_j_guideline_1b() {
function test_annex_j_guideline_1c (line 443) | fn test_annex_j_guideline_1c() {
function bench_optimize (line 457) | fn bench_optimize(bencher: &mut test::Bencher) {
type ExclCharSet (line 489) | enum ExclCharSet {
method from_u8 (line 532) | const fn from_u8(c: u8) -> Self {
type State (line 549) | enum State {
type Action (line 576) | enum Action {
FILE: src/render/eps.rs
type Color (line 26) | pub struct Color(pub [f64; 3]);
type Canvas (line 29) | type Canvas = Canvas;
type Image (line 30) | type Image = String;
method default_color (line 32) | fn default_color(color: ModuleColor) -> Self {
type Canvas (line 38) | pub struct Canvas {
type Pixel (line 44) | type Pixel = Color;
type Image (line 45) | type Image = String;
method new (line 47) | fn new(width: u32, height: u32, dark_pixel: Color, light_pixel: Color) -...
method draw_dark_pixel (line 74) | fn draw_dark_pixel(&mut self, x: u32, y: u32) {
method draw_dark_rect (line 78) | fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u3...
method into_image (line 83) | fn into_image(mut self) -> String {
FILE: src/render/image.rs
type Pixel (line 39) | type Pixel = P;
type Image (line 40) | type Image = ImageBuffer<P, Vec<P::Subpixel>>;
method new (line 42) | fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self {
method draw_dark_pixel (line 46) | fn draw_dark_pixel(&mut self, x: u32, y: u32) {
method into_image (line 50) | fn into_image(self) -> ImageBuffer<P, Vec<P::Subpixel>> {
function test_render_luma8_unsized (line 62) | fn test_render_luma8_unsized() {
function test_render_rgba_unsized (line 95) | fn test_render_rgba_unsized() {
function test_render_resized_min (line 112) | fn test_render_resized_min() {
function test_render_resized_max (line 141) | fn test_render_resized_max() {
FILE: src/render/mod.rs
type Pixel (line 18) | pub trait Pixel: Copy + Sized {
method default_unit_size (line 27) | fn default_unit_size() -> (u32, u32) {
method default_color (line 32) | fn default_color(color: Color) -> Self;
type Canvas (line 36) | pub trait Canvas: Sized {
method new (line 44) | fn new(width: u32, height: u32, dark_pixel: Self::Pixel, light_pixel: ...
method draw_dark_pixel (line 47) | fn draw_dark_pixel(&mut self, x: u32, y: u32);
method draw_dark_rect (line 51) | fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: ...
method into_image (line 60) | fn into_image(self) -> Self::Image;
type Renderer (line 69) | pub struct Renderer<'a, P: Pixel> {
function new (line 86) | pub fn new(content: &'a [Color], modules_count: usize, quiet_zone: u32) ...
function dark_color (line 100) | pub fn dark_color(&mut self, color: P) -> &mut Self {
function light_color (line 106) | pub fn light_color(&mut self, color: P) -> &mut Self {
function quiet_zone (line 112) | pub fn quiet_zone(&mut self, has_quiet_zone: bool) -> &mut Self {
function module_size (line 119) | pub fn module_size(&mut self, width: u32) -> &mut Self {
function module_dimensions (line 124) | pub fn module_dimensions(&mut self, width: u32, height: u32) -> &mut Self {
function min_width (line 138) | pub fn min_width(&mut self, width: u32) -> &mut Self {
function min_dimensions (line 150) | pub fn min_dimensions(&mut self, width: u32, height: u32) -> &mut Self {
function max_dimensions (line 169) | pub fn max_dimensions(&mut self, width: u32, height: u32) -> &mut Self {
function to_image (line 179) | pub fn to_image(&self) -> P::Image {
function build (line 184) | pub fn build(&self) -> P::Image {
FILE: src/render/pic.rs
type Color (line 24) | pub struct Color;
type Canvas (line 27) | type Canvas = Canvas;
type Image (line 28) | type Image = String;
method default_color (line 30) | fn default_color(_color: ModuleColor) -> Self {
type Canvas (line 36) | pub struct Canvas {
type Pixel (line 41) | type Pixel = Color;
type Image (line 42) | type Image = String;
method new (line 44) | fn new(width: u32, height: u32, _dark_pixel: Color, _light_pixel: Color)...
method draw_dark_pixel (line 58) | fn draw_dark_pixel(&mut self, x: u32, y: u32) {
method draw_dark_rect (line 62) | fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u3...
method into_image (line 66) | fn into_image(self) -> String {
FILE: src/render/string.rs
type Element (line 12) | pub trait Element: Copy {
method default_color (line 14) | fn default_color(color: Color) -> Self;
method strlen (line 17) | fn strlen(self) -> usize;
method append_to_string (line 20) | fn append_to_string(self, string: &mut String);
method default_color (line 24) | fn default_color(color: Color) -> Self {
method strlen (line 28) | fn strlen(self) -> usize {
method append_to_string (line 32) | fn append_to_string(self, string: &mut String) {
method default_color (line 38) | fn default_color(color: Color) -> Self {
method strlen (line 42) | fn strlen(self) -> usize {
method append_to_string (line 46) | fn append_to_string(self, string: &mut String) {
type Canvas (line 52) | pub struct Canvas<P: Element> {
type Canvas (line 61) | type Canvas = Canvas<Self>;
type Image (line 62) | type Image = String;
method default_unit_size (line 64) | fn default_unit_size() -> (u32, u32) {
method default_color (line 68) | fn default_color(color: Color) -> Self {
type Pixel (line 74) | type Pixel = P;
type Image (line 75) | type Image = String;
method new (line 77) | fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self {
method draw_dark_pixel (line 91) | fn draw_dark_pixel(&mut self, x: u32, y: u32) {
method into_image (line 98) | fn into_image(self) -> String {
function test_render_to_string (line 111) | fn test_render_to_string() {
FILE: src/render/svg.rs
type Color (line 25) | pub struct Color<'a>(pub &'a str);
type Canvas (line 28) | type Canvas = Canvas<'a>;
type Image (line 29) | type Image = String;
method default_color (line 31) | fn default_color(color: ModuleColor) -> Self {
type Canvas (line 37) | pub struct Canvas<'a> {
type Pixel (line 43) | type Pixel = Color<'a>;
type Image (line 44) | type Image = String;
method new (line 46) | fn new(width: u32, height: u32, dark_pixel: Color<'a>, light_pixel: Colo...
method draw_dark_pixel (line 66) | fn draw_dark_pixel(&mut self, x: u32, y: u32) {
method draw_dark_rect (line 70) | fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u3...
method into_image (line 74) | fn into_image(mut self) -> String {
FILE: src/render/unicode.rs
constant CODEPAGE (line 9) | const CODEPAGE: [&str; 4] = [" ", "\u{2584}", "\u{2580}", "\u{2588}"];
type Dense1x2 (line 13) | pub enum Dense1x2 {
method value (line 32) | const fn value(self) -> u8 {
method parse_2_bits (line 38) | fn parse_2_bits(sym: u8) -> &'static str {
type Image (line 21) | type Image = String;
type Canvas (line 22) | type Canvas = Canvas1x2;
method default_color (line 23) | fn default_color(color: Color) -> Self {
method default_unit_size (line 26) | fn default_unit_size() -> (u32, u32) {
type Canvas1x2 (line 44) | pub struct Canvas1x2 {
type Pixel (line 51) | type Pixel = Dense1x2;
type Image (line 52) | type Image = String;
method new (line 54) | fn new(width: u32, height: u32, dark_pixel: Dense1x2, light_pixel: Dense...
method draw_dark_pixel (line 59) | fn draw_dark_pixel(&mut self, x: u32, y: u32) {
method into_image (line 63) | fn into_image(self) -> String {
function test_render_to_utf8_string (line 91) | fn test_render_to_utf8_string() {
function integration_render_utf8_1x2 (line 104) | fn integration_render_utf8_1x2() {
function integration_render_utf8_1x2_inverted (line 126) | fn integration_render_utf8_1x2_inverted() {
FILE: src/types.rs
type QrError (line 15) | pub enum QrError {
method fmt (line 35) | fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
type QrResult (line 51) | pub type QrResult<T> = Result<T, QrError>;
type Color (line 59) | pub enum Color {
method select (line 77) | pub fn select<T>(self, dark: T, light: T) -> T {
type Output (line 86) | type Output = Self;
method not (line 87) | fn not(self) -> Self {
type EcLevel (line 102) | pub enum EcLevel {
type Version (line 127) | pub enum Version {
method width (line 138) | pub const fn width(self) -> i16 {
method fetch (line 157) | pub fn fetch<T>(self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T>
method mode_bits_count (line 177) | pub fn mode_bits_count(self) -> usize {
method is_micro (line 186) | pub const fn is_micro(self) -> bool {
type Mode (line 197) | pub enum Mode {
method length_bits_count (line 223) | pub fn length_bits_count(self, version: Version) -> usize {
method data_bits_count (line 263) | pub const fn data_bits_count(self, raw_data_len: usize) -> usize {
method max (line 284) | pub fn max(self, other: Self) -> Self {
method partial_cmp (line 296) | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
function test_mode_order (line 311) | fn test_mode_order() {
function test_max (line 319) | fn test_max() {
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (261K chars).
[
{
"path": ".github/workflows/rust.yml",
"chars": 2054,
"preview": "name: Rust\n\non:\n push:\n branches:\n - master\n pull_request:\n branches:\n - master\n\njobs:\n check:\n na"
},
{
"path": ".gitignore",
"chars": 57,
"preview": "/target\n*.swp\n*.swo\n.DS_Store\n*.o\n__pycache__\nCargo.lock\n"
},
{
"path": "Cargo.toml",
"chars": 1075,
"preview": "[package]\nname = \"qrcode\"\ndescription = \"QR code encoder in Rust\"\nlicense = \"MIT OR Apache-2.0\"\nversion = \"0.14.1\"\nediti"
},
{
"path": "LICENSE-APACHE.txt",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "LICENSE-MIT.txt",
"chars": 1052,
"preview": "Copyright (c) 2016 kennytm\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis softwar"
},
{
"path": "README.md",
"chars": 5344,
"preview": "qrcode-rust\n===========\n\n[](https://gith"
},
{
"path": "examples/encode_eps.rs",
"chars": 385,
"preview": "use qrcode::render::eps;\nuse qrcode::{EcLevel, QrCode, Version};\n\nfn main() {\n let code = QrCode::with_version(b\"0123"
},
{
"path": "examples/encode_image.rs",
"chars": 295,
"preview": "use image::Luma;\nuse qrcode::QrCode;\n\nfn main() {\n // Encode some data into bits.\n let code = QrCode::new(b\"012345"
},
{
"path": "examples/encode_pic.roff",
"chars": 473,
"preview": ".\\\" To convert this file to pdf use:\n.\\\" groff -Tpdf -P-p14.5c,14.5c -p encode_pic.roff > encode_pic.pdf\n.\n.po -1i\n.vs 0"
},
{
"path": "examples/encode_pic.rs",
"chars": 209,
"preview": "use qrcode::render::pic;\nuse qrcode::QrCode;\n\nfn main() {\n let code = QrCode::new(b\"01234567\").unwrap();\n let imag"
},
{
"path": "examples/encode_string.rs",
"chars": 198,
"preview": "use qrcode::QrCode;\n\nfn main() {\n let code = QrCode::new(b\"Hello\").unwrap();\n let string = code.render::<char>().q"
},
{
"path": "examples/encode_svg.rs",
"chars": 373,
"preview": "use qrcode::render::svg;\nuse qrcode::{EcLevel, QrCode, Version};\n\nfn main() {\n let code = QrCode::with_version(b\"0123"
},
{
"path": "examples/encode_unicode.rs",
"chars": 216,
"preview": "use qrcode::render::unicode;\nuse qrcode::QrCode;\n\nfn main() {\n let code = QrCode::new(b\"Hello\").unwrap();\n let str"
},
{
"path": "rustfmt.toml",
"chars": 77,
"preview": "max_width = 120\nuse_small_heuristics = \"Max\"\nuse_field_init_shorthand = true\n"
},
{
"path": "src/bin/qrencode.rs",
"chars": 243,
"preview": "use std::env;\n\npub fn main() {\n let arg = env::args().nth(1).unwrap();\n let code = qrcode::QrCode::new(arg.as_byte"
},
{
"path": "src/bits.rs",
"chars": 33357,
"preview": "//! The `bits` module encodes binary data into raw bits used in a QR code.\n\nuse alloc::vec::Vec;\nuse core::cmp::min;\n\n#["
},
{
"path": "src/canvas.rs",
"chars": 71261,
"preview": "//! The `canvas` module puts raw bits into the QR code canvas.\n//!\n//! ```\n//! use qrcode::canvas::{Canvas, MaskPattern}"
},
{
"path": "src/cast.rs",
"chars": 1571,
"preview": "pub trait Truncate {\n fn truncate_as_u8(self) -> u8;\n}\n\nimpl Truncate for u16 {\n #[allow(clippy::cast_possible_tru"
},
{
"path": "src/ec.rs",
"chars": 28677,
"preview": "//! The `ec` module applies the Reed-Solomon error correction codes.\n\nuse alloc::vec::Vec;\nuse core::ops::Deref;\n\nuse cr"
},
{
"path": "src/lib.rs",
"chars": 14737,
"preview": "//! QR Code encoder\n//!\n//! This crate provides a QR code and Micro QR code encoder for binary data.\n//!\n//! ```\n//! # #"
},
{
"path": "src/optimize.rs",
"chars": 24218,
"preview": "//! Find the optimal data mode sequence to encode a piece of data.\nuse crate::types::{Mode, Version};\nuse core::slice::I"
},
{
"path": "src/render/eps.rs",
"chars": 2265,
"preview": "//! EPS rendering support.\n//!\n//! # Example\n//!\n//! ```\n//! use qrcode::QrCode;\n//! use qrcode::render::eps;\n//!\n//! le"
},
{
"path": "src/render/image.rs",
"chars": 5041,
"preview": "//! Raster image rendering support powered by the [`image`] crate.\n\n#![cfg(feature = \"image\")]\n\nuse crate::render::{Canv"
},
{
"path": "src/render/mod.rs",
"chars": 7669,
"preview": "//! Render a QR code into image.\n\nuse crate::cast::As;\nuse crate::types::Color;\nuse core::cmp::max;\n\npub mod eps;\npub mo"
},
{
"path": "src/render/pic.rs",
"chars": 1647,
"preview": "//! PIC rendering support.\n//!\n//! # Example\n//!\n//! ```\n//! use qrcode::QrCode;\n//! use qrcode::render::pic;\n//!\n//! le"
},
{
"path": "src/render/string.rs",
"chars": 3321,
"preview": "//! String rendering support.\n\nuse crate::cast::As;\nuse crate::render::{Canvas as RenderCanvas, Pixel};\nuse crate::types"
},
{
"path": "src/render/svg.rs",
"chars": 2118,
"preview": "//! SVG rendering support.\n//!\n//! # Example\n//!\n//! ```\n//! use qrcode::QrCode;\n//! use qrcode::render::svg;\n//!\n//! le"
},
{
"path": "src/render/unicode.rs",
"chars": 4342,
"preview": "//! UTF-8 rendering, with 2 pixels per symbol.\n\nuse crate::render::{Canvas as RenderCanvas, Color, Pixel};\n\nuse alloc::s"
},
{
"path": "src/test_annex_i_micro_qr_as_eps.eps",
"chars": 2208,
"preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 204 204\n%%Pages: 1\n%%EndComments\ngsave\n1 1 0.5 setrgbcolor\n0 0 204 204 rectfi"
},
{
"path": "src/test_annex_i_micro_qr_as_pic.pic",
"chars": 1271,
"preview": "maxpswid=17;maxpsht=17;movewid=0;moveht=1;boxwid=1;boxht=1\ndefine p { box wid $3 ht $4 fill 1 thickness 0.1 with .nw at "
},
{
"path": "src/test_annex_i_qr_as_eps.eps",
"chars": 4511,
"preview": "%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 232 232\n%%Pages: 1\n%%EndComments\ngsave\n1 1 1 setrgbcolor\n0 0 232 232 rectfill"
},
{
"path": "src/test_annex_i_qr_as_pic.pic",
"chars": 3216,
"preview": "maxpswid=232;maxpsht=232;movewid=0;moveht=1;boxwid=1;boxht=1\ndefine p { box wid $3 ht $4 fill 1 thickness 0.1 with .nw a"
},
{
"path": "src/types.rs",
"chars": 10207,
"preview": "//! The `types` module contains types associated with the functional elements of\n//! a QR code.\n\nuse crate::cast::As;\nus"
}
]
About this extraction
This page contains the full source code of the kennytm/qrcode-rust GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (239.3 KB), approximately 78.7k tokens, and a symbol index with 358 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.