Change all bool type to explicit Color type.
This commit is contained in:
parent
fab0705ef8
commit
21114481f4
|
@ -13,14 +13,14 @@ Cargo.toml
|
|||
|
||||
```toml
|
||||
[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`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
qrcode = { version = "0.2.0", default-features = false }
|
||||
qrcode = { version = "0.4", default-features = false }
|
||||
```
|
||||
|
||||
Example
|
||||
|
|
|
@ -12,7 +12,7 @@ pub fn main() {
|
|||
|
||||
for y 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!("\n{}{}{}{}{}", SPACE, SPACE, SPACE, SPACE, SPACE);
|
||||
|
|
210
src/canvas.rs
210
src/canvas.rs
|
@ -9,13 +9,12 @@
|
|||
//! c.apply_mask(MaskPattern::Checkerboard);
|
||||
//! let bools = c.to_bools();
|
||||
|
||||
use std::iter::repeat;
|
||||
use std::cmp::max;
|
||||
use std::ops::Range;
|
||||
|
||||
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.
|
||||
fn range_inclusive<N: PrimInt>(from: N, to: N) -> Range<N> {
|
||||
|
@ -31,49 +30,47 @@ pub enum Module {
|
|||
/// The module is empty.
|
||||
Empty,
|
||||
|
||||
/// The module is light (white), and cannot be masked. This mainly refers to
|
||||
/// modules of functional patterns.
|
||||
Light,
|
||||
/// The module is of functional patterns which cannot be masked, or pixels
|
||||
/// which have been masked.
|
||||
Masked(Color),
|
||||
|
||||
/// The module is dark (black), and cannot be masked. This mainly refers to
|
||||
/// modules of functional patterns.
|
||||
Dark,
|
||||
/// The module is of data and error correction bits before masking.
|
||||
Unmasked(Color),
|
||||
}
|
||||
|
||||
/// The module is light (white), but not yet masked. This mainly refers to
|
||||
/// modules of data and error correction bits before masking.
|
||||
LightUnmasked,
|
||||
|
||||
/// The module is dark (black), but not yet masked. This mainly refers to
|
||||
/// modules of data and error correction bits before masking.
|
||||
DarkUnmasked,
|
||||
impl From<Module> for Color {
|
||||
fn from(module: Module) -> Color {
|
||||
match module {
|
||||
Module::Empty => Color::Light,
|
||||
Module::Masked(c) | Module::Unmasked(c) => c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// Checks whether a module is dark.
|
||||
pub fn is_dark(&self) -> bool {
|
||||
match *self {
|
||||
Module::Dark | Module::DarkUnmasked => true,
|
||||
_ => false,
|
||||
}
|
||||
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::LightUnmasked.mask(true), Module::Dark);
|
||||
/// assert_eq!(Module::DarkUnmasked.mask(true), Module::Light);
|
||||
/// assert_eq!(Module::LightUnmasked.mask(false), Module::Light);
|
||||
/// assert_eq!(Module::Dark.mask(true), Module::Dark);
|
||||
/// assert_eq!(Module::Dark.mask(false), Module::Dark);
|
||||
/// 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));
|
||||
///
|
||||
pub fn mask(&self, should_invert: bool) -> Module {
|
||||
match (*self, should_invert) {
|
||||
(Module::Empty, true) | (Module::LightUnmasked, true) => Module::Dark,
|
||||
(Module::Empty, false) | (Module::LightUnmasked, false) => Module::Light,
|
||||
(Module::DarkUnmasked, true) => Module::Light,
|
||||
(Module::DarkUnmasked, false) => Module::Dark,
|
||||
(a, _) => a,
|
||||
pub fn mask(self, should_invert: bool) -> Module {
|
||||
match (self, should_invert) {
|
||||
(Module::Empty, true) => Module::Masked(Color::Dark),
|
||||
(Module::Empty, false) => Module::Masked(Color::Light),
|
||||
(Module::Unmasked(c), true) => Module::Masked(!c),
|
||||
(Module::Unmasked(c), false) |
|
||||
(Module::Masked(c), _) => Module::Masked(c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +105,7 @@ impl Canvas {
|
|||
width: width,
|
||||
version: version,
|
||||
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 {
|
||||
res.push(match self.get(x, y) {
|
||||
Module::Empty => '?',
|
||||
Module::Light => '.',
|
||||
Module::Dark => '#',
|
||||
Module::LightUnmasked => '-',
|
||||
Module::DarkUnmasked => '*',
|
||||
Module::Masked(Color::Light) => '.',
|
||||
Module::Masked(Color::Dark) => '#',
|
||||
Module::Unmasked(Color::Light) => '-',
|
||||
Module::Unmasked(Color::Dark) => '*',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -151,18 +148,17 @@ impl Canvas {
|
|||
&mut self.modules[index]
|
||||
}
|
||||
|
||||
/// Sets the color of a module at the given coordinates. For convenience,
|
||||
/// negative coordinates will wrap around.
|
||||
pub fn put(&mut self, x: i16, y: i16, module: Module) {
|
||||
*self.get_mut(x, y) = module;
|
||||
/// 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 canvas::{Canvas, Module};
|
||||
use types::{Version, EcLevel};
|
||||
use types::{Version, EcLevel, Color};
|
||||
|
||||
#[test]
|
||||
fn test_index() {
|
||||
|
@ -172,11 +168,11 @@ mod basic_canvas_tests {
|
|||
assert_eq!(c.get(-1, -7), Module::Empty);
|
||||
assert_eq!(c.get(21-1, 21-7), Module::Empty);
|
||||
|
||||
c.put(0, 0, Module::Dark);
|
||||
c.put(-1, -7, Module::Light);
|
||||
assert_eq!(c.get(0, 0), Module::Dark);
|
||||
assert_eq!(c.get(21-1, -7), Module::Light);
|
||||
assert_eq!(c.get(-1, 21-7), Module::Light);
|
||||
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]
|
||||
|
@ -185,14 +181,14 @@ mod basic_canvas_tests {
|
|||
|
||||
for i 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,
|
||||
1 => Module::Light,
|
||||
2 => Module::Dark,
|
||||
3 => Module::LightUnmasked,
|
||||
4 => Module::DarkUnmasked,
|
||||
_ => panic!(),
|
||||
});
|
||||
1 => Module::Masked(Color::Light),
|
||||
2 => Module::Masked(Color::Dark),
|
||||
3 => Module::Unmasked(Color::Light),
|
||||
4 => Module::Unmasked(Color::Dark),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,10 +229,10 @@ impl Canvas {
|
|||
for j in range_inclusive(dy_top, dy_bottom) {
|
||||
for i in range_inclusive(dx_left, dx_right) {
|
||||
self.put(x+i, y+j, match (i, j) {
|
||||
(4, _) | (_, 4) | (-4, _) | (_, -4) => Module::Light,
|
||||
(3, _) | (_, 3) | (-3, _) | (_, -3) => Module::Dark,
|
||||
(2, _) | (_, 2) | (-2, _) | (_, -2) => Module::Light,
|
||||
_ => Module::Dark,
|
||||
(4, _) | (_, 4) | (-4, _) | (_, -4) => Color::Light,
|
||||
(3, _) | (_, 3) | (-3, _) | (_, -3) => Color::Dark,
|
||||
(2, _) | (_, 2) | (-2, _) | (_, -2) => Color::Light,
|
||||
_ => Color::Dark,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -325,8 +321,8 @@ impl Canvas {
|
|||
for j in range_inclusive(-2, 2) {
|
||||
for i in range_inclusive(-2, 2) {
|
||||
self.put(x+i, y+j, match (i, j) {
|
||||
(2, _) | (_, 2) | (-2, _) | (_, -2) | (0, 0) => Module::Dark,
|
||||
_ => Module::Light,
|
||||
(2, _) | (_, 2) | (-2, _) | (_, -2) | (0, 0) => Color::Dark,
|
||||
_ => Color::Light,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -534,7 +530,7 @@ impl Canvas {
|
|||
/// drawn using this method.
|
||||
///
|
||||
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);
|
||||
|
||||
if y1 == y2 { // Horizontal line.
|
||||
|
@ -559,8 +555,8 @@ impl Canvas {
|
|||
Version::Micro(_) => (0, 8, width-1),
|
||||
Version::Normal(_) => (6, 8, width-9),
|
||||
};
|
||||
self.draw_line(x1, y, x2, y, Module::Dark, Module::Light);
|
||||
self.draw_line(y, x1, y, x2, Module::Dark, Module::Light);
|
||||
self.draw_line(x1, y, x2, y, Color::Dark, Color::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
|
||||
/// *trailing* zeros will be ignored.
|
||||
fn draw_number<N: PrimInt>(&mut self, number: N,
|
||||
on_color: Module, off_color: Module,
|
||||
on_color: Color, off_color: Color,
|
||||
coords: &[(i16, i16)]) {
|
||||
let zero: N = N::zero();
|
||||
let mut mask: N = !(!zero >> 1);
|
||||
|
@ -643,15 +639,15 @@ impl Canvas {
|
|||
fn draw_format_info_patterns_with_number(&mut self, format_info: u16) {
|
||||
match self.version {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
self.draw_number(format_info, Module::Dark, Module::Light,
|
||||
self.draw_number(format_info, Color::Dark, Color::Light,
|
||||
&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::Normal(a) => {
|
||||
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);
|
||||
self.draw_number(version_info, Module::Dark, Module::Light,
|
||||
self.draw_number(version_info, Color::Dark, Color::Light,
|
||||
&VERSION_INFO_COORDS_TR);
|
||||
}
|
||||
}
|
||||
|
@ -678,13 +674,13 @@ impl Canvas {
|
|||
|
||||
#[cfg(test)]
|
||||
mod draw_version_info_tests {
|
||||
use canvas::{Canvas, Module};
|
||||
use types::{Version, EcLevel};
|
||||
use canvas::Canvas;
|
||||
use types::{Version, EcLevel, Color};
|
||||
|
||||
#[test]
|
||||
fn test_draw_number() {
|
||||
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)]);
|
||||
assert_eq!(&*c.to_debug_str(), "\n\
|
||||
#????????.?\n\
|
||||
|
@ -1284,14 +1280,14 @@ impl Canvas {
|
|||
'outside:
|
||||
for j in range_inclusive(bits_end, 7).rev() {
|
||||
let color = if (*b & (1 << j)) != 0 {
|
||||
Module::DarkUnmasked
|
||||
Color::Dark
|
||||
} else {
|
||||
Module::LightUnmasked
|
||||
Color::Light
|
||||
};
|
||||
while let Some((x, y)) = coords.next() {
|
||||
let r = self.get_mut(x, y);
|
||||
if *r == Module::Empty {
|
||||
*r = color;
|
||||
*r = Module::Unmasked(color);
|
||||
continue 'outside;
|
||||
}
|
||||
}
|
||||
|
@ -1648,35 +1644,28 @@ impl Canvas {
|
|||
/// Every pattern that looks like `#.###.#....` in any orientation will add
|
||||
/// 40 points.
|
||||
fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
|
||||
static PATTERN: [Module; 7] = [
|
||||
Module::Dark, Module::Light, Module::Dark, Module::Dark,
|
||||
Module::Dark, Module::Light, Module::Dark,
|
||||
static PATTERN: [Color; 7] = [
|
||||
Color::Dark, Color::Light, Color::Dark, Color::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;
|
||||
|
||||
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<Fn(i16) -> Module> = if is_horizontal {
|
||||
Box::new(|k: i16| self.get(k, i))
|
||||
let get: Box<Fn(i16) -> Color> = if is_horizontal {
|
||||
Box::new(|k| self.get(k, i).into())
|
||||
} 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;
|
||||
}
|
||||
|
||||
let check = |k| { 0 <= k && k < self.width && get(k).is_dark() };
|
||||
if !(j-4 .. j).any(|k| check(k)) || !(j+7 .. j+11).any(|k| check(k)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1721,7 +1710,6 @@ impl Canvas {
|
|||
/// 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 s1a = self.compute_adjacent_penalty_score(true);
|
||||
|
@ -1739,8 +1727,8 @@ impl Canvas {
|
|||
|
||||
#[cfg(test)]
|
||||
mod penalty_tests {
|
||||
use canvas::{Canvas, MaskPattern, Module};
|
||||
use types::{Version, EcLevel};
|
||||
use canvas::{Canvas, MaskPattern};
|
||||
use types::{Version, EcLevel, Color};
|
||||
|
||||
fn create_test_canvas() -> Canvas {
|
||||
let mut c = Canvas::new(Version::Normal(1), EcLevel::Q);
|
||||
|
@ -1806,19 +1794,19 @@ mod penalty_tests {
|
|||
|
||||
#[test]
|
||||
fn test_penalty_score_light_sides() {
|
||||
static HORIZONTAL_SIDE: [Module; 17] = [
|
||||
Module::Dark, Module::Light, Module::Light, Module::Dark,
|
||||
Module::Dark, Module::Dark, Module::Light, Module::Light,
|
||||
Module::Dark, Module::Light, Module::Dark, Module::Light,
|
||||
Module::Light, Module::Dark, Module::Light, Module::Light,
|
||||
Module::Light,
|
||||
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: [Module; 17] = [
|
||||
Module::Dark, Module::Dark, Module::Dark, Module::Light,
|
||||
Module::Light, Module::Dark, Module::Dark, Module::Light,
|
||||
Module::Dark, Module::Light, Module::Dark, Module::Light,
|
||||
Module::Dark, Module::Light, Module::Light, Module::Dark,
|
||||
Module::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);
|
||||
|
@ -1876,9 +1864,15 @@ impl Canvas {
|
|||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
|
||||
//}}}
|
||||
|
|
26
src/lib.rs
26
src/lib.rs
|
@ -40,14 +40,14 @@ pub mod ec;
|
|||
pub mod canvas;
|
||||
pub mod render;
|
||||
|
||||
pub use types::{QrResult, EcLevel, Version};
|
||||
pub use types::{QrResult, Color, EcLevel, Version};
|
||||
|
||||
#[cfg(feature="image")] use render::{BlankAndWhitePixel, Renderer};
|
||||
|
||||
/// The encoded QR code symbol.
|
||||
#[derive(Clone)]
|
||||
pub struct QrCode {
|
||||
content: Vec<bool>,
|
||||
content: Vec<Color>,
|
||||
version: Version,
|
||||
ec_level: EcLevel,
|
||||
width: usize,
|
||||
|
@ -132,7 +132,7 @@ impl QrCode {
|
|||
canvas.draw_data(&*encoded_data, &*ec_data);
|
||||
let canvas = canvas.apply_best_mask();
|
||||
Ok(QrCode {
|
||||
content: canvas.to_bools(),
|
||||
content: canvas.into_colors(),
|
||||
version: version,
|
||||
ec_level: ec_level,
|
||||
width: version.width() as usize,
|
||||
|
@ -178,7 +178,7 @@ impl QrCode {
|
|||
for _ in 0 .. width {
|
||||
res.push('\n');
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -187,13 +187,25 @@ impl QrCode {
|
|||
|
||||
/// 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.clone()
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -231,9 +243,9 @@ impl 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;
|
||||
&self.content[index]
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![cfg(feature="image")]
|
||||
|
||||
use image::{Pixel, Rgb, Rgba, Luma, LumaA, Primitive, ImageBuffer};
|
||||
use types::Color;
|
||||
|
||||
/// A pixel which can support black and white colors.
|
||||
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
|
||||
/// an image.
|
||||
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`.
|
||||
quiet_zone: u32,
|
||||
module_size: u32,
|
||||
|
@ -65,7 +66,7 @@ pub struct Renderer<'a, P: BlankAndWhitePixel> {
|
|||
|
||||
impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
||||
/// 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());
|
||||
Renderer {
|
||||
content: content,
|
||||
|
@ -131,7 +132,11 @@ impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
|||
for y in 0 .. width {
|
||||
for x in 0 .. width {
|
||||
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;
|
||||
c
|
||||
} else {
|
||||
|
@ -153,13 +158,14 @@ impl<'a, P: BlankAndWhitePixel + 'static> Renderer<'a, P> {
|
|||
mod render_tests {
|
||||
use render::Renderer;
|
||||
use image::{Luma, Rgba};
|
||||
use types::Color;
|
||||
|
||||
#[test]
|
||||
fn test_render_luma8_unsized() {
|
||||
let image = Renderer::<Luma<u8>>::new(&[
|
||||
false, true, true,
|
||||
true, false, false,
|
||||
false, true, false,
|
||||
Color::Light, Color::Dark, Color::Dark,
|
||||
Color::Dark, Color::Light, Color::Light,
|
||||
Color::Light, Color::Dark, Color::Light,
|
||||
], 3, 1).module_size(1).to_image();
|
||||
|
||||
let expected = [
|
||||
|
@ -175,8 +181,8 @@ mod render_tests {
|
|||
#[test]
|
||||
fn test_render_rgba_unsized() {
|
||||
let image = Renderer::<Rgba<u8>>::new(&[
|
||||
false, true,
|
||||
true, true,
|
||||
Color::Light, Color::Dark,
|
||||
Color::Dark, Color::Dark,
|
||||
], 2, 1).module_size(1).to_image();
|
||||
|
||||
let expected: &[u8] = &[
|
||||
|
@ -192,8 +198,8 @@ mod render_tests {
|
|||
#[test]
|
||||
fn test_render_resized() {
|
||||
let image = Renderer::<Luma<u8>>::new(&[
|
||||
true, false,
|
||||
false, true,
|
||||
Color::Dark, Color::Light,
|
||||
Color::Light, Color::Dark,
|
||||
], 2, 1).min_width(10).to_image();
|
||||
|
||||
let expected: &[u8] = &[
|
||||
|
|
43
src/types.rs
43
src/types.rs
|
@ -1,6 +1,7 @@
|
|||
use std::default::Default;
|
||||
use std::cmp::{PartialOrd, Ordering};
|
||||
use std::fmt::{Display, Formatter, Error};
|
||||
use std::ops::Not;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//{{{ QrResult
|
||||
|
@ -42,6 +43,48 @@ impl Display for QrError {
|
|||
/// `QrResult` is a convenient alias for a QR code generation result.
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue