This commit is contained in:
kennytm 2018-07-30 16:59:03 +08:00
parent 01f209d0a5
commit 51dd9c4fa1
16 changed files with 123 additions and 449 deletions

View file

@ -1,8 +1,8 @@
extern crate image;
extern crate qrcode;
use qrcode::QrCode;
use image::Luma;
use qrcode::QrCode;
fn main() {
// Encode some data into bits.

View file

@ -3,9 +3,6 @@ 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();
let string = code.render::<char>().quiet_zone(false).module_dimensions(2, 1).build();
println!("{}", string);
}

View file

@ -1,11 +1,12 @@
extern crate qrcode;
use qrcode::{EcLevel, QrCode, Version};
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()
let image = code
.render()
.min_dimensions(200, 200)
.dark_color(svg::Color("#800000"))
.light_color(svg::Color("#ffff80"))

View file

@ -1,8 +1,2 @@
array_width = 100
chain_width = 100
fn_call_width = 100
# single_line_if_else_max_width = 100
struct_lit_width = 100
struct_variant_width = 100
error_on_line_overflow = false
max_width = 120
use_small_heuristics = "Max"

View file

@ -6,11 +6,5 @@ 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()
);
print!("{}", code.render().dark_color("\x1b[7m \x1b[0m").light_color("\x1b[49m \x1b[0m").build());
}

View file

@ -5,9 +5,9 @@ use std::cmp::min;
#[cfg(feature = "bench")]
use test::Bencher;
use types::{EcLevel, Mode, QrError, QrResult, Version};
use optimize::{total_encoded_len, Optimizer, Parser, Segment};
use cast::{As, Truncate};
use optimize::{total_encoded_len, Optimizer, Parser, Segment};
use types::{EcLevel, Mode, QrError, QrResult, Version};
//------------------------------------------------------------------------------
//{{{ Bits
@ -31,12 +31,7 @@ impl Bits {
/// `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),
"{} is too big as a {}-bit number",
number,
n
);
debug_assert!(n == 16 || n < 16 && number < (1 << n), "{} is too big as a {}-bit number", number, n);
let b = self.bit_offset + n;
let last_index = self.data.len().wrapping_sub(1);
@ -205,8 +200,7 @@ impl Bits {
(_, ExtendedMode::StructuredAppend) => 0b0011,
};
let bits = self.version.mode_bits_count();
self.push_number_checked(bits, number)
.or(Err(QrError::UnsupportedCharacterSet))
self.push_number_checked(bits, number).or(Err(QrError::UnsupportedCharacterSet))
}
}
@ -330,10 +324,7 @@ impl Bits {
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 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);
}
@ -437,10 +428,7 @@ impl Bits {
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 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);
}
@ -543,11 +531,7 @@ impl Bits {
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 bytes = if cp < 0xe040 { cp - 0x8140 } else { cp - 0xc140 };
let number = (bytes >> 8) * 0xc0 + (bytes & 0xff);
self.push_number(13, number);
}
@ -564,10 +548,7 @@ mod kanji_tests {
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]
);
assert_eq!(bits.into_bytes(), vec![0b1000_0000, 0b0010_0110, 0b11001111, 0b1_1101010, 0b101010__00]);
}
#[test]
@ -579,10 +560,7 @@ mod kanji_tests {
#[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)
);
assert_eq!(bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"), Err(QrError::DataTooLong));
}
}
@ -715,11 +693,7 @@ impl Bits {
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()
.cloned()
.cycle()
.take(padding_bytes_count);
let padding = PADDING_BYTES.iter().cloned().cycle().take(padding_bytes_count);
self.data.extend(padding);
}
@ -744,19 +718,8 @@ mod finish_tests {
assert_eq!(
bits.into_bytes(),
vec![
0b00100000,
0b01011011,
0b00001011,
0b01111000,
0b11010001,
0b01110010,
0b11011100,
0b01001101,
0b01000011,
0b01000000,
0b11101100,
0b00010001,
0b11101100,
0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101,
0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100,
]
);
}
@ -848,19 +811,8 @@ mod encode_tests {
assert_eq!(
res,
Ok(vec![
0b00100000,
0b01011011,
0b00001011,
0b01111000,
0b11010001,
0b01110010,
0b11011100,
0b01001101,
0b01000011,
0b01000000,
0b11101100,
0b00010001,
0b11101100,
0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101,
0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100,
])
);
}
@ -868,10 +820,7 @@ mod encode_tests {
#[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])
);
assert_eq!(res, Ok(vec![0b0_0011_000, 0b1111011_1, 0b001_00101, 0b0_00000__00, 0b11101100]));
}
#[test]
@ -894,9 +843,7 @@ pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
for version in &[Version::Normal(9), Version::Normal(26), Version::Normal(40)] {
let opt_segments = Optimizer::new(segments.iter().cloned(), *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");
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);
@ -941,7 +888,6 @@ mod encode_auto_tests {
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();

View file

@ -11,8 +11,8 @@
use std::cmp::max;
use types::{Color, EcLevel, Version};
use cast::As;
use types::{Color, EcLevel, Version};
//------------------------------------------------------------------------------
//{{{ Modules
@ -492,7 +492,6 @@ mod alignment_pattern_tests {
}
}
/// `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.
@ -548,15 +547,7 @@ impl Canvas {
/// `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,
) {
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 {
@ -657,21 +648,10 @@ impl Canvas {
/// `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)],
) {
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
};
let color = if (mask & number) == 0 { off_color } else { on_color };
self.put(x, y, color);
mask >>= 1;
}
@ -682,29 +662,11 @@ impl Canvas {
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,
);
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.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.
}
}
@ -723,20 +685,8 @@ impl Canvas {
}
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,
);
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);
}
}
}
@ -750,13 +700,7 @@ mod draw_version_info_tests {
#[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)],
);
c.draw_number(0b10101101, 8, Color::Dark, Color::Light, &[(0, 0), (0, -1), (-2, -2), (-2, 0)]);
assert_eq!(
&*c.to_debug_str(),
"\n\
@ -1011,40 +955,9 @@ static FORMAT_INFO_COORDS_MICRO_QR: [(i16, i16); 15] = [
];
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,
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,
];
//}}}
@ -1217,7 +1130,6 @@ mod all_functional_patterns_tests {
assert!(!is_functional(version, version.width(), 1, 9));
}
}
//}}}
@ -1250,11 +1162,7 @@ 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
};
let adjusted_ref_col = if self.x <= self.timing_pattern_column { self.x + 1 } else { self.x };
if adjusted_ref_col <= 0 {
return None;
}
@ -1459,19 +1367,11 @@ impl Canvas {
I: Iterator<Item = (i16, i16)>,
{
let length = codewords.len();
let last_word = if is_half_codeword_at_end {
length - 1
} else {
length
};
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
};
let color = if (*b & (1 << j)) == 0 { Color::Light } else { Color::Dark };
while let Some((x, y)) = coords.next() {
let r = self.get_mut(x, y);
if *r == Module::Empty {
@ -1784,73 +1684,15 @@ mod mask_tests {
}
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,
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,
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,
];
//}}}
@ -1867,15 +1709,9 @@ impl Canvas {
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 map_fn = |j| if is_horizontal { self.get(j, i) } else { self.get(i, j) };
let colors = (0..self.width)
.map(map_fn)
.chain(Some(Module::Empty).into_iter());
let colors = (0..self.width).map(map_fn).chain(Some(Module::Empty).into_iter());
let mut last_color = Module::Empty;
let mut consecutive_len = 1_u16;
@ -1924,15 +1760,8 @@ 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: [Color; 7] = [
Color::Dark,
Color::Light,
Color::Dark,
Color::Dark,
Color::Dark,
Color::Light,
Color::Dark,
];
static PATTERN: [Color; 7] =
[Color::Dark, Color::Light, Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Dark];
let mut total_score = 0;
@ -1971,11 +1800,7 @@ impl Canvas {
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;
if ratio >= 100 {
ratio - 100
} else {
100 - ratio
}.as_u16()
if ratio >= 100 { ratio - 100 } else { 100 - ratio }.as_u16()
}
/// Compute the penalty score for having too many light modules on the sides.
@ -1986,12 +1811,8 @@ impl Canvas {
/// 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();
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()
}
@ -2001,13 +1822,13 @@ impl Canvas {
fn compute_total_penalty_scores(&self) -> u16 {
match self.version {
Version::Normal(_) => {
let s1a = self.compute_adjacent_penalty_score(true);
let s1b = self.compute_adjacent_penalty_score(false);
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 s3a = self.compute_finder_penalty_score(true);
let s3b = self.compute_finder_penalty_score(false);
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();
s1a + s1b + s2 + s3a + s3b + s4
s1_a + s1_b + s2 + s3_a + s3_b + s4
}
Version::Micro(_) => self.compute_light_side_penalty_score(),
}
@ -2152,12 +1973,8 @@ static ALL_PATTERNS_QR: [MaskPattern; 8] = [
MaskPattern::Meadow,
];
static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] = [
MaskPattern::HorizontalLines,
MaskPattern::LargeCheckerboard,
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
@ -2170,8 +1987,7 @@ impl Canvas {
let mut c = self.clone();
c.apply_mask(*ptn);
c
})
.min_by_key(Self::compute_total_penalty_scores)
}).min_by_key(Self::compute_total_penalty_scores)
.expect("at least one pattern")
}

View file

@ -81,7 +81,7 @@ macro_rules! impl_as {
self as isize
}
}
}
};
}
impl_as!(i16);

View file

@ -99,13 +99,8 @@ fn test_interleave() {
/// Constructs data and error correction codewords ready to be put in the QR
/// code matrix.
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)?;
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;
@ -122,10 +117,7 @@ pub fn construct_codewords(
// 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 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);
@ -141,8 +133,7 @@ mod construct_codewords_test {
#[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();
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");
}
@ -160,8 +151,7 @@ mod construct_codewords_test {
\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();
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[..]);
}
@ -174,8 +164,8 @@ mod construct_codewords_test {
/// Computes the maximum allowed number of erratic modules can be introduced to
/// the QR code, before the data becomes truly corrupted.
pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult<usize> {
use Version::{Micro, Normal};
use EcLevel::{L, M};
use Version::{Micro, Normal};
let p = match (version, ec_level) {
(Micro(2), L) | (Normal(1), L) => 3,

View file

@ -46,19 +46,19 @@ extern crate test;
use std::ops::Index;
pub mod types;
pub mod bits;
pub mod optimize;
pub mod ec;
pub mod canvas;
pub mod render;
mod cast;
pub mod ec;
pub mod optimize;
pub mod render;
pub mod types;
pub use types::{Color, EcLevel, QrResult, Version};
use render::{Pixel, Renderer};
use checked_int_cast::CheckedIntCast;
use cast::As;
use checked_int_cast::CheckedIntCast;
use render::{Pixel, Renderer};
/// The encoded QR code symbol.
#[derive(Clone)]
@ -92,10 +92,7 @@ impl QrCode {
///
/// let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap();
///
pub fn with_error_correction_level<D: AsRef<[u8]>>(
data: D,
ec_level: EcLevel,
) -> QrResult<Self> {
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)
}
@ -113,11 +110,7 @@ impl QrCode {
///
/// let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap();
///
pub fn with_version<D: AsRef<[u8]>>(
data: D,
version: Version,
ec_level: EcLevel,
) -> QrResult<Self> {
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)?;
@ -189,21 +182,15 @@ impl QrCode {
/// Checks whether a module at coordinate (x, y) is a functional module or
/// not.
pub fn is_functional(&self, x: usize, y: usize) -> bool {
let x = x.as_i16_checked()
.expect("coordinate is too large for QR code");
let y = y.as_i16_checked()
.expect("coordinate is too large for QR code");
let x = x.as_i16_checked().expect("coordinate is too large for QR code");
let y = y.as_i16_checked().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()
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
@ -217,10 +204,7 @@ impl QrCode {
/// 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()
self.content.into_iter().map(|c| c != Color::Light).collect()
}
/// Converts the QR code to a vector of colors.
@ -342,9 +326,7 @@ mod image_tests {
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()
.to_luma();
let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma();
assert_eq!(image.dimensions(), expected.dimensions());
assert_eq!(image.into_raw(), expected.into_raw());
}
@ -352,14 +334,13 @@ mod image_tests {
#[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()
let image = code
.render()
.min_dimensions(200, 200)
.dark_color(Rgb { data: [128, 0, 0] })
.light_color(Rgb { data: [255, 255, 128] })
.build();
let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png"))
.unwrap()
.to_rgb();
let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png")).unwrap().to_rgb();
assert_eq!(image.dimensions(), expected.dimensions());
assert_eq!(image.into_raw(), expected.into_raw());
}
@ -381,7 +362,8 @@ mod svg_tests {
#[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()
let image = code
.render()
.min_dimensions(200, 200)
.dark_color(SvgColor("#800000"))
.light_color(SvgColor("#ffff80"))

View file

@ -26,11 +26,7 @@ impl Segment {
/// 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 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);
@ -144,9 +140,7 @@ impl<'a> Iterator for Parser<'a> {
} else {
self.pending_single_byte = true;
self.begin = next_begin;
return Some(
Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin },
);
return Some(Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin });
}
}
};
@ -217,10 +211,7 @@ mod parse_tests {
let segs = parse(b"\x81\x30");
assert_eq!(
segs,
vec![
Segment { mode: Mode::Byte, begin: 0, end: 1 },
Segment { mode: Mode::Numeric, begin: 1, end: 2 },
]
vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Numeric, begin: 1, end: 2 },]
);
}
@ -231,10 +222,7 @@ mod parse_tests {
let segs = parse(b"\xeb\xc0");
assert_eq!(
segs,
vec![
Segment { mode: Mode::Byte, begin: 0, end: 1 },
Segment { mode: Mode::Byte, begin: 1, end: 2 },
]
vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },]
);
}
@ -243,10 +231,7 @@ mod parse_tests {
let segs = parse(b"\x81\x7f");
assert_eq!(
segs,
vec![
Segment { mode: Mode::Byte, begin: 0, end: 1 },
Segment { mode: Mode::Byte, begin: 1, end: 2 },
]
vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },]
);
}
@ -255,10 +240,7 @@ mod parse_tests {
let segs = parse(b"\x81\x40\x81");
assert_eq!(
segs,
vec![
Segment { mode: Mode::Kanji, begin: 0, end: 2 },
Segment { mode: Mode::Byte, begin: 2, end: 3 },
]
vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 },]
);
}
}
@ -351,9 +333,7 @@ impl<I: Iterator<Item = Segment>> Iterator for Optimizer<I> {
/// Computes the total encoded length of all segments.
pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize {
// TODO revert to `.map().sum()` after `sum()` is stable.
segments
.iter()
.fold(0, |acc, seg| acc + seg.encoded_len(version))
segments.iter().fold(0, |acc, seg| acc + seg.encoded_len(version))
}
#[cfg(test)]
@ -428,14 +408,8 @@ mod optimize_tests {
#[test]
fn test_example_4() {
test_optimization_result(
vec![
Segment { mode: Mode::Kanji, begin: 0, end: 10 },
Segment { mode: Mode::Byte, begin: 10, end: 11 },
],
vec![
Segment { mode: Mode::Kanji, begin: 0, end: 10 },
Segment { mode: Mode::Byte, begin: 10, end: 11 },
],
vec![Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }],
vec![Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }],
Version::Normal(1),
);
}
@ -507,7 +481,6 @@ fn bench_optimize(bencher: &mut Bencher) {
bencher.iter(|| Parser::new(data).optimize(Version::Normal(15)));
}
//}}}
//------------------------------------------------------------------------------
//{{{ Internal types and data for parsing

View file

@ -13,11 +13,11 @@ macro_rules! impl_pixel_for_image_pixel {
fn default_color(color: Color) -> Self {
match color.select($s::zero(), $s::max_value()) {
$c => $p { data: $d }
}
$c => $p { data: $d },
}
}
}
};
}
impl_pixel_for_image_pixel!{ Luma<S>: p => [p] }
@ -44,8 +44,8 @@ impl<P: ImagePixel + 'static> Canvas for (P, ImageBuffer<P, Vec<P::Subpixel>>) {
#[cfg(test)]
mod render_tests {
use render::Renderer;
use image::{Luma, Rgba};
use render::Renderer;
use types::Color;
#[test]
@ -82,8 +82,7 @@ mod render_tests {
#[test]
fn test_render_rgba_unsized() {
let image =
Renderer::<Rgba<u8>>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1)
let image = Renderer::<Rgba<u8>>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1)
.module_dimensions(1, 1)
.build();
@ -100,11 +99,8 @@ mod render_tests {
#[test]
fn test_render_resized_min() {
let image = Renderer::<Luma<u8>>::new(
&[Color::Dark, Color::Light, Color::Light, Color::Dark],
2,
1,
).min_dimensions(10, 10)
let image = Renderer::<Luma<u8>>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1)
.min_dimensions(10, 10)
.build();
#[cfg_attr(rustfmt, rustfmt_skip)]
@ -132,11 +128,8 @@ mod render_tests {
#[test]
fn test_render_resized_max() {
let image = Renderer::<Luma<u8>>::new(
&[Color::Dark, Color::Light, Color::Light, Color::Dark],
2,
1,
).max_dimensions(10, 5)
let image = Renderer::<Luma<u8>>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1)
.max_dimensions(10, 5)
.build();
#[cfg_attr(rustfmt, rustfmt_skip)]

View file

@ -1,8 +1,8 @@
//! Render a QR code into image.
use cast::As;
use std::cmp::max;
use types::Color;
use cast::As;
pub mod image;
pub mod string;
@ -156,8 +156,7 @@ impl<'a, P: Pixel> Renderer<'a, P> {
}
/// Renders the QR code into an image.
#[deprecated(since = "0.4.0",
note = "renamed to `.build()` to de-emphasize the image connection")]
#[deprecated(since = "0.4.0", note = "renamed to `.build()` to de-emphasize the image connection")]
pub fn to_image(&self) -> P::Image {
self.build()
}
@ -165,11 +164,7 @@ impl<'a, P: Pixel> Renderer<'a, P> {
/// Renders the QR code into an image.
pub fn build(&self) -> P::Image {
let w = self.modules_count;
let qz = if self.has_quiet_zone {
self.quiet_zone
} else {
0
};
let qz = if self.has_quiet_zone { self.quiet_zone } else { 0 };
let width = w + 2 * qz;
let (mw, mh) = self.module_size;

View file

@ -1,8 +1,8 @@
//! String rendering support.
use cast::As;
use render::{Canvas as RenderCanvas, Pixel};
use types::Color;
use cast::As;
pub trait Element: Copy {
fn default_color(color: Color) -> Self;
@ -85,7 +85,6 @@ impl<P: Element> RenderCanvas for Canvas<P> {
self.buffer[x + y * self.width] = self.dark_pixel;
}
fn into_image(self) -> String {
let mut result = String::with_capacity(self.capacity.as_usize());
for (i, pixel) in self.buffer.into_iter().enumerate() {
@ -106,11 +105,7 @@ fn test_render_to_string() {
let image: String = Renderer::<char>::new(colors, 2, 1).build();
assert_eq!(&image, " \n \u{2588} \n \u{2588} \n ");
let image2 = Renderer::new(colors, 2, 1)
.light_color("A")
.dark_color("!B!")
.module_dimensions(2, 2)
.build();
let image2 = Renderer::new(colors, 2, 1).light_color("A").dark_color("!B!").module_dimensions(2, 2).build();
assert_eq!(
&image2,

View file

@ -69,8 +69,7 @@ impl<'a> RenderCanvas for Canvas<'a> {
}
fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u32) {
write!(self.svg, "M{l} {t}h{w}v{h}H{l}V{t}", l = left, t = top, w = width, h = height)
.unwrap();
write!(self.svg, "M{l} {t}h{w}v{h}H{l}V{t}", l = left, t = top, w = width, h = height).unwrap();
}
fn into_image(mut self) -> String {

View file

@ -1,8 +1,8 @@
use std::default::Default;
use cast::As;
use std::cmp::{Ordering, PartialOrd};
use std::default::Default;
use std::fmt::{Display, Error, Formatter};
use std::ops::Not;
use cast::As;
//------------------------------------------------------------------------------
//{{{ QrResult
@ -182,7 +182,6 @@ impl Version {
}
}
//}}}
//------------------------------------------------------------------------------
//{{{ Mode indicator
@ -284,14 +283,14 @@ impl PartialOrd for Mode {
/// a superset of all characters supported by `a`.
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self, *other) {
(Mode::Numeric, Mode::Alphanumeric) |
(Mode::Numeric, Mode::Byte) |
(Mode::Alphanumeric, Mode::Byte) |
(Mode::Kanji, Mode::Byte) => Some(Ordering::Less),
(Mode::Alphanumeric, Mode::Numeric) |
(Mode::Byte, Mode::Numeric) |
(Mode::Byte, Mode::Alphanumeric) |
(Mode::Byte, Mode::Kanji) => Some(Ordering::Greater),
(Mode::Numeric, Mode::Alphanumeric)
| (Mode::Numeric, Mode::Byte)
| (Mode::Alphanumeric, Mode::Byte)
| (Mode::Kanji, Mode::Byte) => Some(Ordering::Less),
(Mode::Alphanumeric, Mode::Numeric)
| (Mode::Byte, Mode::Numeric)
| (Mode::Byte, Mode::Alphanumeric)
| (Mode::Byte, Mode::Kanji) => Some(Ordering::Greater),
(a, b) if a == b => Some(Ordering::Equal),
_ => None,
}