Change all bool type to explicit Color type.

This commit is contained in:
kennytm 2017-05-22 21:38:23 +08:00
parent fab0705ef8
commit 21114481f4
6 changed files with 183 additions and 128 deletions

View file

@ -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

View file

@ -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);

View file

@ -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()
}
} }
//}}} //}}}

View file

@ -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]
} }

View file

@ -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] = &[

View file

@ -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