Change all bool type to explicit Color type.
This commit is contained in:
parent
fab0705ef8
commit
21114481f4
|
@ -13,14 +13,14 @@ Cargo.toml
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
qrcode = "0.2.0"
|
qrcode = "0.4"
|
||||||
```
|
```
|
||||||
|
|
||||||
The default settings will depend on the `image` crate. If you don't need image generation capability, disable the `default-features`:
|
The default settings will depend on the `image` crate. If you don't need image generation capability, disable the `default-features`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
qrcode = { version = "0.2.0", default-features = false }
|
qrcode = { version = "0.4", default-features = false }
|
||||||
```
|
```
|
||||||
|
|
||||||
Example
|
Example
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub fn main() {
|
||||||
|
|
||||||
for y in 0 .. code.width() {
|
for y in 0 .. code.width() {
|
||||||
for x in 0 .. code.width() {
|
for x in 0 .. code.width() {
|
||||||
let block = if code[(x, y)] { '█' } else { SPACE };
|
let block = code[(x, y)].select('█', SPACE);
|
||||||
print!("{}{}", block, block);
|
print!("{}{}", block, block);
|
||||||
}
|
}
|
||||||
print!("\n{}{}{}{}{}", SPACE, SPACE, SPACE, SPACE, SPACE);
|
print!("\n{}{}{}{}{}", SPACE, SPACE, SPACE, SPACE, SPACE);
|
||||||
|
|
210
src/canvas.rs
210
src/canvas.rs
|
@ -9,13 +9,12 @@
|
||||||
//! c.apply_mask(MaskPattern::Checkerboard);
|
//! c.apply_mask(MaskPattern::Checkerboard);
|
||||||
//! let bools = c.to_bools();
|
//! let bools = c.to_bools();
|
||||||
|
|
||||||
use std::iter::repeat;
|
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
use types::{Version, EcLevel};
|
use types::{Version, EcLevel, Color};
|
||||||
|
|
||||||
// TODO remove this after `p ... q` becomes stable. See rust-lang/rust#28237.
|
// TODO remove this after `p ... q` becomes stable. See rust-lang/rust#28237.
|
||||||
fn range_inclusive<N: PrimInt>(from: N, to: N) -> Range<N> {
|
fn range_inclusive<N: PrimInt>(from: N, to: N) -> Range<N> {
|
||||||
|
@ -31,49 +30,47 @@ pub enum Module {
|
||||||
/// The module is empty.
|
/// The module is empty.
|
||||||
Empty,
|
Empty,
|
||||||
|
|
||||||
/// The module is light (white), and cannot be masked. This mainly refers to
|
/// The module is of functional patterns which cannot be masked, or pixels
|
||||||
/// modules of functional patterns.
|
/// which have been masked.
|
||||||
Light,
|
Masked(Color),
|
||||||
|
|
||||||
/// The module is dark (black), and cannot be masked. This mainly refers to
|
/// The module is of data and error correction bits before masking.
|
||||||
/// modules of functional patterns.
|
Unmasked(Color),
|
||||||
Dark,
|
}
|
||||||
|
|
||||||
/// The module is light (white), but not yet masked. This mainly refers to
|
impl From<Module> for Color {
|
||||||
/// modules of data and error correction bits before masking.
|
fn from(module: Module) -> Color {
|
||||||
LightUnmasked,
|
match module {
|
||||||
|
Module::Empty => Color::Light,
|
||||||
/// The module is dark (black), but not yet masked. This mainly refers to
|
Module::Masked(c) | Module::Unmasked(c) => c,
|
||||||
/// modules of data and error correction bits before masking.
|
}
|
||||||
DarkUnmasked,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Checks whether a module is dark.
|
/// Checks whether a module is dark.
|
||||||
pub fn is_dark(&self) -> bool {
|
pub fn is_dark(self) -> bool {
|
||||||
match *self {
|
Color::from(self) == Color::Dark
|
||||||
Module::Dark | Module::DarkUnmasked => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a mask to the unmasked modules.
|
/// Apply a mask to the unmasked modules.
|
||||||
///
|
///
|
||||||
/// use qrcode::canvas::Module;
|
/// use qrcode::canvas::Module;
|
||||||
|
/// use qrcode::types::Color;
|
||||||
///
|
///
|
||||||
/// assert_eq!(Module::LightUnmasked.mask(true), Module::Dark);
|
/// assert_eq!(Module::Unmasked(Color::Light).mask(true), Module::Masked(Color::Dark));
|
||||||
/// assert_eq!(Module::DarkUnmasked.mask(true), Module::Light);
|
/// assert_eq!(Module::Unmasked(Color::Dark).mask(true), Module::Masked(Color::Light));
|
||||||
/// assert_eq!(Module::LightUnmasked.mask(false), Module::Light);
|
/// assert_eq!(Module::Unmasked(Color::Light).mask(false), Module::Masked(Color::Light));
|
||||||
/// assert_eq!(Module::Dark.mask(true), Module::Dark);
|
/// assert_eq!(Module::Masked(Color::Dark).mask(true), Module::Masked(Color::Dark));
|
||||||
/// assert_eq!(Module::Dark.mask(false), Module::Dark);
|
/// assert_eq!(Module::Masked(Color::Dark).mask(false), Module::Masked(Color::Dark));
|
||||||
///
|
///
|
||||||
pub fn mask(&self, should_invert: bool) -> Module {
|
pub fn mask(self, should_invert: bool) -> Module {
|
||||||
match (*self, should_invert) {
|
match (self, should_invert) {
|
||||||
(Module::Empty, true) | (Module::LightUnmasked, true) => Module::Dark,
|
(Module::Empty, true) => Module::Masked(Color::Dark),
|
||||||
(Module::Empty, false) | (Module::LightUnmasked, false) => Module::Light,
|
(Module::Empty, false) => Module::Masked(Color::Light),
|
||||||
(Module::DarkUnmasked, true) => Module::Light,
|
(Module::Unmasked(c), true) => Module::Masked(!c),
|
||||||
(Module::DarkUnmasked, false) => Module::Dark,
|
(Module::Unmasked(c), false) |
|
||||||
(a, _) => a,
|
(Module::Masked(c), _) => Module::Masked(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +105,7 @@ impl Canvas {
|
||||||
width: width,
|
width: width,
|
||||||
version: version,
|
version: version,
|
||||||
ec_level: ec_level,
|
ec_level: ec_level,
|
||||||
modules: repeat(Module::Empty).take((width*width) as usize).collect()
|
modules: vec![Module::Empty; (width*width) as usize],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,10 +119,10 @@ impl Canvas {
|
||||||
for x in 0 .. width {
|
for x in 0 .. width {
|
||||||
res.push(match self.get(x, y) {
|
res.push(match self.get(x, y) {
|
||||||
Module::Empty => '?',
|
Module::Empty => '?',
|
||||||
Module::Light => '.',
|
Module::Masked(Color::Light) => '.',
|
||||||
Module::Dark => '#',
|
Module::Masked(Color::Dark) => '#',
|
||||||
Module::LightUnmasked => '-',
|
Module::Unmasked(Color::Light) => '-',
|
||||||
Module::DarkUnmasked => '*',
|
Module::Unmasked(Color::Dark) => '*',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,18 +148,17 @@ impl Canvas {
|
||||||
&mut self.modules[index]
|
&mut self.modules[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the color of a module at the given coordinates. For convenience,
|
/// Sets the color of a functional module at the given coordinates. For
|
||||||
/// negative coordinates will wrap around.
|
/// convenience, negative coordinates will wrap around.
|
||||||
pub fn put(&mut self, x: i16, y: i16, module: Module) {
|
pub fn put(&mut self, x: i16, y: i16, color: Color) {
|
||||||
*self.get_mut(x, y) = module;
|
*self.get_mut(x, y) = Module::Masked(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod basic_canvas_tests {
|
mod basic_canvas_tests {
|
||||||
use canvas::{Canvas, Module};
|
use canvas::{Canvas, Module};
|
||||||
use types::{Version, EcLevel};
|
use types::{Version, EcLevel, Color};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_index() {
|
fn test_index() {
|
||||||
|
@ -172,11 +168,11 @@ mod basic_canvas_tests {
|
||||||
assert_eq!(c.get(-1, -7), Module::Empty);
|
assert_eq!(c.get(-1, -7), Module::Empty);
|
||||||
assert_eq!(c.get(21-1, 21-7), Module::Empty);
|
assert_eq!(c.get(21-1, 21-7), Module::Empty);
|
||||||
|
|
||||||
c.put(0, 0, Module::Dark);
|
c.put(0, 0, Color::Dark);
|
||||||
c.put(-1, -7, Module::Light);
|
c.put(-1, -7, Color::Light);
|
||||||
assert_eq!(c.get(0, 0), Module::Dark);
|
assert_eq!(c.get(0, 0), Module::Masked(Color::Dark));
|
||||||
assert_eq!(c.get(21-1, -7), Module::Light);
|
assert_eq!(c.get(21-1, -7), Module::Masked(Color::Light));
|
||||||
assert_eq!(c.get(-1, 21-7), Module::Light);
|
assert_eq!(c.get(-1, 21-7), Module::Masked(Color::Light));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -185,14 +181,14 @@ mod basic_canvas_tests {
|
||||||
|
|
||||||
for i in 3i16 .. 20 {
|
for i in 3i16 .. 20 {
|
||||||
for j in 3i16 .. 20 {
|
for j in 3i16 .. 20 {
|
||||||
c.put(i, j, match ((i * 3) ^ j) % 5 {
|
*c.get_mut(i, j) = match ((i * 3) ^ j) % 5 {
|
||||||
0 => Module::Empty,
|
0 => Module::Empty,
|
||||||
1 => Module::Light,
|
1 => Module::Masked(Color::Light),
|
||||||
2 => Module::Dark,
|
2 => Module::Masked(Color::Dark),
|
||||||
3 => Module::LightUnmasked,
|
3 => Module::Unmasked(Color::Light),
|
||||||
4 => Module::DarkUnmasked,
|
4 => Module::Unmasked(Color::Dark),
|
||||||
_ => panic!(),
|
_ => unreachable!(),
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,10 +229,10 @@ impl Canvas {
|
||||||
for j in range_inclusive(dy_top, dy_bottom) {
|
for j in range_inclusive(dy_top, dy_bottom) {
|
||||||
for i in range_inclusive(dx_left, dx_right) {
|
for i in range_inclusive(dx_left, dx_right) {
|
||||||
self.put(x+i, y+j, match (i, j) {
|
self.put(x+i, y+j, match (i, j) {
|
||||||
(4, _) | (_, 4) | (-4, _) | (_, -4) => Module::Light,
|
(4, _) | (_, 4) | (-4, _) | (_, -4) => Color::Light,
|
||||||
(3, _) | (_, 3) | (-3, _) | (_, -3) => Module::Dark,
|
(3, _) | (_, 3) | (-3, _) | (_, -3) => Color::Dark,
|
||||||
(2, _) | (_, 2) | (-2, _) | (_, -2) => Module::Light,
|
(2, _) | (_, 2) | (-2, _) | (_, -2) => Color::Light,
|
||||||
_ => Module::Dark,
|
_ => Color::Dark,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,8 +321,8 @@ impl Canvas {
|
||||||
for j in range_inclusive(-2, 2) {
|
for j in range_inclusive(-2, 2) {
|
||||||
for i in range_inclusive(-2, 2) {
|
for i in range_inclusive(-2, 2) {
|
||||||
self.put(x+i, y+j, match (i, j) {
|
self.put(x+i, y+j, match (i, j) {
|
||||||
(2, _) | (_, 2) | (-2, _) | (_, -2) | (0, 0) => Module::Dark,
|
(2, _) | (_, 2) | (-2, _) | (_, -2) | (0, 0) => Color::Dark,
|
||||||
_ => Module::Light,
|
_ => Color::Light,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,7 +530,7 @@ impl Canvas {
|
||||||
/// drawn using this method.
|
/// drawn using this method.
|
||||||
///
|
///
|
||||||
fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16,
|
fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16,
|
||||||
color_even: Module, color_odd: Module) {
|
color_even: Color, color_odd: Color) {
|
||||||
debug_assert!(x1 == x2 || y1 == y2);
|
debug_assert!(x1 == x2 || y1 == y2);
|
||||||
|
|
||||||
if y1 == y2 { // Horizontal line.
|
if y1 == y2 { // Horizontal line.
|
||||||
|
@ -559,8 +555,8 @@ impl Canvas {
|
||||||
Version::Micro(_) => (0, 8, width-1),
|
Version::Micro(_) => (0, 8, width-1),
|
||||||
Version::Normal(_) => (6, 8, width-9),
|
Version::Normal(_) => (6, 8, width-9),
|
||||||
};
|
};
|
||||||
self.draw_line(x1, y, x2, y, Module::Dark, Module::Light);
|
self.draw_line(x1, y, x2, y, Color::Dark, Color::Light);
|
||||||
self.draw_line(y, x1, y, x2, Module::Dark, Module::Light);
|
self.draw_line(y, x1, y, x2, Color::Dark, Color::Light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,7 +624,7 @@ impl Canvas {
|
||||||
/// iterator. It will start from the most significant bits first, so
|
/// iterator. It will start from the most significant bits first, so
|
||||||
/// *trailing* zeros will be ignored.
|
/// *trailing* zeros will be ignored.
|
||||||
fn draw_number<N: PrimInt>(&mut self, number: N,
|
fn draw_number<N: PrimInt>(&mut self, number: N,
|
||||||
on_color: Module, off_color: Module,
|
on_color: Color, off_color: Color,
|
||||||
coords: &[(i16, i16)]) {
|
coords: &[(i16, i16)]) {
|
||||||
let zero: N = N::zero();
|
let zero: N = N::zero();
|
||||||
let mut mask: N = !(!zero >> 1);
|
let mut mask: N = !(!zero >> 1);
|
||||||
|
@ -643,15 +639,15 @@ impl Canvas {
|
||||||
fn draw_format_info_patterns_with_number(&mut self, format_info: u16) {
|
fn draw_format_info_patterns_with_number(&mut self, format_info: u16) {
|
||||||
match self.version {
|
match self.version {
|
||||||
Version::Micro(_) => {
|
Version::Micro(_) => {
|
||||||
self.draw_number(format_info, Module::Dark, Module::Light,
|
self.draw_number(format_info, Color::Dark, Color::Light,
|
||||||
&FORMAT_INFO_COORDS_MICRO_QR);
|
&FORMAT_INFO_COORDS_MICRO_QR);
|
||||||
}
|
}
|
||||||
Version::Normal(_) => {
|
Version::Normal(_) => {
|
||||||
self.draw_number(format_info, Module::Dark, Module::Light,
|
self.draw_number(format_info, Color::Dark, Color::Light,
|
||||||
&FORMAT_INFO_COORDS_QR_MAIN);
|
&FORMAT_INFO_COORDS_QR_MAIN);
|
||||||
self.draw_number(format_info, Module::Dark, Module::Light,
|
self.draw_number(format_info, Color::Dark, Color::Light,
|
||||||
&FORMAT_INFO_COORDS_QR_SIDE);
|
&FORMAT_INFO_COORDS_QR_SIDE);
|
||||||
self.put(8, -8, Module::Dark); // Dark module.
|
self.put(8, -8, Color::Dark); // Dark module.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -667,9 +663,9 @@ impl Canvas {
|
||||||
Version::Micro(_) | Version::Normal(1...6) => { return; }
|
Version::Micro(_) | Version::Normal(1...6) => { return; }
|
||||||
Version::Normal(a) => {
|
Version::Normal(a) => {
|
||||||
let version_info = VERSION_INFOS[(a - 7) as usize] << 14;
|
let version_info = VERSION_INFOS[(a - 7) as usize] << 14;
|
||||||
self.draw_number(version_info, Module::Dark, Module::Light,
|
self.draw_number(version_info, Color::Dark, Color::Light,
|
||||||
&VERSION_INFO_COORDS_BL);
|
&VERSION_INFO_COORDS_BL);
|
||||||
self.draw_number(version_info, Module::Dark, Module::Light,
|
self.draw_number(version_info, Color::Dark, Color::Light,
|
||||||
&VERSION_INFO_COORDS_TR);
|
&VERSION_INFO_COORDS_TR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -678,13 +674,13 @@ impl Canvas {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod draw_version_info_tests {
|
mod draw_version_info_tests {
|
||||||
use canvas::{Canvas, Module};
|
use canvas::Canvas;
|
||||||
use types::{Version, EcLevel};
|
use types::{Version, EcLevel, Color};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_draw_number() {
|
fn test_draw_number() {
|
||||||
let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
|
let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
|
||||||
c.draw_number(0b10101101u8, Module::Dark, Module::Light,
|
c.draw_number(0b10101101u8, Color::Dark, Color::Light,
|
||||||
&[(0,0), (0,-1), (-2,-2), (-2,0)]);
|
&[(0,0), (0,-1), (-2,-2), (-2,0)]);
|
||||||
assert_eq!(&*c.to_debug_str(), "\n\
|
assert_eq!(&*c.to_debug_str(), "\n\
|
||||||
#????????.?\n\
|
#????????.?\n\
|
||||||
|
@ -1284,14 +1280,14 @@ impl Canvas {
|
||||||
'outside:
|
'outside:
|
||||||
for j in range_inclusive(bits_end, 7).rev() {
|
for j in range_inclusive(bits_end, 7).rev() {
|
||||||
let color = if (*b & (1 << j)) != 0 {
|
let color = if (*b & (1 << j)) != 0 {
|
||||||
Module::DarkUnmasked
|
Color::Dark
|
||||||
} else {
|
} else {
|
||||||
Module::LightUnmasked
|
Color::Light
|
||||||
};
|
};
|
||||||
while let Some((x, y)) = coords.next() {
|
while let Some((x, y)) = coords.next() {
|
||||||
let r = self.get_mut(x, y);
|
let r = self.get_mut(x, y);
|
||||||
if *r == Module::Empty {
|
if *r == Module::Empty {
|
||||||
*r = color;
|
*r = Module::Unmasked(color);
|
||||||
continue 'outside;
|
continue 'outside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1648,35 +1644,28 @@ impl Canvas {
|
||||||
/// Every pattern that looks like `#.###.#....` in any orientation will add
|
/// Every pattern that looks like `#.###.#....` in any orientation will add
|
||||||
/// 40 points.
|
/// 40 points.
|
||||||
fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
|
fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
|
||||||
static PATTERN: [Module; 7] = [
|
static PATTERN: [Color; 7] = [
|
||||||
Module::Dark, Module::Light, Module::Dark, Module::Dark,
|
Color::Dark, Color::Light, Color::Dark, Color::Dark,
|
||||||
Module::Dark, Module::Light, Module::Dark,
|
Color::Dark, Color::Light, Color::Dark,
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO remove this after `equals()` is stable.
|
|
||||||
fn equals<T, U>(left: T, right: U) -> bool
|
|
||||||
where T: Iterator, U: Iterator, T::Item: PartialEq<U::Item>
|
|
||||||
{
|
|
||||||
left.zip(right).all(|(p, q)| p == q)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut total_score = 0;
|
let mut total_score = 0;
|
||||||
|
|
||||||
for i in 0 .. self.width {
|
for i in 0 .. self.width {
|
||||||
for j in 0 .. self.width-6 {
|
for j in 0 .. self.width-6 {
|
||||||
// TODO a ref to a closure should be enough?
|
// TODO a ref to a closure should be enough?
|
||||||
let get: Box<Fn(i16) -> Module> = if is_horizontal {
|
let get: Box<Fn(i16) -> Color> = if is_horizontal {
|
||||||
Box::new(|k: i16| self.get(k, i))
|
Box::new(|k| self.get(k, i).into())
|
||||||
} else {
|
} else {
|
||||||
Box::new(|k: i16| self.get(i, k))
|
Box::new(|k| self.get(i, k).into())
|
||||||
};
|
};
|
||||||
|
|
||||||
if !equals((j .. j+7).map(|k| get(k)), PATTERN.iter().map(|m| *m)) {
|
if (j .. j+7).map(&*get).ne(PATTERN.iter().cloned()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let check = |k| { 0 <= k && k < self.width && get(k).is_dark() };
|
let check = |k| 0 <= k && k < self.width && get(k) != Color::Light;
|
||||||
if !(j-4 .. j).any(|k| check(k)) || !(j+7 .. j+11).any(|k| check(k)) {
|
if !(j-4 .. j).any(&check) || !(j+7 .. j+11).any(&check) {
|
||||||
total_score += 40;
|
total_score += 40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1721,7 +1710,6 @@ impl Canvas {
|
||||||
/// Compute the total penalty scores. A QR code having higher points is less
|
/// Compute the total penalty scores. A QR code having higher points is less
|
||||||
/// desirable.
|
/// desirable.
|
||||||
fn compute_total_penalty_scores(&self) -> u16 {
|
fn compute_total_penalty_scores(&self) -> u16 {
|
||||||
|
|
||||||
match self.version {
|
match self.version {
|
||||||
Version::Normal(_) => {
|
Version::Normal(_) => {
|
||||||
let s1a = self.compute_adjacent_penalty_score(true);
|
let s1a = self.compute_adjacent_penalty_score(true);
|
||||||
|
@ -1739,8 +1727,8 @@ impl Canvas {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod penalty_tests {
|
mod penalty_tests {
|
||||||
use canvas::{Canvas, MaskPattern, Module};
|
use canvas::{Canvas, MaskPattern};
|
||||||
use types::{Version, EcLevel};
|
use types::{Version, EcLevel, Color};
|
||||||
|
|
||||||
fn create_test_canvas() -> Canvas {
|
fn create_test_canvas() -> Canvas {
|
||||||
let mut c = Canvas::new(Version::Normal(1), EcLevel::Q);
|
let mut c = Canvas::new(Version::Normal(1), EcLevel::Q);
|
||||||
|
@ -1806,19 +1794,19 @@ mod penalty_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_penalty_score_light_sides() {
|
fn test_penalty_score_light_sides() {
|
||||||
static HORIZONTAL_SIDE: [Module; 17] = [
|
static HORIZONTAL_SIDE: [Color; 17] = [
|
||||||
Module::Dark, Module::Light, Module::Light, Module::Dark,
|
Color::Dark, Color::Light, Color::Light, Color::Dark,
|
||||||
Module::Dark, Module::Dark, Module::Light, Module::Light,
|
Color::Dark, Color::Dark, Color::Light, Color::Light,
|
||||||
Module::Dark, Module::Light, Module::Dark, Module::Light,
|
Color::Dark, Color::Light, Color::Dark, Color::Light,
|
||||||
Module::Light, Module::Dark, Module::Light, Module::Light,
|
Color::Light, Color::Dark, Color::Light, Color::Light,
|
||||||
Module::Light,
|
Color::Light,
|
||||||
];
|
];
|
||||||
static VERTICAL_SIDE: [Module; 17] = [
|
static VERTICAL_SIDE: [Color; 17] = [
|
||||||
Module::Dark, Module::Dark, Module::Dark, Module::Light,
|
Color::Dark, Color::Dark, Color::Dark, Color::Light,
|
||||||
Module::Light, Module::Dark, Module::Dark, Module::Light,
|
Color::Light, Color::Dark, Color::Dark, Color::Light,
|
||||||
Module::Dark, Module::Light, Module::Dark, Module::Light,
|
Color::Dark, Color::Light, Color::Dark, Color::Light,
|
||||||
Module::Dark, Module::Light, Module::Light, Module::Dark,
|
Color::Dark, Color::Light, Color::Light, Color::Dark,
|
||||||
Module::Light,
|
Color::Light,
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut c = Canvas::new(Version::Micro(4), EcLevel::Q);
|
let mut c = Canvas::new(Version::Micro(4), EcLevel::Q);
|
||||||
|
@ -1876,9 +1864,15 @@ impl Canvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the modules into a vector of booleans.
|
/// 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> {
|
pub fn to_bools(&self) -> Vec<bool> {
|
||||||
self.modules.iter().map(|m| m.is_dark()).collect()
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
|
26
src/lib.rs
26
src/lib.rs
|
@ -40,14 +40,14 @@ pub mod ec;
|
||||||
pub mod canvas;
|
pub mod canvas;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
|
||||||
pub use types::{QrResult, EcLevel, Version};
|
pub use types::{QrResult, Color, EcLevel, Version};
|
||||||
|
|
||||||
#[cfg(feature="image")] use render::{BlankAndWhitePixel, Renderer};
|
#[cfg(feature="image")] use render::{BlankAndWhitePixel, Renderer};
|
||||||
|
|
||||||
/// The encoded QR code symbol.
|
/// The encoded QR code symbol.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct QrCode {
|
pub struct QrCode {
|
||||||
content: Vec<bool>,
|
content: Vec<Color>,
|
||||||
version: Version,
|
version: Version,
|
||||||
ec_level: EcLevel,
|
ec_level: EcLevel,
|
||||||
width: usize,
|
width: usize,
|
||||||
|
@ -132,7 +132,7 @@ impl QrCode {
|
||||||
canvas.draw_data(&*encoded_data, &*ec_data);
|
canvas.draw_data(&*encoded_data, &*ec_data);
|
||||||
let canvas = canvas.apply_best_mask();
|
let canvas = canvas.apply_best_mask();
|
||||||
Ok(QrCode {
|
Ok(QrCode {
|
||||||
content: canvas.to_bools(),
|
content: canvas.into_colors(),
|
||||||
version: version,
|
version: version,
|
||||||
ec_level: ec_level,
|
ec_level: ec_level,
|
||||||
width: version.width() as usize,
|
width: version.width() as usize,
|
||||||
|
@ -178,7 +178,7 @@ impl QrCode {
|
||||||
for _ in 0 .. width {
|
for _ in 0 .. width {
|
||||||
res.push('\n');
|
res.push('\n');
|
||||||
for _ in 0 .. width {
|
for _ in 0 .. width {
|
||||||
res.push(if self.content[k] { on_char } else { off_char });
|
res.push(self.content[k].select(on_char, off_char));
|
||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,13 +187,25 @@ impl QrCode {
|
||||||
|
|
||||||
/// Converts the QR code to a vector of booleans. Each entry represents the
|
/// 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.
|
/// 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> {
|
pub fn to_vec(&self) -> Vec<bool> {
|
||||||
self.content.clone()
|
self.content.iter().map(|c| *c != Color::Light).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the QR code to a vector of booleans. Each entry represents the
|
/// 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.
|
/// 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> {
|
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
|
self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,9 +243,9 @@ impl QrCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<(usize, usize)> for QrCode {
|
impl Index<(usize, usize)> for QrCode {
|
||||||
type Output = bool;
|
type Output = Color;
|
||||||
|
|
||||||
fn index(&self, (x, y): (usize, usize)) -> &bool {
|
fn index(&self, (x, y): (usize, usize)) -> &Color {
|
||||||
let index = y * self.width + x;
|
let index = y * self.width + x;
|
||||||
&self.content[index]
|
&self.content[index]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![cfg(feature="image")]
|
#![cfg(feature="image")]
|
||||||
|
|
||||||
use image::{Pixel, Rgb, Rgba, Luma, LumaA, Primitive, ImageBuffer};
|
use image::{Pixel, Rgb, Rgba, Luma, LumaA, Primitive, ImageBuffer};
|
||||||
|
use types::Color;
|
||||||
|
|
||||||
/// A pixel which can support black and white colors.
|
/// A pixel which can support black and white colors.
|
||||||
pub trait BlankAndWhitePixel: Pixel {
|
pub trait BlankAndWhitePixel: Pixel {
|
||||||
|
@ -53,7 +54,7 @@ impl<S: Primitive + 'static> BlankAndWhitePixel for LumaA<S> {
|
||||||
/// A QR code renderer. This is a builder type which converts a bool-vector into
|
/// A QR code renderer. This is a builder type which converts a bool-vector into
|
||||||
/// an image.
|
/// an image.
|
||||||
pub struct Renderer<'a, P: BlankAndWhitePixel> {
|
pub struct Renderer<'a, P: BlankAndWhitePixel> {
|
||||||
content: &'a [bool],
|
content: &'a [Color],
|
||||||
modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`.
|
modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`.
|
||||||
quiet_zone: u32,
|
quiet_zone: u32,
|
||||||
module_size: u32,
|
module_size: u32,
|
||||||
|
@ -65,7 +66,7 @@ pub struct Renderer<'a, P: BlankAndWhitePixel> {
|
||||||
|
|
||||||
impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
||||||
/// Creates a new renderer.
|
/// Creates a new renderer.
|
||||||
pub fn new(content: &'a [bool], modules_count: usize, quiet_zone: u32) -> Renderer<'a, P> {
|
pub fn new(content: &'a [Color], modules_count: usize, quiet_zone: u32) -> Renderer<'a, P> {
|
||||||
assert!(modules_count * modules_count == content.len());
|
assert!(modules_count * modules_count == content.len());
|
||||||
Renderer {
|
Renderer {
|
||||||
content: content,
|
content: content,
|
||||||
|
@ -131,7 +132,11 @@ impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
||||||
for y in 0 .. width {
|
for y in 0 .. width {
|
||||||
for x in 0 .. width {
|
for x in 0 .. width {
|
||||||
let color = if qz <= x && x < w + qz && qz <= y && y < w + qz {
|
let color = if qz <= x && x < w + qz && qz <= y && y < w + qz {
|
||||||
let c = if self.content[i] { self.dark_color } else { self.light_color };
|
let c = if self.content[i] != Color::Light {
|
||||||
|
self.dark_color
|
||||||
|
} else {
|
||||||
|
self.light_color
|
||||||
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
c
|
c
|
||||||
} else {
|
} else {
|
||||||
|
@ -153,13 +158,14 @@ impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
||||||
mod render_tests {
|
mod render_tests {
|
||||||
use render::Renderer;
|
use render::Renderer;
|
||||||
use image::{Luma, Rgba};
|
use image::{Luma, Rgba};
|
||||||
|
use types::Color;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_luma8_unsized() {
|
fn test_render_luma8_unsized() {
|
||||||
let image = Renderer::<Luma<u8>>::new(&[
|
let image = Renderer::<Luma<u8>>::new(&[
|
||||||
false, true, true,
|
Color::Light, Color::Dark, Color::Dark,
|
||||||
true, false, false,
|
Color::Dark, Color::Light, Color::Light,
|
||||||
false, true, false,
|
Color::Light, Color::Dark, Color::Light,
|
||||||
], 3, 1).module_size(1).to_image();
|
], 3, 1).module_size(1).to_image();
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
|
@ -175,8 +181,8 @@ mod render_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_rgba_unsized() {
|
fn test_render_rgba_unsized() {
|
||||||
let image = Renderer::<Rgba<u8>>::new(&[
|
let image = Renderer::<Rgba<u8>>::new(&[
|
||||||
false, true,
|
Color::Light, Color::Dark,
|
||||||
true, true,
|
Color::Dark, Color::Dark,
|
||||||
], 2, 1).module_size(1).to_image();
|
], 2, 1).module_size(1).to_image();
|
||||||
|
|
||||||
let expected: &[u8] = &[
|
let expected: &[u8] = &[
|
||||||
|
@ -192,8 +198,8 @@ mod render_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_resized() {
|
fn test_render_resized() {
|
||||||
let image = Renderer::<Luma<u8>>::new(&[
|
let image = Renderer::<Luma<u8>>::new(&[
|
||||||
true, false,
|
Color::Dark, Color::Light,
|
||||||
false, true,
|
Color::Light, Color::Dark,
|
||||||
], 2, 1).min_width(10).to_image();
|
], 2, 1).min_width(10).to_image();
|
||||||
|
|
||||||
let expected: &[u8] = &[
|
let expected: &[u8] = &[
|
||||||
|
|
43
src/types.rs
43
src/types.rs
|
@ -1,6 +1,7 @@
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::cmp::{PartialOrd, Ordering};
|
use std::cmp::{PartialOrd, Ordering};
|
||||||
use std::fmt::{Display, Formatter, Error};
|
use std::fmt::{Display, Formatter, Error};
|
||||||
|
use std::ops::Not;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ QrResult
|
//{{{ QrResult
|
||||||
|
@ -42,6 +43,48 @@ impl Display for QrError {
|
||||||
/// `QrResult` is a convenient alias for a QR code generation result.
|
/// `QrResult` is a convenient alias for a QR code generation result.
|
||||||
pub type QrResult<T> = Result<T, QrError>;
|
pub type QrResult<T> = Result<T, QrError>;
|
||||||
|
|
||||||
|
//}}}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//{{{ Color
|
||||||
|
|
||||||
|
/// The color of a module.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub enum Color {
|
||||||
|
/// The module is light colored.
|
||||||
|
Light,
|
||||||
|
/// The module is dark colored.
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
/// Selects a value according to color of the module. Equivalent to
|
||||||
|
/// `if self != Color::Light { dark } else { light }`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use qrcode::types::Color;
|
||||||
|
/// assert_eq!(Color::Light.select(1, 0), 0);
|
||||||
|
/// assert_eq!(Color::Dark.select("black", "white"), "black");
|
||||||
|
/// ```
|
||||||
|
pub fn select<T>(self, dark: T, light: T) -> T {
|
||||||
|
match self {
|
||||||
|
Color::Light => light,
|
||||||
|
Color::Dark => dark,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for Color {
|
||||||
|
type Output = Color;
|
||||||
|
fn not(self) -> Color {
|
||||||
|
match self {
|
||||||
|
Color::Light => Color::Dark,
|
||||||
|
Color::Dark => Color::Light,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ Error correction level
|
//{{{ Error correction level
|
||||||
|
|
Loading…
Reference in a new issue