Merge branch 'version020'
Version 0.2.0.
This commit is contained in:
commit
e3c947dc99
|
@ -31,6 +31,9 @@ matrix:
|
||||||
- env: ARCH=i686
|
- env: ARCH=i686
|
||||||
rust: 1.8.0
|
rust: 1.8.0
|
||||||
# Note: on 1.8.0, all i686 build panics with the message "Box<Any>", cause all `should_panic` tests to fail.
|
# Note: on 1.8.0, all i686 build panics with the message "Box<Any>", cause all `should_panic` tests to fail.
|
||||||
|
- env: ARCH=i686
|
||||||
|
rust: nightly
|
||||||
|
# Note: nightly-i686 keeps failing, it seems that travis's nightly is outdated.
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- if [ "$TRAVIS_OS_NAME" = 'linux' ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi
|
- if [ "$TRAVIS_OS_NAME" = 'linux' ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi
|
||||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -1,21 +1,23 @@
|
||||||
[package]
|
[package]
|
||||||
name = "qrcode"
|
name = "qrcode"
|
||||||
description = "QR code encoder in Rust"
|
description = "QR code encoder in Rust"
|
||||||
license = "Apache-2.0"
|
license = "MIT / Apache-2.0"
|
||||||
version = "0.1.8"
|
version = "0.2.0"
|
||||||
authors = ["kennytm <kennytm@gmail.com>"]
|
authors = ["kennytm <kennytm@gmail.com>"]
|
||||||
keywords = ["qrcode"]
|
keywords = ["qrcode"]
|
||||||
repository = "https://github.com/kennytm/qrcode-rust"
|
repository = "https://github.com/kennytm/qrcode-rust"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
documentation = "http://kennytm.github.io/qrcode-rust/qrcode-rust/qrcode/"
|
documentation = "http://kennytm.github.io/qrcode-rust/"
|
||||||
exclude = [
|
exclude = [
|
||||||
"scripts/*", ".travis.yml", ".gitignore"
|
".travis.yml", ".gitignore"
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num = "0.1"
|
num-traits = "0.1.32"
|
||||||
|
image = { version = "0.10.0", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["image"]
|
||||||
bench = []
|
bench = []
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
19
LICENSE-MIT.txt
Normal file
19
LICENSE-MIT.txt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2016 kennytm
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
44
README.md
44
README.md
|
@ -4,14 +4,50 @@ qrcode-rust
|
||||||
[![Build status](https://travis-ci.org/kennytm/qrcode-rust.svg?branch=master)](https://travis-ci.org/kennytm/qrcode-rust)
|
[![Build status](https://travis-ci.org/kennytm/qrcode-rust.svg?branch=master)](https://travis-ci.org/kennytm/qrcode-rust)
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/kennytm/qrcode-rust/badge.svg?branch=coveralls)](https://coveralls.io/github/kennytm/qrcode-rust?branch=coveralls)
|
[![Coverage Status](https://coveralls.io/repos/github/kennytm/qrcode-rust/badge.svg?branch=coveralls)](https://coveralls.io/github/kennytm/qrcode-rust?branch=coveralls)
|
||||||
[![crates.io](http://meritbadge.herokuapp.com/qrcode)](https://crates.io/crates/qrcode)
|
[![crates.io](http://meritbadge.herokuapp.com/qrcode)](https://crates.io/crates/qrcode)
|
||||||
[![Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE)
|
[![MIT / Apache 2.0](https://img.shields.io/badge/license-MIT%20%2f%20Apache%202.0-blue.svg)](./LICENSE-APACHE.txt)
|
||||||
|
|
||||||
QR code and Micro QR code encoder in Rust.
|
QR code and Micro QR code encoder in Rust. [Documentation](https://kennytm.github.io/qrcode-rust).
|
||||||
|
|
||||||
|
Cargo.toml
|
||||||
|
----------
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# Cargo.toml
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
qrcode = "0.1.7"
|
qrcode = "0.2.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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 }
|
||||||
|
```
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
This code:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate qrcode;
|
||||||
|
extern crate image;
|
||||||
|
|
||||||
|
use qrcode::QrCode;
|
||||||
|
use image::GrayImage;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Encode some data into bits.
|
||||||
|
let code = QrCode::new(b"01234567").unwrap();
|
||||||
|
|
||||||
|
// Render the bits into an image.
|
||||||
|
let image: GrayImage = code.render().to_image();
|
||||||
|
|
||||||
|
// Save the image.
|
||||||
|
image.save("/tmp/qrcode.png").unwrap();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Generates this image:
|
||||||
|
|
||||||
|
![Output](src/test_annex_i_qr_as_image.png)
|
||||||
|
|
||||||
|
|
13
src/bits.rs
13
src/bits.rs
|
@ -894,17 +894,4 @@ mod encode_auto_tests {
|
||||||
//}}}
|
//}}}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Copyright 2014 Kenny Chan
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
// use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
// the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
// License for the specific language governing permissions and limitations under
|
|
||||||
// the License.
|
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
|
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use num::traits::PrimInt;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
use types::{Version, EcLevel};
|
use types::{Version, EcLevel};
|
||||||
|
|
||||||
// TODO remove this after it is decided whether we want `p ... q` or
|
// TODO remove this after `p ... q` becomes stable. See rust-lang/rust#28237.
|
||||||
// `(p .. q).inclusive()`
|
|
||||||
fn range_inclusive<N: PrimInt>(from: N, to: N) -> Range<N> {
|
fn range_inclusive<N: PrimInt>(from: N, to: N) -> Range<N> {
|
||||||
from .. (to + N::one())
|
from .. (to + N::one())
|
||||||
}
|
}
|
||||||
|
@ -1884,17 +1884,4 @@ impl Canvas {
|
||||||
//}}}
|
//}}}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Copyright 2014 Kenny Chan
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
// use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
// the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
// License for the specific language governing permissions and limitations under
|
|
||||||
// the License.
|
|
||||||
|
|
||||||
|
|
13
src/ec.rs
13
src/ec.rs
|
@ -444,17 +444,4 @@ static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
|
||||||
// Copyright 2014-2016 kennytm
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
// use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
// the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
// License for the specific language governing permissions and limitations under
|
|
||||||
// the License.
|
|
||||||
|
|
||||||
|
|
88
src/lib.rs
88
src/lib.rs
|
@ -2,37 +2,46 @@
|
||||||
//!
|
//!
|
||||||
//! This crate provides a QR code and Micro QR code encoder for binary data.
|
//! This crate provides a QR code and Micro QR code encoder for binary data.
|
||||||
//!
|
//!
|
||||||
//! use qrcode::QrCode;
|
//! ```
|
||||||
|
//! extern crate image;
|
||||||
|
//! extern crate qrcode;
|
||||||
//!
|
//!
|
||||||
//! let code = QrCode::new(b"Some content here.");
|
//! use image::GrayImage;
|
||||||
//! match code {
|
//! use qrcode::QrCode;
|
||||||
//! Err(err) => panic!("Failed to encode the QR code: {:?}", err),
|
//!
|
||||||
//! Ok(code) => {
|
//! # fn main() {
|
||||||
//! for y in 0 .. code.width() {
|
//!
|
||||||
//! for x in 0 .. code.width() {
|
//! let code = QrCode::new(b"Some content here.");
|
||||||
//! let color = if code[(x, y)] { "black" } else { "white" };
|
//! match code {
|
||||||
//! // render color at position (x, y)
|
//! Err(err) => panic!("Failed to encode the QR code: {:?}", err),
|
||||||
//! }
|
//! Ok(code) => {
|
||||||
//! }
|
//! let image: GrayImage = code.render().min_width(100).to_image();
|
||||||
//! }
|
//! // render `image`...
|
||||||
//! }
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
#![cfg_attr(feature="bench", feature(test))] // Unstable libraries
|
#![cfg_attr(feature="bench", feature(test))] // Unstable libraries
|
||||||
|
|
||||||
#[cfg(feature="bench")]
|
#[cfg(feature="bench")] extern crate test;
|
||||||
extern crate test;
|
extern crate num_traits;
|
||||||
extern crate num;
|
#[cfg(feature="image")] extern crate image;
|
||||||
|
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
pub use types::{QrResult, EcLevel, Version};
|
|
||||||
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod bits;
|
pub mod bits;
|
||||||
pub mod optimize;
|
pub mod optimize;
|
||||||
pub mod ec;
|
pub mod ec;
|
||||||
pub mod canvas;
|
pub mod canvas;
|
||||||
|
pub mod render;
|
||||||
|
|
||||||
|
pub use types::{QrResult, EcLevel, Version};
|
||||||
|
|
||||||
|
#[cfg(feature="image")] use render::{BlankAndWhitePixel, Renderer};
|
||||||
|
|
||||||
/// The encoded QR code symbol.
|
/// The encoded QR code symbol.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -186,6 +195,12 @@ impl QrCode {
|
||||||
pub fn into_vec(self) -> Vec<bool> {
|
pub fn into_vec(self) -> Vec<bool> {
|
||||||
self.content
|
self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="image")]
|
||||||
|
pub fn render<P: BlankAndWhitePixel + 'static>(&self) -> Renderer<P> {
|
||||||
|
let quiet_zone = if self.version.is_micro() { 2 } else { 4 };
|
||||||
|
Renderer::new(&self.content, self.width, quiet_zone)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<(usize, usize)> for QrCode {
|
impl Index<(usize, usize)> for QrCode {
|
||||||
|
@ -249,17 +264,30 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copyright 2014 Kenny Chan
|
#[cfg(all(test, feature="image"))]
|
||||||
//
|
mod image_tests {
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
use image::{GrayImage, Rgb, load_from_memory};
|
||||||
// use this file except in compliance with the License. You may obtain a copy of
|
use {QrCode, Version, EcLevel};
|
||||||
// the License at
|
|
||||||
//
|
#[test]
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
fn test_annex_i_qr_as_image() {
|
||||||
//
|
let code = QrCode::new(b"01234567").unwrap();
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
let image: GrayImage = code.render().to_image();
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma();
|
||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
assert_eq!(image.dimensions(), expected.dimensions());
|
||||||
// License for the specific language governing permissions and limitations under
|
assert_eq!(image.into_raw(), expected.into_raw());
|
||||||
// the License.
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_annex_i_micro_qr_as_image() {
|
||||||
|
let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
|
||||||
|
let image = code.render().min_width(200)
|
||||||
|
.dark_color(Rgb { data: [128, 0, 0] })
|
||||||
|
.light_color(Rgb { data: [255, 255, 128] })
|
||||||
|
.to_image();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -676,17 +676,4 @@ static STATE_TRANSITION: [(State, Action); 70] = [
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
|
||||||
// Copyright 2014 Kenny Chan
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
// use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
// the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
// License for the specific language governing permissions and limitations under
|
|
||||||
// the License.
|
|
||||||
|
|
||||||
|
|
222
src/render.rs
Normal file
222
src/render.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
//! Render a QR code into image.
|
||||||
|
|
||||||
|
#![cfg(feature="image")]
|
||||||
|
|
||||||
|
use image::{Pixel, Rgb, Rgba, Luma, LumaA, Primitive, ImageBuffer};
|
||||||
|
|
||||||
|
/// A pixel which can support black and white colors.
|
||||||
|
pub trait BlankAndWhitePixel: Pixel {
|
||||||
|
fn black_color() -> Self;
|
||||||
|
fn white_color() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Primitive + 'static> BlankAndWhitePixel for Rgb<S> {
|
||||||
|
fn black_color() -> Self {
|
||||||
|
Rgb { data: [S::zero(); 3] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn white_color() -> Self {
|
||||||
|
Rgb { data: [S::max_value(); 3] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Primitive + 'static> BlankAndWhitePixel for Rgba<S> {
|
||||||
|
fn black_color() -> Self {
|
||||||
|
Rgba { data: [S::zero(), S::zero(), S::zero(), S::max_value()] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn white_color() -> Self {
|
||||||
|
Rgba { data: [S::max_value(); 4] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Primitive + 'static> BlankAndWhitePixel for Luma<S> {
|
||||||
|
fn black_color() -> Self {
|
||||||
|
Luma { data: [S::zero()] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn white_color() -> Self {
|
||||||
|
Luma { data: [S::max_value()] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Primitive + 'static> BlankAndWhitePixel for LumaA<S> {
|
||||||
|
fn black_color() -> Self {
|
||||||
|
LumaA { data: [S::zero(), S::max_value()] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn white_color() -> Self {
|
||||||
|
LumaA { data: [S::max_value(); 2] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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],
|
||||||
|
modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`.
|
||||||
|
quiet_zone: u32,
|
||||||
|
module_size: u32,
|
||||||
|
|
||||||
|
dark_color: P,
|
||||||
|
light_color: P,
|
||||||
|
has_quiet_zone: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
assert!(modules_count * modules_count == content.len());
|
||||||
|
Renderer {
|
||||||
|
content: content,
|
||||||
|
modules_count: modules_count as u32,
|
||||||
|
quiet_zone: quiet_zone,
|
||||||
|
module_size: 8,
|
||||||
|
dark_color: P::black_color(),
|
||||||
|
light_color: P::white_color(),
|
||||||
|
has_quiet_zone: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets color of a dark module. Default is opaque black.
|
||||||
|
pub fn dark_color(&mut self, color: P) -> &mut Self {
|
||||||
|
self.dark_color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets color of a light module. Default is opaque white.
|
||||||
|
pub fn light_color(&mut self, color: P) -> &mut Self {
|
||||||
|
self.light_color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether to include the quiet zone in the generated image.
|
||||||
|
pub fn quiet_zone(&mut self, has_quiet_zone: bool) -> &mut Self {
|
||||||
|
self.has_quiet_zone = has_quiet_zone;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the size of each module in pixels. Default is 8px.
|
||||||
|
pub fn module_size(&mut self, size: u32) -> &mut Self {
|
||||||
|
self.module_size = size;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the minimal total image width (and thus height) in pixels,
|
||||||
|
/// including the quiet zone if applicable. The renderer will try to find
|
||||||
|
/// the dimension as small as possible, such that each module in the QR code
|
||||||
|
/// has uniform size (no distortion).
|
||||||
|
///
|
||||||
|
/// For instance, a version 1 QR code has 19 modules across including the
|
||||||
|
/// quiet zone. If we request an image of width ≥200px, we get that each
|
||||||
|
/// module's size should be 11px, so the actual image size will be 209px.
|
||||||
|
pub fn min_width(&mut self, width: u32) -> &mut Self {
|
||||||
|
let quiet_zone = if self.has_quiet_zone { 2 } else { 0 } * self.quiet_zone;
|
||||||
|
let width_in_modules = self.modules_count + quiet_zone;
|
||||||
|
let module_size = (width + width_in_modules - 1) / width_in_modules;
|
||||||
|
self.module_size(module_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Renders the QR code into an image.
|
||||||
|
pub fn to_image(&self) -> ImageBuffer<P, Vec<P::Subpixel>> {
|
||||||
|
let w = self.modules_count;
|
||||||
|
let qz = if self.has_quiet_zone { self.quiet_zone } else { 0 };
|
||||||
|
let width = w + 2 * qz;
|
||||||
|
|
||||||
|
let ms = self.module_size;
|
||||||
|
let real_width = width * ms;
|
||||||
|
|
||||||
|
let mut image = ImageBuffer::new(real_width, real_width);
|
||||||
|
let mut i = 0;
|
||||||
|
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 };
|
||||||
|
i += 1;
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
self.light_color
|
||||||
|
};
|
||||||
|
for yy in y * ms .. (y + 1) * ms {
|
||||||
|
for xx in x * ms .. (x + 1) * ms {
|
||||||
|
image.put_pixel(xx, yy, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod render_tests {
|
||||||
|
use render::Renderer;
|
||||||
|
use image::{Luma, Rgba};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_render_luma8_unsized() {
|
||||||
|
let image = Renderer::<Luma<u8>>::new(&[
|
||||||
|
false, true, true,
|
||||||
|
true, false, false,
|
||||||
|
false, true, false,
|
||||||
|
], 3, 1).module_size(1).to_image();
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
255, 255, 255, 255, 255,
|
||||||
|
255, 255, 0, 0, 255,
|
||||||
|
255, 0, 255, 255, 255,
|
||||||
|
255, 255, 0, 255, 255,
|
||||||
|
255, 255, 255, 255, 255,
|
||||||
|
];
|
||||||
|
assert_eq!(image.into_raw(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_render_rgba_unsized() {
|
||||||
|
let image = Renderer::<Rgba<u8>>::new(&[
|
||||||
|
false, true,
|
||||||
|
true, true,
|
||||||
|
], 2, 1).module_size(1).to_image();
|
||||||
|
|
||||||
|
let expected: &[u8] = &[
|
||||||
|
255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255,
|
||||||
|
255,255,255,255, 255,255,255,255, 0, 0, 0,255, 255,255,255,255,
|
||||||
|
255,255,255,255, 0, 0, 0,255, 0, 0, 0,255, 255,255,255,255,
|
||||||
|
255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255,
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(image.into_raw(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_render_resized() {
|
||||||
|
let image = Renderer::<Luma<u8>>::new(&[
|
||||||
|
true, false,
|
||||||
|
false, true,
|
||||||
|
], 2, 1).min_width(10).to_image();
|
||||||
|
|
||||||
|
let expected: &[u8] = &[
|
||||||
|
255,255,255, 255,255,255, 255,255,255, 255,255,255,
|
||||||
|
255,255,255, 255,255,255, 255,255,255, 255,255,255,
|
||||||
|
255,255,255, 255,255,255, 255,255,255, 255,255,255,
|
||||||
|
|
||||||
|
255,255,255, 0, 0, 0, 255,255,255, 255,255,255,
|
||||||
|
255,255,255, 0, 0, 0, 255,255,255, 255,255,255,
|
||||||
|
255,255,255, 0, 0, 0, 255,255,255, 255,255,255,
|
||||||
|
|
||||||
|
255,255,255, 255,255,255, 0, 0, 0, 255,255,255,
|
||||||
|
255,255,255, 255,255,255, 0, 0, 0, 255,255,255,
|
||||||
|
255,255,255, 255,255,255, 0, 0, 0, 255,255,255,
|
||||||
|
|
||||||
|
255,255,255, 255,255,255, 255,255,255, 255,255,255,
|
||||||
|
255,255,255, 255,255,255, 255,255,255, 255,255,255,
|
||||||
|
255,255,255, 255,255,255, 255,255,255, 255,255,255,
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(image.dimensions(), (12, 12));
|
||||||
|
assert_eq!(image.into_raw(), expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
BIN
src/test_annex_i_micro_qr_as_image.png
Normal file
BIN
src/test_annex_i_micro_qr_as_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 B |
BIN
src/test_annex_i_qr_as_image.png
Normal file
BIN
src/test_annex_i_qr_as_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 217 B |
13
src/types.rs
13
src/types.rs
|
@ -279,17 +279,4 @@ mod mode_tests {
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
|
||||||
// Copyright 2014 Kenny Chan
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
// use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
// the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
// License for the specific language governing permissions and limitations under
|
|
||||||
// the License.
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue