diff --git a/src/bits.rs b/src/bits.rs index c763c79..e7d7738 100644 --- a/src/bits.rs +++ b/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>(&mut self, - data: &[u8], - mut segments_iter: I, - ec_level: ErrorCorrectionLevel, - data_length: uint) -> QrResult<()> { - self.data.reserve(data_length); + pub fn push_segments>(&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> { - 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> { + 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, Version)> { +pub fn encode_auto(data: &[u8], ec_level: ErrorCorrectionLevel) -> QrResult { let segments = Parser::new(data).collect::>(); for version in [Version(9), Version(26), Version(40)].iter() { let opt_segments = Optimizer::new(segments.iter().map(|s| *s), *version).collect::>(); @@ -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)); } } diff --git a/src/ec.rs b/src/ec.rs index 2c2c023..c469cb8 100644 --- a/src/ec.rs +++ b/src/ec.rs @@ -65,6 +65,17 @@ mod ec_tests { // TODO Make Vec implements ImmutableVector, or &[T] implements Index. trait InterleaveSupport { + /// Equivalent to + /// + /// ```ignore + /// if i < self.len() { + /// v.push(self[i]); + /// } + /// ``` + /// + /// This trait exists solely because `Vec` 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); } @@ -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)], diff --git a/src/lib.rs b/src/lib.rs index a28b0f3..9f05d0e 100644 --- a/src/lib.rs +++ b/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::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 { - 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 { + 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 { - 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 { - 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 { + 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()); diff --git a/src/optimize.rs b/src/optimize.rs index 634572b..992d2fc 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -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 { } impl> Optimizer { - pub fn new(mut parser: I, version: Version) -> Optimizer { - 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 { + 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> Optimizer { } 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> { Optimizer::new(self, version) } diff --git a/src/types.rs b/src/types.rs index c5be5f5..f22cac2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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), }