2014-08-18 14:26:49 -05:00
|
|
|
|
#![unstable]
|
|
|
|
|
|
|
|
|
|
use std::default::Default;
|
2015-01-10 07:53:34 -06:00
|
|
|
|
use std::cmp::{PartialOrd, Ordering};
|
2014-08-18 14:26:49 -05:00
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
//{{{ QrResult
|
|
|
|
|
|
|
|
|
|
/// `QrError` encodes the error encountered when generating a QR code.
|
|
|
|
|
#[unstable]
|
2015-01-10 07:53:34 -06:00
|
|
|
|
#[derive(Show, PartialEq, Eq, Copy, Clone)]
|
2014-08-18 14:26:49 -05:00
|
|
|
|
pub enum QrError {
|
|
|
|
|
/// The data is too long to encode into a QR code for the given version.
|
|
|
|
|
DataTooLong,
|
|
|
|
|
|
|
|
|
|
/// The provided version / error correction level combination is invalid.
|
|
|
|
|
InvalidVersion,
|
|
|
|
|
|
|
|
|
|
/// Some characters in the data cannot be supported by the provided QR code
|
|
|
|
|
/// version.
|
|
|
|
|
UnsupportedCharacterSet,
|
|
|
|
|
|
|
|
|
|
/// The provided ECI designator is invalid. A valid designator should be
|
|
|
|
|
/// between 0 and 999999.
|
|
|
|
|
InvalidEciDesignator,
|
|
|
|
|
|
|
|
|
|
/// A character not belonging to the character set is found.
|
|
|
|
|
InvalidCharacter,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `QrResult` is a convenient alias for a QR code generation result.
|
|
|
|
|
#[stable]
|
|
|
|
|
pub type QrResult<T> = Result<T, QrError>;
|
|
|
|
|
|
|
|
|
|
//}}}
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
//{{{ Error correction level
|
|
|
|
|
|
|
|
|
|
/// The error correction level. It allows the original information be recovered
|
|
|
|
|
/// even if parts of the code is damaged.
|
2015-01-10 07:53:34 -06:00
|
|
|
|
#[derive(Show, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
|
2014-08-18 14:26:49 -05:00
|
|
|
|
#[unstable]
|
2014-11-28 15:29:01 -06:00
|
|
|
|
pub enum EcLevel {
|
2014-08-18 14:26:49 -05:00
|
|
|
|
/// Low error correction. Allows up to 7% of wrong blocks.
|
|
|
|
|
L = 0,
|
|
|
|
|
|
|
|
|
|
/// Medium error correction (default). Allows up to 15% of wrong blocks.
|
|
|
|
|
M = 1,
|
|
|
|
|
|
|
|
|
|
/// "Quartile" error correction. Allows up to 25% of wrong blocks.
|
|
|
|
|
Q = 2,
|
|
|
|
|
|
|
|
|
|
/// High error correction. Allows up to 30% of wrong blocks.
|
|
|
|
|
H = 3,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//}}}
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
//{{{ Version
|
|
|
|
|
|
|
|
|
|
/// In QR code terminology, `Version` means the size of the generated image.
|
|
|
|
|
/// Larger version means the size of code is larger, and therefore can carry
|
|
|
|
|
/// more information.
|
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// The smallest version is `Version::Normal(1)` of size 21×21, and the largest
|
|
|
|
|
/// is `Version::Normal(40)` of size 177×177.
|
2014-08-18 14:26:49 -05:00
|
|
|
|
#[unstable]
|
2015-01-10 07:53:34 -06:00
|
|
|
|
#[derive(Show, PartialEq, Eq, Copy, Clone)]
|
2014-11-28 15:29:01 -06:00
|
|
|
|
pub enum Version {
|
2014-08-18 14:26:49 -05:00
|
|
|
|
/// A normal QR code version. The parameter should be between 1 and 40.
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Normal(i16),
|
2014-08-18 14:26:49 -05:00
|
|
|
|
|
|
|
|
|
/// A Micro QR code version. The parameter should be between 1 and 4.
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Micro(i16),
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-28 15:29:01 -06:00
|
|
|
|
impl Version {
|
2014-08-18 14:26:49 -05:00
|
|
|
|
/// Get the number of "modules" on each size of the QR code, i.e. the width
|
|
|
|
|
/// and height of the code.
|
|
|
|
|
#[unstable]
|
|
|
|
|
pub fn width(&self) -> i16 {
|
|
|
|
|
match *self {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Normal(v) => v * 4 + 17,
|
|
|
|
|
Version::Micro(v) => v * 2 + 9,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Obtains an object from a hard-coded table.
|
|
|
|
|
///
|
|
|
|
|
/// The table must be a 44×4 array. The outer array represents the content
|
|
|
|
|
/// for each version. The first 40 entry corresponds to QR code versions 1
|
|
|
|
|
/// to 40, and the last 4 corresponds to Micro QR code version 1 to 4. The
|
|
|
|
|
/// inner array represents the content in each error correction level, in
|
|
|
|
|
/// the order [L, M, Q, H].
|
|
|
|
|
///
|
|
|
|
|
/// If the entry compares equal to the default value of T, this method
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// returns `Err(QrError::InvalidVersion)`.
|
2015-01-10 07:53:34 -06:00
|
|
|
|
pub fn fetch<T>(&self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T>
|
2014-09-12 04:18:04 -05:00
|
|
|
|
where T: PartialEq + Default + Copy
|
|
|
|
|
{
|
2014-08-18 14:26:49 -05:00
|
|
|
|
match *self {
|
2015-01-10 07:53:34 -06:00
|
|
|
|
Version::Normal(v @ 1...40) => Ok(table[v as usize - 1][ec_level as usize]),
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Micro(v @ 1...4) => {
|
2015-01-10 07:53:34 -06:00
|
|
|
|
let obj = table[v as usize + 39][ec_level as usize];
|
2014-08-18 14:26:49 -05:00
|
|
|
|
if obj != Default::default() {
|
|
|
|
|
Ok(obj)
|
|
|
|
|
} else {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Err(QrError::InvalidVersion)
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-28 15:29:01 -06:00
|
|
|
|
_ => Err(QrError::InvalidVersion)
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The number of bits needed to encode the mode indicator.
|
|
|
|
|
#[unstable]
|
2015-01-10 07:53:34 -06:00
|
|
|
|
pub fn mode_bits_count(&self) -> usize {
|
2014-08-18 14:26:49 -05:00
|
|
|
|
match *self {
|
2015-01-10 07:53:34 -06:00
|
|
|
|
Version::Micro(a) => (a - 1) as usize,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
_ => 4,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-01 06:33:11 -06:00
|
|
|
|
/// Checks whether is version refers to a Micro QR code.
|
2014-08-18 14:26:49 -05:00
|
|
|
|
#[unstable]
|
|
|
|
|
pub fn is_micro(&self) -> bool {
|
|
|
|
|
match *self {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Normal(_) => false,
|
|
|
|
|
Version::Micro(_) => true,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-01 06:33:11 -06:00
|
|
|
|
|
2014-08-18 14:26:49 -05:00
|
|
|
|
//}}}
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
//{{{ Mode indicator
|
|
|
|
|
|
|
|
|
|
/// The mode indicator, which specifies the character set of the encoded data.
|
|
|
|
|
#[unstable]
|
2015-01-10 07:53:34 -06:00
|
|
|
|
#[derive(Show, PartialEq, Eq, Copy, Clone)]
|
2014-08-18 14:26:49 -05:00
|
|
|
|
pub enum Mode {
|
|
|
|
|
/// The data contains only characters 0 to 9.
|
|
|
|
|
Numeric,
|
|
|
|
|
|
|
|
|
|
/// The data contains only uppercase letters (A–Z), numbers (0–9) and a few
|
|
|
|
|
/// punctuations marks (space, `$`, `%`, `*`, `+`, `-`, `.`, `/`, `:`).
|
|
|
|
|
Alphanumeric,
|
|
|
|
|
|
|
|
|
|
/// The data contains arbitrary binary data.
|
|
|
|
|
Byte,
|
|
|
|
|
|
|
|
|
|
/// The data contains Shift-JIS-encoded double-byte text.
|
|
|
|
|
Kanji,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Mode {
|
|
|
|
|
/// Computes the number of bits needed to encode the data length.
|
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// use qrcode::types::{Version, Mode};
|
2014-08-18 14:26:49 -05:00
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// assert_eq!(Mode::Numeric.length_bits_count(Version::Normal(1)), 10);
|
2014-08-18 14:26:49 -05:00
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// This method will return `Err(QrError::UnsupportedCharacterSet)` if the
|
|
|
|
|
/// mode is not supported in the given version.
|
2014-08-18 14:26:49 -05:00
|
|
|
|
#[unstable]
|
2015-01-10 07:53:34 -06:00
|
|
|
|
pub fn length_bits_count(&self, version: Version) -> usize {
|
2014-08-18 14:26:49 -05:00
|
|
|
|
match version {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Micro(a) => {
|
2015-01-10 07:53:34 -06:00
|
|
|
|
let a = a as usize;
|
2014-08-18 14:26:49 -05:00
|
|
|
|
match *self {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Mode::Numeric => 2 + a,
|
|
|
|
|
Mode::Alphanumeric | Mode::Byte => 1 + a,
|
|
|
|
|
Mode::Kanji => a,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Normal(1...9) => match *self {
|
|
|
|
|
Mode::Numeric => 10,
|
|
|
|
|
Mode::Alphanumeric => 9,
|
|
|
|
|
Mode::Byte => 8,
|
|
|
|
|
Mode::Kanji => 8,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
},
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Normal(10...26) => match *self {
|
|
|
|
|
Mode::Numeric => 12,
|
|
|
|
|
Mode::Alphanumeric => 11,
|
|
|
|
|
Mode::Byte => 16,
|
|
|
|
|
Mode::Kanji => 10,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
},
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Version::Normal(_) => match *self {
|
|
|
|
|
Mode::Numeric => 14,
|
|
|
|
|
Mode::Alphanumeric => 13,
|
|
|
|
|
Mode::Byte => 16,
|
|
|
|
|
Mode::Kanji => 12,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Computes the number of bits needed to some data of a given raw length.
|
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// use qrcode::types::Mode;
|
2014-08-18 14:26:49 -05:00
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// assert_eq!(Mode::Numeric.data_bits_count(7), 24);
|
2014-08-18 14:26:49 -05:00
|
|
|
|
///
|
|
|
|
|
/// Note that in Kanji mode, the `raw_data_len` is the number of Kanjis,
|
|
|
|
|
/// i.e. half the total size of bytes.
|
|
|
|
|
#[unstable]
|
2015-01-10 07:53:34 -06:00
|
|
|
|
pub fn data_bits_count(&self, raw_data_len: usize) -> usize {
|
2014-08-18 14:26:49 -05:00
|
|
|
|
match *self {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
Mode::Numeric => (raw_data_len * 10 + 2) / 3,
|
|
|
|
|
Mode::Alphanumeric => (raw_data_len * 11 + 1) / 2,
|
|
|
|
|
Mode::Byte => raw_data_len * 8,
|
|
|
|
|
Mode::Kanji => raw_data_len * 13,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Find the lowest common mode which both modes are compatible with.
|
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// use qrcode::types::Mode;
|
2014-08-18 14:26:49 -05:00
|
|
|
|
///
|
2014-11-28 15:29:01 -06:00
|
|
|
|
/// let a = Mode::Numeric;
|
|
|
|
|
/// let b = Mode::Kanji;
|
2014-08-18 14:26:49 -05:00
|
|
|
|
/// let c = a.max(b);
|
|
|
|
|
/// assert!(a <= c);
|
|
|
|
|
/// assert!(b <= c);
|
|
|
|
|
///
|
|
|
|
|
pub fn max(&self, other: Mode) -> Mode {
|
|
|
|
|
match self.partial_cmp(&other) {
|
2015-01-10 07:53:34 -06:00
|
|
|
|
Some(Ordering::Less) | Some(Ordering::Equal) => other,
|
|
|
|
|
Some(Ordering::Greater) => *self,
|
2014-11-28 15:29:01 -06:00
|
|
|
|
None => Mode::Byte,
|
2014-08-18 14:26:49 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PartialOrd for Mode {
|
|
|
|
|
/// Defines a partial ordering between modes. If `a <= b`, then `b` contains
|
|
|
|
|
/// a superset of all characters supported by `a`.
|
|
|
|
|
fn partial_cmp(&self, other: &Mode) -> Option<Ordering> {
|
|
|
|
|
match (*self, *other) {
|
2015-01-10 07:53:34 -06:00
|
|
|
|
(Mode::Numeric, Mode::Alphanumeric) => Some(Ordering::Less),
|
|
|
|
|
(Mode::Alphanumeric, Mode::Numeric) => Some(Ordering::Greater),
|
|
|
|
|
(Mode::Numeric, Mode::Byte) => Some(Ordering::Less),
|
|
|
|
|
(Mode::Byte, Mode::Numeric) => Some(Ordering::Greater),
|
|
|
|
|
(Mode::Alphanumeric, Mode::Byte) => Some(Ordering::Less),
|
|
|
|
|
(Mode::Byte, Mode::Alphanumeric) => Some(Ordering::Greater),
|
|
|
|
|
(Mode::Kanji, Mode::Byte) => Some(Ordering::Less),
|
|
|
|
|
(Mode::Byte, Mode::Kanji) => Some(Ordering::Greater),
|
|
|
|
|
(a, b) if a == b => Some(Ordering::Equal),
|
2014-08-18 14:26:49 -05:00
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod mode_tests {
|
2014-11-28 15:29:01 -06:00
|
|
|
|
use types::Mode::{Numeric, Alphanumeric, Byte, Kanji};
|
2014-08-18 14:26:49 -05:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_mode_order() {
|
|
|
|
|
assert!(Numeric < Alphanumeric);
|
|
|
|
|
assert!(Byte > Kanji);
|
|
|
|
|
assert!(!(Numeric < Kanji));
|
|
|
|
|
assert!(!(Numeric >= Kanji));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_max() {
|
|
|
|
|
assert_eq!(Byte.max(Kanji), Byte);
|
|
|
|
|
assert_eq!(Numeric.max(Alphanumeric), Alphanumeric);
|
|
|
|
|
assert_eq!(Alphanumeric.max(Alphanumeric), Alphanumeric);
|
|
|
|
|
assert_eq!(Numeric.max(Kanji), Byte);
|
|
|
|
|
assert_eq!(Kanji.max(Numeric), Byte);
|
|
|
|
|
assert_eq!(Alphanumeric.max(Numeric), Alphanumeric);
|
|
|
|
|
assert_eq!(Kanji.max(Kanji), Kanji);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//}}}
|
|
|
|
|
|
2014-11-28 15:57:11 -06:00
|
|
|
|
// 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.
|
|
|
|
|
|