Update doc. Refactor bits API. De-experimentalize everything.
This commit is contained in:
parent
072cadec95
commit
6b4d8aa366
75
src/bits.rs
75
src/bits.rs
|
@ -97,6 +97,11 @@ impl Bits {
|
|||
(self.data.len() - 1) * 8 + self.bit_offset
|
||||
}
|
||||
}
|
||||
|
||||
/// Version of the QR code.
|
||||
pub fn version(&self) -> Version {
|
||||
self.version
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -227,7 +232,6 @@ impl Bits {
|
|||
///
|
||||
/// If the designator is outside of the expected range, this method will
|
||||
/// return `Err(InvalidECIDesignator)`.
|
||||
#[experimental]
|
||||
pub fn push_eci_designator(&mut self, eci_designator: u32) -> QrResult<()> {
|
||||
self.reserve_additional(12); // assume the common case that eci_designator <= 127.
|
||||
try!(self.push_mode_indicator(Eci));
|
||||
|
@ -568,7 +572,6 @@ impl Bits {
|
|||
/// bits.push_alphanumeric_data(b"%10ABC123");
|
||||
///
|
||||
/// In QR code, the character `%` is used as the data field separator (0x1D).
|
||||
#[experimental]
|
||||
pub fn push_fnc1_first_position(&mut self) -> QrResult<()> {
|
||||
self.push_mode_indicator(Fnc1First)
|
||||
}
|
||||
|
@ -593,7 +596,6 @@ impl Bits {
|
|||
/// ```ignore
|
||||
/// bits.push_fnc1_second_position(b'A' + 100);
|
||||
/// ```
|
||||
#[experimental]
|
||||
pub fn push_fnc1_second_position(&mut self, application_indicator: u8) -> QrResult<()> {
|
||||
try!(self.push_mode_indicator(Fnc1Second));
|
||||
self.push_number(8, application_indicator as u16);
|
||||
|
@ -755,13 +757,9 @@ mod finish_tests {
|
|||
|
||||
impl Bits {
|
||||
/// Push a segmented data to the bits, and then terminate it.
|
||||
#[experimental]
|
||||
pub fn push_segments_terminated<I: Iterator<Segment>>(&mut self,
|
||||
data: &[u8],
|
||||
mut segments_iter: I,
|
||||
ec_level: ErrorCorrectionLevel,
|
||||
data_length: uint) -> QrResult<()> {
|
||||
self.data.reserve(data_length);
|
||||
pub fn push_segments<I: Iterator<Segment>>(&mut self,
|
||||
data: &[u8],
|
||||
mut segments_iter: I) -> QrResult<()> {
|
||||
for segment in segments_iter {
|
||||
let slice = data.slice(segment.begin, segment.end);
|
||||
try!(match segment.mode {
|
||||
|
@ -771,26 +769,29 @@ impl Bits {
|
|||
Kanji => self.push_kanji_data(slice),
|
||||
});
|
||||
}
|
||||
try!(self.push_terminator(ec_level));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Pushes the data the bits, using the optimal encoding.
|
||||
pub fn push_optimal_data(&mut self, data: &[u8]) -> QrResult<()> {
|
||||
let segments = Parser::new(data).optimize(self.version);
|
||||
self.push_segments(data, segments)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Encodes a binary string to the raw QR code bits.
|
||||
#[experimental]
|
||||
pub fn encode(data: &[u8], version: Version, ec_level: ErrorCorrectionLevel) -> QrResult<Vec<u8>> {
|
||||
let segments = Parser::new(data);
|
||||
let opt_segments = segments.optimize(version);
|
||||
let mut bits = Bits::new(version);
|
||||
try!(bits.push_segments_terminated(data, opt_segments, ec_level, 0u));
|
||||
Ok(bits.into_bytes())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod encode_tests {
|
||||
use bits::encode;
|
||||
use types::{Version, MicroVersion, DataTooLong, L, Q, H};
|
||||
use bits::Bits;
|
||||
use types::{Version, MicroVersion, DataTooLong, QrResult,
|
||||
L, Q, H, ErrorCorrectionLevel};
|
||||
|
||||
fn encode(data: &[u8], version: Version, ec_level: ErrorCorrectionLevel) -> QrResult<Vec<u8>> {
|
||||
let mut bits = Bits::new(version);
|
||||
try!(bits.push_optimal_data(data));
|
||||
try!(bits.push_terminator(ec_level));
|
||||
Ok(bits.into_bytes())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alphanumeric() {
|
||||
|
@ -824,8 +825,7 @@ mod encode_tests {
|
|||
/// the result.
|
||||
///
|
||||
/// This method will not consider any Micro QR code versions.
|
||||
#[experimental]
|
||||
pub fn encode_auto(data: &[u8], ec_level: ErrorCorrectionLevel) -> QrResult<(Vec<u8>, Version)> {
|
||||
pub fn encode_auto(data: &[u8], ec_level: ErrorCorrectionLevel) -> QrResult<Bits> {
|
||||
let segments = Parser::new(data).collect::<Vec<Segment>>();
|
||||
for version in [Version(9), Version(26), Version(40)].iter() {
|
||||
let opt_segments = Optimizer::new(segments.iter().map(|s| *s), *version).collect::<Vec<Segment>>();
|
||||
|
@ -834,9 +834,10 @@ pub fn encode_auto(data: &[u8], ec_level: ErrorCorrectionLevel) -> QrResult<(Vec
|
|||
if total_len <= data_capacity {
|
||||
let min_version = find_min_version(total_len, ec_level);
|
||||
let mut bits = Bits::new(min_version);
|
||||
try!(bits.push_segments_terminated(data, opt_segments.move_iter(),
|
||||
ec_level, total_len));
|
||||
return Ok((bits.into_bytes(), min_version));
|
||||
bits.reserve_additional(total_len);
|
||||
try!(bits.push_segments(data, opt_segments.move_iter()));
|
||||
try!(bits.push_terminator(ec_level));
|
||||
return Ok(bits);
|
||||
}
|
||||
}
|
||||
Err(DataTooLong)
|
||||
|
@ -878,26 +879,20 @@ mod encode_auto_tests {
|
|||
|
||||
#[test]
|
||||
fn test_alpha_q() {
|
||||
match encode_auto(b"HELLO WORLD", Q) {
|
||||
Ok((_, Version(1))) => {},
|
||||
x => fail!("{}", x),
|
||||
}
|
||||
let bits = encode_auto(b"HELLO WORLD", Q).unwrap();
|
||||
assert_eq!(bits.version(), Version(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alpha_h() {
|
||||
match encode_auto(b"HELLO WORLD", H) {
|
||||
Ok((_, Version(2))) => {},
|
||||
x => fail!("{}", x),
|
||||
}
|
||||
let bits = encode_auto(b"HELLO WORLD", H).unwrap();
|
||||
assert_eq!(bits.version(), Version(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed() {
|
||||
match encode_auto(b"This is a mixed data test. 1234567890", H) {
|
||||
Ok((_, Version(4))) => {},
|
||||
x => fail!("{}", x),
|
||||
}
|
||||
let bits = encode_auto(b"This is a mixed data test. 1234567890", H).unwrap();
|
||||
assert_eq!(bits.version(), Version(4));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
src/ec.rs
15
src/ec.rs
|
@ -65,6 +65,17 @@ mod ec_tests {
|
|||
|
||||
// TODO Make Vec implements ImmutableVector, or &[T] implements Index.
|
||||
trait InterleaveSupport<T> {
|
||||
/// Equivalent to
|
||||
///
|
||||
/// ```ignore
|
||||
/// if i < self.len() {
|
||||
/// v.push(self[i]);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This trait exists solely because `Vec<T>` does not implement
|
||||
/// ImmutableVector, or `&[T]` does not implement Index. This trait can be
|
||||
/// deprecated once either of above are implemented.
|
||||
fn push_item_to(&self, i: uint, v: &mut Vec<T>);
|
||||
}
|
||||
|
||||
|
@ -270,7 +281,7 @@ static GENERATOR_POLYNOMIALS: [&'static [u8], ..70] = [
|
|||
/// correction per block in each version.
|
||||
///
|
||||
/// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9.
|
||||
pub static EC_BYTES_PER_BLOCK: [[uint, ..4], ..44] = [
|
||||
static EC_BYTES_PER_BLOCK: [[uint, ..4], ..44] = [
|
||||
// Normal versions.
|
||||
[7, 10, 13, 17],
|
||||
[10, 16, 22, 28],
|
||||
|
@ -328,7 +339,7 @@ pub static EC_BYTES_PER_BLOCK: [[uint, ..4], ..44] = [
|
|||
/// Every entry is a 4-tuple. Take `DATA_BYTES_PER_BLOCK[39][3] == (15, 20, 16, 61)`
|
||||
/// as an example, this means in version 40 with correction level H, there are
|
||||
/// 20 blocks with 15 bytes in size, and 61 blocks with 16 bytes in size.
|
||||
pub static DATA_BYTES_PER_BLOCK: [[(uint, uint, uint, uint), ..4], ..44] = [
|
||||
static DATA_BYTES_PER_BLOCK: [[(uint, uint, uint, uint), ..4], ..44] = [
|
||||
// Normal versions.
|
||||
[(19, 1, 0, 0), (16, 1, 0, 0), (13, 1, 0, 0), (9, 1, 0, 0)],
|
||||
[(34, 1, 0, 0), (28, 1, 0, 0), (22, 1, 0, 0), (16, 1, 0, 0)],
|
||||
|
|
70
src/lib.rs
70
src/lib.rs
|
@ -44,34 +44,80 @@ impl QrCode {
|
|||
/// Constructs a new QR code which automatically encodes the given data.
|
||||
///
|
||||
/// This method uses the "medium" error correction level and automatically
|
||||
/// chooses the smallest QR code. Please use `.with_error_correction()` and
|
||||
/// `.with_version()` for finer adjustment.
|
||||
/// chooses the smallest QR code.
|
||||
///
|
||||
/// use qrcode::QrCode;
|
||||
///
|
||||
/// let code = QrCode::new(b"Some data").unwrap();
|
||||
///
|
||||
pub fn new(data: &[u8]) -> QrResult<QrCode> {
|
||||
QrCode::with_error_correction(data, M)
|
||||
QrCode::with_error_correction_level(data, M)
|
||||
}
|
||||
|
||||
/// Constructs a new QR code which automatically encodes the given data at a
|
||||
/// specific error correction level.
|
||||
///
|
||||
/// This method automatically chooses the smallest QR code.
|
||||
pub fn with_error_correction(data: &[u8], ec_level: ErrorCorrectionLevel) -> QrResult<QrCode> {
|
||||
let (encoded_data, version) = try!(bits::encode_auto(data, ec_level));
|
||||
QrCode::with_encoded_data(encoded_data.as_slice(), version, ec_level)
|
||||
///
|
||||
/// use qrcode::{QrCode, H};
|
||||
///
|
||||
/// let code = QrCode::with_error_correction_level(b"Some data", H).unwrap();
|
||||
///
|
||||
pub fn with_error_correction_level(data: &[u8], ec_level: ErrorCorrectionLevel) -> QrResult<QrCode> {
|
||||
let bits = try!(bits::encode_auto(data, ec_level));
|
||||
QrCode::with_bits(bits, ec_level)
|
||||
}
|
||||
|
||||
/// Constructs a new QR code for the given version and error correction
|
||||
/// level.
|
||||
///
|
||||
/// use qrcode::{QrCode, Version, M};
|
||||
///
|
||||
/// let code = QrCode::with_version(b"Some data", Version(5), M).unwrap();
|
||||
///
|
||||
/// This method can also be used to generate Micro QR code.
|
||||
///
|
||||
/// use qrcode::{QrCode, MicroVersion, L};
|
||||
///
|
||||
/// let micro_code = QrCode::with_version(b"123", MicroVersion(1), L).unwrap();
|
||||
///
|
||||
pub fn with_version(data: &[u8],
|
||||
version: Version,
|
||||
ec_level: ErrorCorrectionLevel) -> QrResult<QrCode> {
|
||||
let encoded_data = try!(bits::encode(data, version, ec_level));
|
||||
QrCode::with_encoded_data(encoded_data.as_slice(), version, ec_level)
|
||||
let mut bits = bits::Bits::new(version);
|
||||
try!(bits.push_optimal_data(data));
|
||||
try!(bits.push_terminator(ec_level));
|
||||
QrCode::with_bits(bits, ec_level)
|
||||
}
|
||||
|
||||
fn with_encoded_data(data: &[u8],
|
||||
version: Version,
|
||||
ec_level: ErrorCorrectionLevel) -> QrResult<QrCode> {
|
||||
let (encoded_data, ec_data) = try!(ec::construct_codewords(data, version, ec_level));
|
||||
/// Constructs a new QR code with encoded bits.
|
||||
///
|
||||
/// Use this method only if there are very special need to manipulate the
|
||||
/// raw bits before encoding. Some examples are:
|
||||
///
|
||||
/// * Encode data using specific character set with ECI
|
||||
/// * Use the FNC1 modes
|
||||
/// * Avoid the optimal segmentation algorithm
|
||||
///
|
||||
/// See the `Bits` structure for detail.
|
||||
///
|
||||
/// #![allow(unused_must_use)];
|
||||
///
|
||||
/// use qrcode::{QrCode, Version, L};
|
||||
/// use qrcode::bits::Bits;
|
||||
///
|
||||
/// let mut bits = Bits::new(Version(1));
|
||||
/// bits.push_eci_designator(9);
|
||||
/// bits.push_byte_data(b"\xca\xfe\xe4\xe9\xea\xe1\xf2 QR");
|
||||
/// bits.push_terminator(L);
|
||||
/// let qrcode = QrCode::with_bits(bits, L);
|
||||
///
|
||||
pub fn with_bits(bits: bits::Bits,
|
||||
ec_level: ErrorCorrectionLevel) -> QrResult<QrCode> {
|
||||
let version = bits.version();
|
||||
let data = bits.into_bytes();
|
||||
let (encoded_data, ec_data) = try!(ec::construct_codewords(data.as_slice(),
|
||||
version, ec_level));
|
||||
let mut canvas = canvas::Canvas::new(version, ec_level);
|
||||
canvas.draw_all_functional_patterns();
|
||||
canvas.draw_data(encoded_data.as_slice(), ec_data.as_slice());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![experimental]
|
||||
#![unstable]
|
||||
|
||||
//! Find the optimal data mode sequence to encode a piece of data.
|
||||
|
||||
|
@ -233,17 +233,23 @@ pub struct Optimizer<I> {
|
|||
}
|
||||
|
||||
impl<I: Iterator<Segment>> Optimizer<I> {
|
||||
pub fn new(mut parser: I, version: Version) -> Optimizer<I> {
|
||||
match parser.next() {
|
||||
/// Optimize the segments by combining adjacent segments when possible.
|
||||
///
|
||||
/// Currently this method uses a greedy algorithm by combining segments from
|
||||
/// left to right until the new segment is longer than before. This method
|
||||
/// does *not* use Annex J from the ISO standard.
|
||||
///
|
||||
pub fn new(mut segments: I, version: Version) -> Optimizer<I> {
|
||||
match segments.next() {
|
||||
None => Optimizer {
|
||||
parser: parser,
|
||||
parser: segments,
|
||||
last_segment: Segment { mode: Numeric, begin: 0, end: 0 },
|
||||
last_segment_size: 0,
|
||||
version: version,
|
||||
ended: true,
|
||||
},
|
||||
Some(segment) => Optimizer {
|
||||
parser: parser,
|
||||
parser: segments,
|
||||
last_segment: segment,
|
||||
last_segment_size: segment.encoded_len(version),
|
||||
version: version,
|
||||
|
@ -254,12 +260,6 @@ impl<I: Iterator<Segment>> Optimizer<I> {
|
|||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
/// Optimize the segments by combining adjacent segments when possible.
|
||||
///
|
||||
/// Currently this method uses a greedy algorithm by combining segments from
|
||||
/// left to right until the new segment is longer than before. This method
|
||||
/// does *not* use Annex J from the ISO standard.
|
||||
///
|
||||
pub fn optimize(self, version: Version) -> Optimizer<Parser<'a>> {
|
||||
Optimizer::new(self, version)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ pub enum QrError {
|
|||
|
||||
/// The provided ECI designator is invalid. A valid designator should be
|
||||
/// between 0 and 999999.
|
||||
#[experimental]
|
||||
InvalidEciDesignator,
|
||||
|
||||
/// A character not belonging to the character set is found.
|
||||
|
@ -72,10 +71,6 @@ pub enum Version {
|
|||
Version(i16),
|
||||
|
||||
/// A Micro QR code version. The parameter should be between 1 and 4.
|
||||
///
|
||||
/// This crate currently does not fully support Micro QR code yet, and using
|
||||
/// these versions will likely result in `Err(InvalidVersion)`.
|
||||
#[experimental]
|
||||
MicroVersion(i16),
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue