mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-25 20:02:34 +00:00
remove qrcode
This commit is contained in:
BIN
port_src/output/.DS_Store
vendored
BIN
port_src/output/.DS_Store
vendored
Binary file not shown.
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
struct BitMatrixParser {
|
||||
|
||||
let bit_matrix: BitMatrix;
|
||||
|
||||
let parsed_version: Version;
|
||||
|
||||
let parsed_format_info: FormatInformation;
|
||||
|
||||
let mirror: bool;
|
||||
}
|
||||
|
||||
impl BitMatrixParser {
|
||||
|
||||
/**
|
||||
* @param bitMatrix {@link BitMatrix} to parse
|
||||
* @throws FormatException if dimension is not >= 21 and 1 mod 4
|
||||
*/
|
||||
fn new( bit_matrix: &BitMatrix) -> BitMatrixParser throws FormatException {
|
||||
let dimension: i32 = bit_matrix.get_height();
|
||||
if dimension < 21 || (dimension & 0x03) != 1 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let .bitMatrix = bit_matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads format information from one of its two locations within the QR Code.</p>
|
||||
*
|
||||
* @return {@link FormatInformation} encapsulating the QR Code's format info
|
||||
* @throws FormatException if both format information locations cannot be parsed as
|
||||
* the valid encoding of format information
|
||||
*/
|
||||
fn read_format_information(&self) -> /* throws FormatException */Result<FormatInformation, Rc<Exception>> {
|
||||
if self.parsed_format_info != null {
|
||||
return Ok(self.parsed_format_info);
|
||||
}
|
||||
// Read top-left format info bits
|
||||
let format_info_bits1: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 6 {
|
||||
{
|
||||
format_info_bits1 = self.copy_bit(i, 8, format_info_bits1);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
format_info_bits1 = self.copy_bit(7, 8, format_info_bits1);
|
||||
format_info_bits1 = self.copy_bit(8, 8, format_info_bits1);
|
||||
format_info_bits1 = self.copy_bit(8, 7, format_info_bits1);
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
{
|
||||
let mut j: i32 = 5;
|
||||
while j >= 0 {
|
||||
{
|
||||
format_info_bits1 = self.copy_bit(8, j, format_info_bits1);
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the top-right/bottom-left pattern too
|
||||
let dimension: i32 = self.bit_matrix.get_height();
|
||||
let format_info_bits2: i32 = 0;
|
||||
let j_min: i32 = dimension - 7;
|
||||
{
|
||||
let mut j: i32 = dimension - 1;
|
||||
while j >= j_min {
|
||||
{
|
||||
format_info_bits2 = self.copy_bit(8, j, format_info_bits2);
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut i: i32 = dimension - 8;
|
||||
while i < dimension {
|
||||
{
|
||||
format_info_bits2 = self.copy_bit(i, 8, format_info_bits2);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.parsed_format_info = FormatInformation::decode_format_information(format_info_bits1, format_info_bits2);
|
||||
if self.parsed_format_info != null {
|
||||
return Ok(self.parsed_format_info);
|
||||
}
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads version information from one of its two locations within the QR Code.</p>
|
||||
*
|
||||
* @return {@link Version} encapsulating the QR Code's version
|
||||
* @throws FormatException if both version information locations cannot be parsed as
|
||||
* the valid encoding of version information
|
||||
*/
|
||||
fn read_version(&self) -> /* throws FormatException */Result<Version, Rc<Exception>> {
|
||||
if self.parsed_version != null {
|
||||
return Ok(self.parsed_version);
|
||||
}
|
||||
let dimension: i32 = self.bit_matrix.get_height();
|
||||
let provisional_version: i32 = (dimension - 17) / 4;
|
||||
if provisional_version <= 6 {
|
||||
return Ok(Version::get_version_for_number(provisional_version));
|
||||
}
|
||||
// Read top-right version info: 3 wide by 6 tall
|
||||
let version_bits: i32 = 0;
|
||||
let ij_min: i32 = dimension - 11;
|
||||
{
|
||||
let mut j: i32 = 5;
|
||||
while j >= 0 {
|
||||
{
|
||||
{
|
||||
let mut i: i32 = dimension - 9;
|
||||
while i >= ij_min {
|
||||
{
|
||||
version_bits = self.copy_bit(i, j, version_bits);
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let the_parsed_version: Version = Version::decode_version_information(version_bits);
|
||||
if the_parsed_version != null && the_parsed_version.get_dimension_for_version() == dimension {
|
||||
self.parsed_version = the_parsed_version;
|
||||
return Ok(the_parsed_version);
|
||||
}
|
||||
// Hmm, failed. Try bottom left: 6 wide by 3 tall
|
||||
version_bits = 0;
|
||||
{
|
||||
let mut i: i32 = 5;
|
||||
while i >= 0 {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = dimension - 9;
|
||||
while j >= ij_min {
|
||||
{
|
||||
version_bits = self.copy_bit(i, j, version_bits);
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
the_parsed_version = Version::decode_version_information(version_bits);
|
||||
if the_parsed_version != null && the_parsed_version.get_dimension_for_version() == dimension {
|
||||
self.parsed_version = the_parsed_version;
|
||||
return Ok(the_parsed_version);
|
||||
}
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
|
||||
fn copy_bit(&self, i: i32, j: i32, version_bits: i32) -> i32 {
|
||||
let bit: bool = if self.mirror { self.bit_matrix.get(j, i) } else { self.bit_matrix.get(i, j) };
|
||||
return if bit { (version_bits << 1) | 0x1 } else { version_bits << 1 };
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
|
||||
* correct order in order to reconstruct the codewords bytes contained within the
|
||||
* QR Code.</p>
|
||||
*
|
||||
* @return bytes encoded within the QR Code
|
||||
* @throws FormatException if the exact number of bytes expected is not read
|
||||
*/
|
||||
fn read_codewords(&self) -> /* throws FormatException */Result<Vec<i8>, Rc<Exception>> {
|
||||
let format_info: FormatInformation = self.read_format_information();
|
||||
let version: Version = self.read_version();
|
||||
// Get the data mask for the format used in this QR Code. This will exclude
|
||||
// some bits from reading as we wind through the bit matrix.
|
||||
let data_mask: DataMask = DataMask::values()[format_info.get_data_mask()];
|
||||
let dimension: i32 = self.bit_matrix.get_height();
|
||||
data_mask.unmask_bit_matrix(self.bit_matrix, dimension);
|
||||
let function_pattern: BitMatrix = version.build_function_pattern();
|
||||
let reading_up: bool = true;
|
||||
let mut result: [i8; version.get_total_codewords()] = [0; version.get_total_codewords()];
|
||||
let result_offset: i32 = 0;
|
||||
let current_byte: i32 = 0;
|
||||
let bits_read: i32 = 0;
|
||||
// Read columns in pairs, from right to left
|
||||
{
|
||||
let mut j: i32 = dimension - 1;
|
||||
while j > 0 {
|
||||
{
|
||||
if j == 6 {
|
||||
// Skip whole column with vertical alignment pattern;
|
||||
// saves time and makes the other code proceed more cleanly
|
||||
j -= 1;
|
||||
}
|
||||
// Read alternatingly from bottom to top then top to bottom
|
||||
{
|
||||
let mut count: i32 = 0;
|
||||
while count < dimension {
|
||||
{
|
||||
let i: i32 = if reading_up { dimension - 1 - count } else { count };
|
||||
{
|
||||
let mut col: i32 = 0;
|
||||
while col < 2 {
|
||||
{
|
||||
// Ignore bits covered by the function pattern
|
||||
if !function_pattern.get(j - col, i) {
|
||||
// Read a bit
|
||||
bits_read += 1;
|
||||
current_byte <<= 1;
|
||||
if self.bit_matrix.get(j - col, i) {
|
||||
current_byte |= 1;
|
||||
}
|
||||
// If we've made a whole byte, save it off
|
||||
if bits_read == 8 {
|
||||
result[result_offset += 1 !!!check!!! post increment] = current_byte as i8;
|
||||
bits_read = 0;
|
||||
current_byte = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// readingUp = !readingUp; // switch directions
|
||||
reading_up ^= true;
|
||||
}
|
||||
j -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if result_offset != version.get_total_codewords() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
|
||||
*/
|
||||
fn remask(&self) {
|
||||
if self.parsed_format_info == null {
|
||||
// We have no format information, and have no data mask
|
||||
return;
|
||||
}
|
||||
let data_mask: DataMask = DataMask::values()[self.parsed_format_info.get_data_mask()];
|
||||
let dimension: i32 = self.bit_matrix.get_height();
|
||||
data_mask.unmask_bit_matrix(self.bit_matrix, dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the parser for a mirrored operation.
|
||||
* This flag has effect only on the {@link #readFormatInformation()} and the
|
||||
* {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the
|
||||
* {@link #mirror()} method should be called.
|
||||
*
|
||||
* @param mirror Whether to read version and format information mirrored.
|
||||
*/
|
||||
fn set_mirror(&self, mirror: bool) {
|
||||
self.parsed_version = null;
|
||||
self.parsed_format_info = null;
|
||||
self.mirror = mirror;
|
||||
}
|
||||
|
||||
/** Mirror the bit matrix in order to attempt a second reading. */
|
||||
fn mirror(&self) {
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < self.bit_matrix.get_width() {
|
||||
{
|
||||
{
|
||||
let mut y: i32 = x + 1;
|
||||
while y < self.bit_matrix.get_height() {
|
||||
{
|
||||
if self.bit_matrix.get(x, y) != self.bit_matrix.get(y, x) {
|
||||
self.bit_matrix.flip(y, x);
|
||||
self.bit_matrix.flip(x, y);
|
||||
}
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
|
||||
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
|
||||
* is represented by an instance of this class.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
struct DataBlock {
|
||||
|
||||
let num_data_codewords: i32;
|
||||
|
||||
let mut codewords: Vec<i8>;
|
||||
}
|
||||
|
||||
impl DataBlock {
|
||||
|
||||
fn new( num_data_codewords: i32, codewords: &Vec<i8>) -> DataBlock {
|
||||
let .numDataCodewords = num_data_codewords;
|
||||
let .codewords = codewords;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
|
||||
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
||||
* method will separate the data into original blocks.</p>
|
||||
*
|
||||
* @param rawCodewords bytes as read directly from the QR Code
|
||||
* @param version version of the QR Code
|
||||
* @param ecLevel error-correction level of the QR Code
|
||||
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
|
||||
* QR Code
|
||||
*/
|
||||
fn get_data_blocks( raw_codewords: &Vec<i8>, version: &Version, ec_level: &ErrorCorrectionLevel) -> Vec<DataBlock> {
|
||||
if raw_codewords.len() != version.get_total_codewords() {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
// Figure out the number and size of data blocks used by this version and
|
||||
// error correction level
|
||||
let ec_blocks: Version.ECBlocks = version.get_e_c_blocks_for_level(ec_level);
|
||||
// First count the total number of data blocks
|
||||
let total_blocks: i32 = 0;
|
||||
let ec_block_array: Vec<Version.ECB> = ec_blocks.get_e_c_blocks();
|
||||
for let ec_block: Version.ECB in ec_block_array {
|
||||
total_blocks += ec_block.get_count();
|
||||
}
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
let mut result: [Option<DataBlock>; total_blocks] = [None; total_blocks];
|
||||
let num_result_blocks: i32 = 0;
|
||||
for let ec_block: Version.ECB in ec_block_array {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < ec_block.get_count() {
|
||||
{
|
||||
let num_data_codewords: i32 = ec_block.get_data_codewords();
|
||||
let num_block_codewords: i32 = ec_blocks.get_e_c_codewords_per_block() + num_data_codewords;
|
||||
result[num_result_blocks += 1 !!!check!!! post increment] = DataBlock::new(num_data_codewords, : [i8; num_block_codewords] = [0; num_block_codewords]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||
let shorter_blocks_total_codewords: i32 = result[0].codewords.len();
|
||||
let longer_blocks_start_at: i32 = result.len() - 1;
|
||||
while longer_blocks_start_at >= 0 {
|
||||
let num_codewords: i32 = result[longer_blocks_start_at].codewords.len();
|
||||
if num_codewords == shorter_blocks_total_codewords {
|
||||
break;
|
||||
}
|
||||
longer_blocks_start_at -= 1;
|
||||
}
|
||||
longer_blocks_start_at += 1;
|
||||
let shorter_blocks_num_data_codewords: i32 = shorter_blocks_total_codewords - ec_blocks.get_e_c_codewords_per_block();
|
||||
// The last elements of result may be 1 element longer;
|
||||
// first fill out as many elements as all of them have
|
||||
let raw_codewords_offset: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < shorter_blocks_num_data_codewords {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < num_result_blocks {
|
||||
{
|
||||
result[j].codewords[i] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out the last data block in the longer ones
|
||||
{
|
||||
let mut j: i32 = longer_blocks_start_at;
|
||||
while j < num_result_blocks {
|
||||
{
|
||||
result[j].codewords[shorter_blocks_num_data_codewords] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now add in error correction blocks
|
||||
let max: i32 = result[0].codewords.len();
|
||||
{
|
||||
let mut i: i32 = shorter_blocks_num_data_codewords;
|
||||
while i < max {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < num_result_blocks {
|
||||
{
|
||||
let i_offset: i32 = if j < longer_blocks_start_at { i } else { i + 1 };
|
||||
result[j].codewords[i_offset] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_num_data_codewords(&self) -> i32 {
|
||||
return self.num_data_codewords;
|
||||
}
|
||||
|
||||
fn get_codewords(&self) -> Vec<i8> {
|
||||
return self.codewords;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
|
||||
* of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
|
||||
* including areas used for finder patterns, timing patterns, etc. These areas should be unused
|
||||
* after the point they are unmasked anyway.</p>
|
||||
*
|
||||
* <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
|
||||
* and j is row position. In fact, as the text says, i is row position and j is column position.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
enum DataMask {
|
||||
|
||||
/**
|
||||
* 000: mask bits for which (x + y) mod 2 == 0
|
||||
*/
|
||||
DATA_MASK_000() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return ((i + j) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 001: mask bits for which x mod 2 == 0
|
||||
*/
|
||||
DATA_MASK_001() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return (i & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 010: mask bits for which y mod 3 == 0
|
||||
*/
|
||||
DATA_MASK_010() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return j % 3 == 0;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 011: mask bits for which (x + y) mod 3 == 0
|
||||
*/
|
||||
DATA_MASK_011() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return (i + j) % 3 == 0;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 100: mask bits for which (x/2 + y/3) mod 2 == 0
|
||||
*/
|
||||
DATA_MASK_100() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return (((i / 2) + (j / 3)) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 101: mask bits for which xy mod 2 + xy mod 3 == 0
|
||||
* equivalently, such that xy mod 6 == 0
|
||||
*/
|
||||
DATA_MASK_101() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return (i * j) % 6 == 0;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0
|
||||
* equivalently, such that xy mod 6 < 3
|
||||
*/
|
||||
DATA_MASK_110() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return ((i * j) % 6) < 3;
|
||||
}
|
||||
}
|
||||
, /**
|
||||
* 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0
|
||||
* equivalently, such that (x + y + xy mod 3) mod 2 == 0
|
||||
*/
|
||||
DATA_MASK_111() {
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool {
|
||||
return ((i + j + ((i * j) % 3)) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
// End of enum constants.
|
||||
/**
|
||||
* <p>Implementations of this method reverse the data masking process applied to a QR Code and
|
||||
* make its bits ready to read.</p>
|
||||
*
|
||||
* @param bits representation of QR Code bits
|
||||
* @param dimension dimension of QR Code, represented by bits, being unmasked
|
||||
*/
|
||||
fn unmask_bit_matrix(&self, bits: &BitMatrix, dimension: i32) {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < dimension {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < dimension {
|
||||
{
|
||||
if self.is_masked(i, j) {
|
||||
bits.flip(j, i);
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn is_masked(&self, i: i32, j: i32) -> bool ;
|
||||
}
|
||||
@@ -1,381 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>QR Codes can encode text as bits in one of several modes, and can use multiple modes
|
||||
* in one QR Code. This class decodes the bits back into text.</p>
|
||||
*
|
||||
* <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006, 6.4.4 Table 5
|
||||
*/
|
||||
const ALPHANUMERIC_CHARS: Vec<char> = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".to_char_array();
|
||||
|
||||
const GB2312_SUBSET: i32 = 1;
|
||||
struct DecodedBitStreamParser {
|
||||
}
|
||||
|
||||
impl DecodedBitStreamParser {
|
||||
|
||||
fn new() -> DecodedBitStreamParser {
|
||||
}
|
||||
|
||||
fn decode( bytes: &Vec<i8>, version: &Version, ec_level: &ErrorCorrectionLevel, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
let bits: BitSource = BitSource::new(&bytes);
|
||||
let result: StringBuilder = StringBuilder::new(50);
|
||||
let byte_segments: List<Vec<i8>> = ArrayList<>::new(1);
|
||||
let symbol_sequence: i32 = -1;
|
||||
let parity_data: i32 = -1;
|
||||
let symbology_modifier: i32;
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
let current_character_set_e_c_i: CharacterSetECI = null;
|
||||
let fc1_in_effect: bool = false;
|
||||
let has_f_n_c1first: bool = false;
|
||||
let has_f_n_c1second: bool = false;
|
||||
let mut mode: Mode;
|
||||
loop { {
|
||||
// While still another segment to read...
|
||||
if bits.available() < 4 {
|
||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
||||
mode = Mode::TERMINATOR;
|
||||
} else {
|
||||
// mode is encoded by 4 bits
|
||||
mode = Mode::for_bits(&bits.read_bits(4));
|
||||
}
|
||||
match mode {
|
||||
TERMINATOR =>
|
||||
{
|
||||
break;
|
||||
}
|
||||
FNC1_FIRST_POSITION =>
|
||||
{
|
||||
// symbology detection
|
||||
has_f_n_c1first = true;
|
||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
||||
fc1_in_effect = true;
|
||||
break;
|
||||
}
|
||||
FNC1_SECOND_POSITION =>
|
||||
{
|
||||
// symbology detection
|
||||
has_f_n_c1second = true;
|
||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
||||
fc1_in_effect = true;
|
||||
break;
|
||||
}
|
||||
STRUCTURED_APPEND =>
|
||||
{
|
||||
if bits.available() < 16 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
// sequence number and parity is added later to the result metadata
|
||||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
||||
symbol_sequence = bits.read_bits(8);
|
||||
parity_data = bits.read_bits(8);
|
||||
break;
|
||||
}
|
||||
ECI =>
|
||||
{
|
||||
// Count doesn't apply to ECI
|
||||
let value: i32 = ::parse_e_c_i_value(bits);
|
||||
current_character_set_e_c_i = CharacterSetECI::get_character_set_e_c_i_by_value(value);
|
||||
if current_character_set_e_c_i == null {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
HANZI =>
|
||||
{
|
||||
// First handle Hanzi mode which does not start with character count
|
||||
// Chinese mode contains a sub set indicator right after mode indicator
|
||||
let subset: i32 = bits.read_bits(4);
|
||||
let count_hanzi: i32 = bits.read_bits(&mode.get_character_count_bits(version));
|
||||
if subset == GB2312_SUBSET {
|
||||
::decode_hanzi_segment(bits, &result, count_hanzi);
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// "Normal" QR code modes:
|
||||
// How many characters will follow, encoded in this mode?
|
||||
let count: i32 = bits.read_bits(&mode.get_character_count_bits(version));
|
||||
match mode {
|
||||
NUMERIC =>
|
||||
{
|
||||
::decode_numeric_segment(bits, &result, count);
|
||||
break;
|
||||
}
|
||||
ALPHANUMERIC =>
|
||||
{
|
||||
::decode_alphanumeric_segment(bits, &result, count, fc1_in_effect);
|
||||
break;
|
||||
}
|
||||
BYTE =>
|
||||
{
|
||||
::decode_byte_segment(bits, &result, count, current_character_set_e_c_i, &byte_segments, &hints);
|
||||
break;
|
||||
}
|
||||
KANJI =>
|
||||
{
|
||||
::decode_kanji_segment(bits, &result, count);
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}if !(mode != Mode::TERMINATOR) break;}
|
||||
if current_character_set_e_c_i != null {
|
||||
if has_f_n_c1first {
|
||||
symbology_modifier = 4;
|
||||
} else if has_f_n_c1second {
|
||||
symbology_modifier = 6;
|
||||
} else {
|
||||
symbology_modifier = 2;
|
||||
}
|
||||
} else {
|
||||
if has_f_n_c1first {
|
||||
symbology_modifier = 3;
|
||||
} else if has_f_n_c1second {
|
||||
symbology_modifier = 5;
|
||||
} else {
|
||||
symbology_modifier = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( iae: &IllegalArgumentException) {
|
||||
throw FormatException::get_format_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
return Ok(DecoderResult::new(&bytes, &result.to_string(), if byte_segments.is_empty() { null } else { byte_segments }, if ec_level == null { null } else { ec_level.to_string() }, symbol_sequence, parity_data, symbology_modifier));
|
||||
}
|
||||
|
||||
/**
|
||||
* See specification GBT 18284-2000
|
||||
*/
|
||||
fn decode_hanzi_segment( bits: &BitSource, result: &StringBuilder, count: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if count * 13 > bits.available() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as GB2312 afterwards
|
||||
let mut buffer: [i8; 2 * count] = [0; 2 * count];
|
||||
let mut offset: i32 = 0;
|
||||
while count > 0 {
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
let two_bytes: i32 = bits.read_bits(13);
|
||||
let assembled_two_bytes: i32 = ((two_bytes / 0x060) << 8) | (two_bytes % 0x060);
|
||||
if assembled_two_bytes < 0x00A00 {
|
||||
// In the 0xA1A1 to 0xAAFE range
|
||||
assembled_two_bytes += 0x0A1A1;
|
||||
} else {
|
||||
// In the 0xB0A1 to 0xFAFE range
|
||||
assembled_two_bytes += 0x0A6A1;
|
||||
}
|
||||
buffer[offset] = ((assembled_two_bytes >> 8) & 0xFF) as i8;
|
||||
buffer[offset + 1] = (assembled_two_bytes & 0xFF) as i8;
|
||||
offset += 2;
|
||||
count -= 1;
|
||||
}
|
||||
result.append(String::new(&buffer, StringUtils::GB2312_CHARSET));
|
||||
}
|
||||
|
||||
fn decode_kanji_segment( bits: &BitSource, result: &StringBuilder, count: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if count * 13 > bits.available() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as Shift_JIS afterwards
|
||||
let mut buffer: [i8; 2 * count] = [0; 2 * count];
|
||||
let mut offset: i32 = 0;
|
||||
while count > 0 {
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
let two_bytes: i32 = bits.read_bits(13);
|
||||
let assembled_two_bytes: i32 = ((two_bytes / 0x0C0) << 8) | (two_bytes % 0x0C0);
|
||||
if assembled_two_bytes < 0x01F00 {
|
||||
// In the 0x8140 to 0x9FFC range
|
||||
assembled_two_bytes += 0x08140;
|
||||
} else {
|
||||
// In the 0xE040 to 0xEBBF range
|
||||
assembled_two_bytes += 0x0C140;
|
||||
}
|
||||
buffer[offset] = (assembled_two_bytes >> 8) as i8;
|
||||
buffer[offset + 1] = assembled_two_bytes as i8;
|
||||
offset += 2;
|
||||
count -= 1;
|
||||
}
|
||||
result.append(String::new(&buffer, StringUtils::SHIFT_JIS_CHARSET));
|
||||
}
|
||||
|
||||
fn decode_byte_segment( bits: &BitSource, result: &StringBuilder, count: i32, current_character_set_e_c_i: &CharacterSetECI, byte_segments: &Collection<Vec<i8>>, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if 8 * count > bits.available() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let read_bytes: [i8; count] = [0; count];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < count {
|
||||
{
|
||||
read_bytes[i] = bits.read_bits(8) as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut encoding: Charset;
|
||||
if current_character_set_e_c_i == null {
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
encoding = StringUtils::guess_charset(&read_bytes, &hints);
|
||||
} else {
|
||||
encoding = current_character_set_e_c_i.get_charset();
|
||||
}
|
||||
result.append(String::new(&read_bytes, &encoding));
|
||||
byte_segments.add(&read_bytes);
|
||||
}
|
||||
|
||||
fn to_alpha_numeric_char( value: i32) -> /* throws FormatException */Result<char, Rc<Exception>> {
|
||||
if value >= ALPHANUMERIC_CHARS.len() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
return Ok(ALPHANUMERIC_CHARS[value]);
|
||||
}
|
||||
|
||||
fn decode_alphanumeric_segment( bits: &BitSource, result: &StringBuilder, count: i32, fc1_in_effect: bool) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Read two characters at a time
|
||||
let start: i32 = result.length();
|
||||
while count > 1 {
|
||||
if bits.available() < 11 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let next_two_chars_bits: i32 = bits.read_bits(11);
|
||||
result.append(&::to_alpha_numeric_char(next_two_chars_bits / 45));
|
||||
result.append(&::to_alpha_numeric_char(next_two_chars_bits % 45));
|
||||
count -= 2;
|
||||
}
|
||||
if count == 1 {
|
||||
// special case: one character left
|
||||
if bits.available() < 6 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
result.append(&::to_alpha_numeric_char(&bits.read_bits(6)));
|
||||
}
|
||||
// See section 6.4.8.1, 6.4.8.2
|
||||
if fc1_in_effect {
|
||||
// We need to massage the result a bit if in an FNC1 mode:
|
||||
{
|
||||
let mut i: i32 = start;
|
||||
while i < result.length() {
|
||||
{
|
||||
if result.char_at(i) == '%' {
|
||||
if i < result.length() - 1 && result.char_at(i + 1) == '%' {
|
||||
// %% is rendered as %
|
||||
result.delete_char_at(i + 1);
|
||||
} else {
|
||||
// In alpha mode, % should be converted to FNC1 separator 0x1D
|
||||
result.set_char_at(i, 0x1D as char);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_numeric_segment( bits: &BitSource, result: &StringBuilder, count: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
// Read three digits at a time
|
||||
while count >= 3 {
|
||||
// Each 10 bits encodes three digits
|
||||
if bits.available() < 10 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let three_digits_bits: i32 = bits.read_bits(10);
|
||||
if three_digits_bits >= 1000 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
result.append(&::to_alpha_numeric_char(three_digits_bits / 100));
|
||||
result.append(&::to_alpha_numeric_char((three_digits_bits / 10) % 10));
|
||||
result.append(&::to_alpha_numeric_char(three_digits_bits % 10));
|
||||
count -= 3;
|
||||
}
|
||||
if count == 2 {
|
||||
// Two digits left over to read, encoded in 7 bits
|
||||
if bits.available() < 7 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let two_digits_bits: i32 = bits.read_bits(7);
|
||||
if two_digits_bits >= 100 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
result.append(&::to_alpha_numeric_char(two_digits_bits / 10));
|
||||
result.append(&::to_alpha_numeric_char(two_digits_bits % 10));
|
||||
} else if count == 1 {
|
||||
// One digit left over to read
|
||||
if bits.available() < 4 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let digit_bits: i32 = bits.read_bits(4);
|
||||
if digit_bits >= 10 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
result.append(&::to_alpha_numeric_char(digit_bits));
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_e_c_i_value( bits: &BitSource) -> /* throws FormatException */Result<i32, Rc<Exception>> {
|
||||
let first_byte: i32 = bits.read_bits(8);
|
||||
if (first_byte & 0x80) == 0 {
|
||||
// just one byte
|
||||
return Ok(first_byte & 0x7F);
|
||||
}
|
||||
if (first_byte & 0xC0) == 0x80 {
|
||||
// two bytes
|
||||
let second_byte: i32 = bits.read_bits(8);
|
||||
return Ok(((first_byte & 0x3F) << 8) | second_byte);
|
||||
}
|
||||
if (first_byte & 0xE0) == 0xC0 {
|
||||
// three bytes
|
||||
let second_third_bytes: i32 = bits.read_bits(16);
|
||||
return Ok(((first_byte & 0x1F) << 16) | second_third_bytes);
|
||||
}
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>The main class which implements QR Code decoding -- as opposed to locating and extracting
|
||||
* the QR Code from an image.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct Decoder {
|
||||
|
||||
let rs_decoder: ReedSolomonDecoder;
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
|
||||
pub fn new() -> Decoder {
|
||||
rs_decoder = ReedSolomonDecoder::new(GenericGF::QR_CODE_FIELD_256);
|
||||
}
|
||||
|
||||
pub fn decode(&self, image: &Vec<Vec<bool>>) -> /* throws ChecksumException, FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
return Ok(self.decode(&image, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.
|
||||
* "true" is taken to mean a black module.</p>
|
||||
*
|
||||
* @param image booleans representing white/black QR Code modules
|
||||
* @param hints decoding hints that should be used to influence decoding
|
||||
* @return text and bytes encoded within the QR Code
|
||||
* @throws FormatException if the QR Code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
pub fn decode(&self, image: &Vec<Vec<bool>>, hints: &Map<DecodeHintType, ?>) -> /* throws ChecksumException, FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
return Ok(self.decode(&BitMatrix::parse(&image), &hints));
|
||||
}
|
||||
|
||||
pub fn decode(&self, bits: &BitMatrix) -> /* throws ChecksumException, FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
return Ok(self.decode(bits, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
|
||||
*
|
||||
* @param bits booleans representing white/black QR Code modules
|
||||
* @param hints decoding hints that should be used to influence decoding
|
||||
* @return text and bytes encoded within the QR Code
|
||||
* @throws FormatException if the QR Code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
pub fn decode(&self, bits: &BitMatrix, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
// Construct a parser and read version, error-correction level
|
||||
let parser: BitMatrixParser = BitMatrixParser::new(bits);
|
||||
let mut fe: FormatException = null;
|
||||
let mut ce: ChecksumException = null;
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return Ok(self.decode(parser, &hints));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &FormatException) {
|
||||
fe = e;
|
||||
} catch ( e: &ChecksumException) {
|
||||
ce = e;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
// Revert the bit matrix
|
||||
parser.remask();
|
||||
// Will be attempting a mirrored reading of the version and format info.
|
||||
parser.set_mirror(true);
|
||||
// Preemptively read the version.
|
||||
parser.read_version();
|
||||
// Preemptively read the format information.
|
||||
parser.read_format_information();
|
||||
/*
|
||||
* Since we're here, this means we have successfully detected some kind
|
||||
* of version and format information when mirrored. This is a good sign,
|
||||
* that the QR code may be mirrored, and we should try once more with a
|
||||
* mirrored content.
|
||||
*/
|
||||
// Prepare for a mirrored reading.
|
||||
parser.mirror();
|
||||
let result: DecoderResult = self.decode(parser, &hints);
|
||||
// Success! Notify the caller that the code was mirrored.
|
||||
result.set_other(QRCodeDecoderMetaData::new(true));
|
||||
return Ok(result);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( e: &FormatExceptionChecksumException | ) {
|
||||
if fe != null {
|
||||
throw fe;
|
||||
}
|
||||
throw ce;
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn decode(&self, parser: &BitMatrixParser, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
let version: Version = parser.read_version();
|
||||
let ec_level: ErrorCorrectionLevel = parser.read_format_information().get_error_correction_level();
|
||||
// Read codewords
|
||||
let codewords: Vec<i8> = parser.read_codewords();
|
||||
// Separate into data blocks
|
||||
let data_blocks: Vec<DataBlock> = DataBlock::get_data_blocks(&codewords, version, ec_level);
|
||||
// Count total number of data bytes
|
||||
let total_bytes: i32 = 0;
|
||||
for let data_block: DataBlock in data_blocks {
|
||||
total_bytes += data_block.get_num_data_codewords();
|
||||
}
|
||||
let result_bytes: [i8; total_bytes] = [0; total_bytes];
|
||||
let result_offset: i32 = 0;
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for let data_block: DataBlock in data_blocks {
|
||||
let codeword_bytes: Vec<i8> = data_block.get_codewords();
|
||||
let num_data_codewords: i32 = data_block.get_num_data_codewords();
|
||||
self.correct_errors(&codeword_bytes, num_data_codewords);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
result_bytes[result_offset += 1 !!!check!!! post increment] = codeword_bytes[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Decode the contents of that stream of bytes
|
||||
return Ok(DecodedBitStreamParser::decode(&result_bytes, version, ec_level, &hints));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
||||
*
|
||||
* @param codewordBytes data and error correction codewords
|
||||
* @param numDataCodewords number of codewords that are data bytes
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn correct_errors(&self, codeword_bytes: &Vec<i8>, num_data_codewords: i32) -> /* throws ChecksumException */Result<Void, Rc<Exception>> {
|
||||
let num_codewords: i32 = codeword_bytes.len();
|
||||
// First read into an array of ints
|
||||
let codewords_ints: [i32; num_codewords] = [0; num_codewords];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_codewords {
|
||||
{
|
||||
codewords_ints[i] = codeword_bytes[i] & 0xFF;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
self.rs_decoder.decode(&codewords_ints, codeword_bytes.len() - num_data_codewords);
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &ReedSolomonException) {
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
// We don't care about errors in the error-correction codewords
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_codewords {
|
||||
{
|
||||
codeword_bytes[i] = codewords_ints[i] as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
|
||||
* defined by the QR code standard.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub enum ErrorCorrectionLevel {
|
||||
|
||||
/** L = ~7% correction */
|
||||
L(0x01), /** M = ~15% correction */
|
||||
M(0x00), /** Q = ~25% correction */
|
||||
Q(0x03), /** H = ~30% correction */
|
||||
H(0x02);
|
||||
|
||||
const FOR_BITS: vec![Vec<ErrorCorrectionLevel>; 4] = vec![M, L, H, Q, ]
|
||||
;
|
||||
|
||||
let bits: i32;
|
||||
|
||||
fn new( bits: i32) -> ErrorCorrectionLevel {
|
||||
let .bits = bits;
|
||||
}
|
||||
|
||||
pub fn get_bits(&self) -> i32 {
|
||||
return self.bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bits int containing the two bits encoding a QR Code's error correction level
|
||||
* @return ErrorCorrectionLevel representing the encoded error correction level
|
||||
*/
|
||||
pub fn for_bits( bits: i32) -> ErrorCorrectionLevel {
|
||||
if bits < 0 || bits >= FOR_BITS.len() {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
return FOR_BITS[bits];
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a QR Code's format information, including the data mask used and
|
||||
* error correction level.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @see DataMask
|
||||
* @see ErrorCorrectionLevel
|
||||
*/
|
||||
|
||||
const FORMAT_INFO_MASK_QR: i32 = 0x5412;
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006, Annex C, Table C.1
|
||||
*/
|
||||
const FORMAT_INFO_DECODE_LOOKUP: vec![vec![Vec<Vec<i32>>; 2]; 32] = vec![vec![0x5412, 0x00, ]
|
||||
, vec![0x5125, 0x01, ]
|
||||
, vec![0x5E7C, 0x02, ]
|
||||
, vec![0x5B4B, 0x03, ]
|
||||
, vec![0x45F9, 0x04, ]
|
||||
, vec![0x40CE, 0x05, ]
|
||||
, vec![0x4F97, 0x06, ]
|
||||
, vec![0x4AA0, 0x07, ]
|
||||
, vec![0x77C4, 0x08, ]
|
||||
, vec![0x72F3, 0x09, ]
|
||||
, vec![0x7DAA, 0x0A, ]
|
||||
, vec![0x789D, 0x0B, ]
|
||||
, vec![0x662F, 0x0C, ]
|
||||
, vec![0x6318, 0x0D, ]
|
||||
, vec![0x6C41, 0x0E, ]
|
||||
, vec![0x6976, 0x0F, ]
|
||||
, vec![0x1689, 0x10, ]
|
||||
, vec![0x13BE, 0x11, ]
|
||||
, vec![0x1CE7, 0x12, ]
|
||||
, vec![0x19D0, 0x13, ]
|
||||
, vec![0x0762, 0x14, ]
|
||||
, vec![0x0255, 0x15, ]
|
||||
, vec![0x0D0C, 0x16, ]
|
||||
, vec![0x083B, 0x17, ]
|
||||
, vec![0x355F, 0x18, ]
|
||||
, vec![0x3068, 0x19, ]
|
||||
, vec![0x3F31, 0x1A, ]
|
||||
, vec![0x3A06, 0x1B, ]
|
||||
, vec![0x24B4, 0x1C, ]
|
||||
, vec![0x2183, 0x1D, ]
|
||||
, vec![0x2EDA, 0x1E, ]
|
||||
, vec![0x2BED, 0x1F, ]
|
||||
, ]
|
||||
;
|
||||
struct FormatInformation {
|
||||
|
||||
let error_correction_level: ErrorCorrectionLevel;
|
||||
|
||||
let data_mask: i8;
|
||||
}
|
||||
|
||||
impl FormatInformation {
|
||||
|
||||
fn new( format_info: i32) -> FormatInformation {
|
||||
// Bits 3,4
|
||||
error_correction_level = ErrorCorrectionLevel::for_bits((format_info >> 3) & 0x03);
|
||||
// Bottom 3 bits
|
||||
data_mask = (format_info & 0x07) as i8;
|
||||
}
|
||||
|
||||
fn num_bits_differing( a: i32, b: i32) -> i32 {
|
||||
return Integer::bit_count(a ^ b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maskedFormatInfo1 format info indicator, with mask still applied
|
||||
* @param maskedFormatInfo2 second copy of same info; both are checked at the same time
|
||||
* to establish best match
|
||||
* @return information about the format it specifies, or {@code null}
|
||||
* if doesn't seem to match any known pattern
|
||||
*/
|
||||
fn decode_format_information( masked_format_info1: i32, masked_format_info2: i32) -> FormatInformation {
|
||||
let format_info: FormatInformation = ::do_decode_format_information(masked_format_info1, masked_format_info2);
|
||||
if format_info != null {
|
||||
return format_info;
|
||||
}
|
||||
// first
|
||||
return ::do_decode_format_information(masked_format_info1 ^ FORMAT_INFO_MASK_QR, masked_format_info2 ^ FORMAT_INFO_MASK_QR);
|
||||
}
|
||||
|
||||
fn do_decode_format_information( masked_format_info1: i32, masked_format_info2: i32) -> FormatInformation {
|
||||
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
||||
let best_difference: i32 = Integer::MAX_VALUE;
|
||||
let best_format_info: i32 = 0;
|
||||
for let decode_info: Vec<i32> in FORMAT_INFO_DECODE_LOOKUP {
|
||||
let target_info: i32 = decode_info[0];
|
||||
if target_info == masked_format_info1 || target_info == masked_format_info2 {
|
||||
// Found an exact match
|
||||
return FormatInformation::new(decode_info[1]);
|
||||
}
|
||||
let bits_difference: i32 = ::num_bits_differing(masked_format_info1, target_info);
|
||||
if bits_difference < best_difference {
|
||||
best_format_info = decode_info[1];
|
||||
best_difference = bits_difference;
|
||||
}
|
||||
if masked_format_info1 != masked_format_info2 {
|
||||
// also try the other option
|
||||
bits_difference = ::num_bits_differing(masked_format_info2, target_info);
|
||||
if bits_difference < best_difference {
|
||||
best_format_info = decode_info[1];
|
||||
best_difference = bits_difference;
|
||||
}
|
||||
}
|
||||
}
|
||||
// differing means we found a match
|
||||
if best_difference <= 3 {
|
||||
return FormatInformation::new(best_format_info);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn get_error_correction_level(&self) -> ErrorCorrectionLevel {
|
||||
return self.error_correction_level;
|
||||
}
|
||||
|
||||
fn get_data_mask(&self) -> i8 {
|
||||
return self.data_mask;
|
||||
}
|
||||
|
||||
pub fn hash_code(&self) -> i32 {
|
||||
return (self.error_correction_level.ordinal() << 3) | self.data_mask;
|
||||
}
|
||||
|
||||
pub fn equals(&self, o: &Object) -> bool {
|
||||
if !(o instanceof FormatInformation) {
|
||||
return false;
|
||||
}
|
||||
let other: FormatInformation = o as FormatInformation;
|
||||
return self.errorCorrectionLevel == other.errorCorrectionLevel && self.dataMask == other.dataMask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
|
||||
* data can be encoded to bits in the QR code standard.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub enum Mode {
|
||||
|
||||
// Not really a mode...
|
||||
TERMINATOR( : vec![i32; 3] = vec![0, 0, 0, ]
|
||||
, 0x00), NUMERIC( : vec![i32; 3] = vec![10, 12, 14, ]
|
||||
, 0x01), ALPHANUMERIC( : vec![i32; 3] = vec![9, 11, 13, ]
|
||||
, 0x02), // Not supported
|
||||
STRUCTURED_APPEND( : vec![i32; 3] = vec![0, 0, 0, ]
|
||||
, 0x03), BYTE( : vec![i32; 3] = vec![8, 16, 16, ]
|
||||
, 0x04), // character counts don't apply
|
||||
ECI( : vec![i32; 3] = vec![0, 0, 0, ]
|
||||
, 0x07), KANJI( : vec![i32; 3] = vec![8, 10, 12, ]
|
||||
, 0x08), FNC1_FIRST_POSITION( : vec![i32; 3] = vec![0, 0, 0, ]
|
||||
, 0x05), FNC1_SECOND_POSITION( : vec![i32; 3] = vec![0, 0, 0, ]
|
||||
, 0x09), /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
|
||||
HANZI( : vec![i32; 3] = vec![8, 10, 12, ]
|
||||
, 0x0D);
|
||||
|
||||
let character_count_bits_for_versions: Vec<i32>;
|
||||
|
||||
let bits: i32;
|
||||
|
||||
fn new( character_count_bits_for_versions: &Vec<i32>, bits: i32) -> Mode {
|
||||
let .characterCountBitsForVersions = character_count_bits_for_versions;
|
||||
let .bits = bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bits four bits encoding a QR Code data mode
|
||||
* @return Mode encoded by these bits
|
||||
* @throws IllegalArgumentException if bits do not correspond to a known mode
|
||||
*/
|
||||
pub fn for_bits( bits: i32) -> Mode {
|
||||
match bits {
|
||||
0x0 =>
|
||||
{
|
||||
return TERMINATOR;
|
||||
}
|
||||
0x1 =>
|
||||
{
|
||||
return NUMERIC;
|
||||
}
|
||||
0x2 =>
|
||||
{
|
||||
return ALPHANUMERIC;
|
||||
}
|
||||
0x3 =>
|
||||
{
|
||||
return STRUCTURED_APPEND;
|
||||
}
|
||||
0x4 =>
|
||||
{
|
||||
return BYTE;
|
||||
}
|
||||
0x5 =>
|
||||
{
|
||||
return FNC1_FIRST_POSITION;
|
||||
}
|
||||
0x7 =>
|
||||
{
|
||||
return ECI;
|
||||
}
|
||||
0x8 =>
|
||||
{
|
||||
return KANJI;
|
||||
}
|
||||
0x9 =>
|
||||
{
|
||||
return FNC1_SECOND_POSITION;
|
||||
}
|
||||
0xD =>
|
||||
{
|
||||
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
|
||||
return HANZI;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param version version in question
|
||||
* @return number of bits used, in this QR Code symbol {@link Version}, to encode the
|
||||
* count of characters that will follow encoded in this Mode
|
||||
*/
|
||||
pub fn get_character_count_bits(&self, version: &Version) -> i32 {
|
||||
let number: i32 = version.get_version_number();
|
||||
let mut offset: i32;
|
||||
if number <= 9 {
|
||||
offset = 0;
|
||||
} else if number <= 26 {
|
||||
offset = 1;
|
||||
} else {
|
||||
offset = 2;
|
||||
}
|
||||
return self.character_count_bits_for_versions[offset];
|
||||
}
|
||||
|
||||
pub fn get_bits(&self) -> i32 {
|
||||
return self.bits;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
|
||||
* decoding caller. Callers are expected to process this.
|
||||
*
|
||||
* @see com.google.zxing.common.DecoderResult#getOther()
|
||||
*/
|
||||
pub struct QRCodeDecoderMetaData {
|
||||
|
||||
let mirrored: bool;
|
||||
}
|
||||
|
||||
impl QRCodeDecoderMetaData {
|
||||
|
||||
fn new( mirrored: bool) -> QRCodeDecoderMetaData {
|
||||
let .mirrored = mirrored;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the QR Code was mirrored.
|
||||
*/
|
||||
pub fn is_mirrored(&self) -> bool {
|
||||
return self.mirrored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the result points' order correction due to mirroring.
|
||||
*
|
||||
* @param points Array of points to apply mirror correction to.
|
||||
*/
|
||||
pub fn apply_mirrored_correction(&self, points: &Vec<ResultPoint>) {
|
||||
if !self.mirrored || points == null || points.len() < 3 {
|
||||
return;
|
||||
}
|
||||
let bottom_left: ResultPoint = points[0];
|
||||
points[0] = points[2];
|
||||
points[2] = bottom_left;
|
||||
// No need to 'fix' top-left and alignment pattern.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::decoder;
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006 Annex D
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006 Annex D.
|
||||
* Element i represents the raw version bits that specify version i + 7
|
||||
*/
|
||||
const VERSION_DECODE_INFO: vec![Vec<i32>; 34] = vec![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, ]
|
||||
;
|
||||
|
||||
const VERSIONS: Vec<Version> = ::build_versions();
|
||||
pub struct Version {
|
||||
|
||||
let version_number: i32;
|
||||
|
||||
let alignment_pattern_centers: Vec<i32>;
|
||||
|
||||
let ec_blocks: Vec<ECBlocks>;
|
||||
|
||||
let total_codewords: i32;
|
||||
}
|
||||
|
||||
impl Version {
|
||||
|
||||
fn new( version_number: i32, alignment_pattern_centers: &Vec<i32>, ec_blocks: &ECBlocks) -> Version {
|
||||
let .versionNumber = version_number;
|
||||
let .alignmentPatternCenters = alignment_pattern_centers;
|
||||
let .ecBlocks = ec_blocks;
|
||||
let mut total: i32 = 0;
|
||||
let ec_codewords: i32 = ec_blocks[0].get_e_c_codewords_per_block();
|
||||
let ecb_array: Vec<ECB> = ec_blocks[0].get_e_c_blocks();
|
||||
for let ec_block: ECB in ecb_array {
|
||||
total += ec_block.get_count() * (ec_block.get_data_codewords() + ec_codewords);
|
||||
}
|
||||
let .totalCodewords = total;
|
||||
}
|
||||
|
||||
pub fn get_version_number(&self) -> i32 {
|
||||
return self.version_number;
|
||||
}
|
||||
|
||||
pub fn get_alignment_pattern_centers(&self) -> Vec<i32> {
|
||||
return self.alignment_pattern_centers;
|
||||
}
|
||||
|
||||
pub fn get_total_codewords(&self) -> i32 {
|
||||
return self.total_codewords;
|
||||
}
|
||||
|
||||
pub fn get_dimension_for_version(&self) -> i32 {
|
||||
return 17 + 4 * self.version_number;
|
||||
}
|
||||
|
||||
pub fn get_e_c_blocks_for_level(&self, ec_level: &ErrorCorrectionLevel) -> ECBlocks {
|
||||
return self.ec_blocks[ec_level.ordinal()];
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Deduces version information purely from QR Code dimensions.</p>
|
||||
*
|
||||
* @param dimension dimension in modules
|
||||
* @return Version for a QR Code of that dimension
|
||||
* @throws FormatException if dimension is not 1 mod 4
|
||||
*/
|
||||
pub fn get_provisional_version_for_dimension( dimension: i32) -> /* throws FormatException */Result<Version, Rc<Exception>> {
|
||||
if dimension % 4 != 1 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return Ok(::get_version_for_number((dimension - 17) / 4));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &IllegalArgumentException) {
|
||||
throw FormatException::get_format_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn get_version_for_number( version_number: i32) -> Version {
|
||||
if version_number < 1 || version_number > 40 {
|
||||
throw IllegalArgumentException::new();
|
||||
}
|
||||
return VERSIONS[version_number - 1];
|
||||
}
|
||||
|
||||
fn decode_version_information( version_bits: i32) -> Version {
|
||||
let best_difference: i32 = Integer::MAX_VALUE;
|
||||
let best_version: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < VERSION_DECODE_INFO.len() {
|
||||
{
|
||||
let target_version: i32 = VERSION_DECODE_INFO[i];
|
||||
// Do the version info bits match exactly? done.
|
||||
if target_version == version_bits {
|
||||
return ::get_version_for_number(i + 7);
|
||||
}
|
||||
// Otherwise see if this is the closest to a real version info bit string
|
||||
// we have seen so far
|
||||
let bits_difference: i32 = FormatInformation::num_bits_differing(version_bits, target_version);
|
||||
if bits_difference < best_difference {
|
||||
best_version = i + 7;
|
||||
best_difference = bits_difference;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// differ in less than 8 bits.
|
||||
if best_difference <= 3 {
|
||||
return ::get_version_for_number(best_version);
|
||||
}
|
||||
// If we didn't find a close enough match, fail
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006 Annex E
|
||||
*/
|
||||
fn build_function_pattern(&self) -> BitMatrix {
|
||||
let dimension: i32 = self.get_dimension_for_version();
|
||||
let bit_matrix: BitMatrix = BitMatrix::new(dimension);
|
||||
// Top left finder pattern + separator + format
|
||||
bit_matrix.set_region(0, 0, 9, 9);
|
||||
// Top right finder pattern + separator + format
|
||||
bit_matrix.set_region(dimension - 8, 0, 8, 9);
|
||||
// Bottom left finder pattern + separator + format
|
||||
bit_matrix.set_region(0, dimension - 8, 9, 8);
|
||||
// Alignment patterns
|
||||
let max: i32 = self.alignment_pattern_centers.len();
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < max {
|
||||
{
|
||||
let i: i32 = self.alignment_pattern_centers[x] - 2;
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < max {
|
||||
{
|
||||
if (x != 0 || (y != 0 && y != max - 1)) && (x != max - 1 || y != 0) {
|
||||
bit_matrix.set_region(self.alignment_pattern_centers[y] - 2, i, 5, 5);
|
||||
}
|
||||
// else no o alignment patterns near the three finder patterns
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical timing pattern
|
||||
bit_matrix.set_region(6, 9, 1, dimension - 17);
|
||||
// Horizontal timing pattern
|
||||
bit_matrix.set_region(9, 6, dimension - 17, 1);
|
||||
if self.version_number > 6 {
|
||||
// Version info, top right
|
||||
bit_matrix.set_region(dimension - 11, 0, 3, 6);
|
||||
// Version info, bottom left
|
||||
bit_matrix.set_region(0, dimension - 11, 6, 3);
|
||||
}
|
||||
return bit_matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
|
||||
* use blocks of differing sizes within one version, so, this encapsulates the parameters for
|
||||
* each set of blocks. It also holds the number of error-correction codewords per block since it
|
||||
* will be the same across all blocks within one version.</p>
|
||||
*/
|
||||
pub struct ECBlocks {
|
||||
|
||||
let ec_codewords_per_block: i32;
|
||||
|
||||
let ec_blocks: Vec<ECB>;
|
||||
}
|
||||
|
||||
impl ECBlocks {
|
||||
|
||||
fn new( ec_codewords_per_block: i32, ec_blocks: &ECB) -> ECBlocks {
|
||||
let .ecCodewordsPerBlock = ec_codewords_per_block;
|
||||
let .ecBlocks = ec_blocks;
|
||||
}
|
||||
|
||||
pub fn get_e_c_codewords_per_block(&self) -> i32 {
|
||||
return self.ec_codewords_per_block;
|
||||
}
|
||||
|
||||
pub fn get_num_blocks(&self) -> i32 {
|
||||
let mut total: i32 = 0;
|
||||
for let ec_block: ECB in self.ec_blocks {
|
||||
total += ec_block.get_count();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
pub fn get_total_e_c_codewords(&self) -> i32 {
|
||||
return self.ec_codewords_per_block * self.get_num_blocks();
|
||||
}
|
||||
|
||||
pub fn get_e_c_blocks(&self) -> Vec<ECB> {
|
||||
return self.ec_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the parameters for one error-correction block in one symbol version.
|
||||
* This includes the number of data codewords, and the number of times a block with these
|
||||
* parameters is used consecutively in the QR code version's format.</p>
|
||||
*/
|
||||
pub struct ECB {
|
||||
|
||||
let count: i32;
|
||||
|
||||
let data_codewords: i32;
|
||||
}
|
||||
|
||||
impl ECB {
|
||||
|
||||
fn new( count: i32, data_codewords: i32) -> ECB {
|
||||
let .count = count;
|
||||
let .dataCodewords = data_codewords;
|
||||
}
|
||||
|
||||
pub fn get_count(&self) -> i32 {
|
||||
return self.count;
|
||||
}
|
||||
|
||||
pub fn get_data_codewords(&self) -> i32 {
|
||||
return self.data_codewords;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return String::value_of(self.version_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006 6.5.1 Table 9
|
||||
*/
|
||||
fn build_versions() -> Vec<Version> {
|
||||
return : vec![Version; 40] = vec![Version::new(1, , ECBlocks::new(7, ECB::new(1, 19)), ECBlocks::new(10, ECB::new(1, 16)), ECBlocks::new(13, ECB::new(1, 13)), ECBlocks::new(17, ECB::new(1, 9))), Version::new(2, : vec![i32; 2] = vec![6, 18, ]
|
||||
, ECBlocks::new(10, ECB::new(1, 34)), ECBlocks::new(16, ECB::new(1, 28)), ECBlocks::new(22, ECB::new(1, 22)), ECBlocks::new(28, ECB::new(1, 16))), Version::new(3, : vec![i32; 2] = vec![6, 22, ]
|
||||
, ECBlocks::new(15, ECB::new(1, 55)), ECBlocks::new(26, ECB::new(1, 44)), ECBlocks::new(18, ECB::new(2, 17)), ECBlocks::new(22, ECB::new(2, 13))), Version::new(4, : vec![i32; 2] = vec![6, 26, ]
|
||||
, ECBlocks::new(20, ECB::new(1, 80)), ECBlocks::new(18, ECB::new(2, 32)), ECBlocks::new(26, ECB::new(2, 24)), ECBlocks::new(16, ECB::new(4, 9))), Version::new(5, : vec![i32; 2] = vec![6, 30, ]
|
||||
, ECBlocks::new(26, ECB::new(1, 108)), ECBlocks::new(24, ECB::new(2, 43)), ECBlocks::new(18, ECB::new(2, 15), ECB::new(2, 16)), ECBlocks::new(22, ECB::new(2, 11), ECB::new(2, 12))), Version::new(6, : vec![i32; 2] = vec![6, 34, ]
|
||||
, ECBlocks::new(18, ECB::new(2, 68)), ECBlocks::new(16, ECB::new(4, 27)), ECBlocks::new(24, ECB::new(4, 19)), ECBlocks::new(28, ECB::new(4, 15))), Version::new(7, : vec![i32; 3] = vec![6, 22, 38, ]
|
||||
, ECBlocks::new(20, ECB::new(2, 78)), ECBlocks::new(18, ECB::new(4, 31)), ECBlocks::new(18, ECB::new(2, 14), ECB::new(4, 15)), ECBlocks::new(26, ECB::new(4, 13), ECB::new(1, 14))), Version::new(8, : vec![i32; 3] = vec![6, 24, 42, ]
|
||||
, ECBlocks::new(24, ECB::new(2, 97)), ECBlocks::new(22, ECB::new(2, 38), ECB::new(2, 39)), ECBlocks::new(22, ECB::new(4, 18), ECB::new(2, 19)), ECBlocks::new(26, ECB::new(4, 14), ECB::new(2, 15))), Version::new(9, : vec![i32; 3] = vec![6, 26, 46, ]
|
||||
, ECBlocks::new(30, ECB::new(2, 116)), ECBlocks::new(22, ECB::new(3, 36), ECB::new(2, 37)), ECBlocks::new(20, ECB::new(4, 16), ECB::new(4, 17)), ECBlocks::new(24, ECB::new(4, 12), ECB::new(4, 13))), Version::new(10, : vec![i32; 3] = vec![6, 28, 50, ]
|
||||
, ECBlocks::new(18, ECB::new(2, 68), ECB::new(2, 69)), ECBlocks::new(26, ECB::new(4, 43), ECB::new(1, 44)), ECBlocks::new(24, ECB::new(6, 19), ECB::new(2, 20)), ECBlocks::new(28, ECB::new(6, 15), ECB::new(2, 16))), Version::new(11, : vec![i32; 3] = vec![6, 30, 54, ]
|
||||
, ECBlocks::new(20, ECB::new(4, 81)), ECBlocks::new(30, ECB::new(1, 50), ECB::new(4, 51)), ECBlocks::new(28, ECB::new(4, 22), ECB::new(4, 23)), ECBlocks::new(24, ECB::new(3, 12), ECB::new(8, 13))), Version::new(12, : vec![i32; 3] = vec![6, 32, 58, ]
|
||||
, ECBlocks::new(24, ECB::new(2, 92), ECB::new(2, 93)), ECBlocks::new(22, ECB::new(6, 36), ECB::new(2, 37)), ECBlocks::new(26, ECB::new(4, 20), ECB::new(6, 21)), ECBlocks::new(28, ECB::new(7, 14), ECB::new(4, 15))), Version::new(13, : vec![i32; 3] = vec![6, 34, 62, ]
|
||||
, ECBlocks::new(26, ECB::new(4, 107)), ECBlocks::new(22, ECB::new(8, 37), ECB::new(1, 38)), ECBlocks::new(24, ECB::new(8, 20), ECB::new(4, 21)), ECBlocks::new(22, ECB::new(12, 11), ECB::new(4, 12))), Version::new(14, : vec![i32; 4] = vec![6, 26, 46, 66, ]
|
||||
, ECBlocks::new(30, ECB::new(3, 115), ECB::new(1, 116)), ECBlocks::new(24, ECB::new(4, 40), ECB::new(5, 41)), ECBlocks::new(20, ECB::new(11, 16), ECB::new(5, 17)), ECBlocks::new(24, ECB::new(11, 12), ECB::new(5, 13))), Version::new(15, : vec![i32; 4] = vec![6, 26, 48, 70, ]
|
||||
, ECBlocks::new(22, ECB::new(5, 87), ECB::new(1, 88)), ECBlocks::new(24, ECB::new(5, 41), ECB::new(5, 42)), ECBlocks::new(30, ECB::new(5, 24), ECB::new(7, 25)), ECBlocks::new(24, ECB::new(11, 12), ECB::new(7, 13))), Version::new(16, : vec![i32; 4] = vec![6, 26, 50, 74, ]
|
||||
, ECBlocks::new(24, ECB::new(5, 98), ECB::new(1, 99)), ECBlocks::new(28, ECB::new(7, 45), ECB::new(3, 46)), ECBlocks::new(24, ECB::new(15, 19), ECB::new(2, 20)), ECBlocks::new(30, ECB::new(3, 15), ECB::new(13, 16))), Version::new(17, : vec![i32; 4] = vec![6, 30, 54, 78, ]
|
||||
, ECBlocks::new(28, ECB::new(1, 107), ECB::new(5, 108)), ECBlocks::new(28, ECB::new(10, 46), ECB::new(1, 47)), ECBlocks::new(28, ECB::new(1, 22), ECB::new(15, 23)), ECBlocks::new(28, ECB::new(2, 14), ECB::new(17, 15))), Version::new(18, : vec![i32; 4] = vec![6, 30, 56, 82, ]
|
||||
, ECBlocks::new(30, ECB::new(5, 120), ECB::new(1, 121)), ECBlocks::new(26, ECB::new(9, 43), ECB::new(4, 44)), ECBlocks::new(28, ECB::new(17, 22), ECB::new(1, 23)), ECBlocks::new(28, ECB::new(2, 14), ECB::new(19, 15))), Version::new(19, : vec![i32; 4] = vec![6, 30, 58, 86, ]
|
||||
, ECBlocks::new(28, ECB::new(3, 113), ECB::new(4, 114)), ECBlocks::new(26, ECB::new(3, 44), ECB::new(11, 45)), ECBlocks::new(26, ECB::new(17, 21), ECB::new(4, 22)), ECBlocks::new(26, ECB::new(9, 13), ECB::new(16, 14))), Version::new(20, : vec![i32; 4] = vec![6, 34, 62, 90, ]
|
||||
, ECBlocks::new(28, ECB::new(3, 107), ECB::new(5, 108)), ECBlocks::new(26, ECB::new(3, 41), ECB::new(13, 42)), ECBlocks::new(30, ECB::new(15, 24), ECB::new(5, 25)), ECBlocks::new(28, ECB::new(15, 15), ECB::new(10, 16))), Version::new(21, : vec![i32; 5] = vec![6, 28, 50, 72, 94, ]
|
||||
, ECBlocks::new(28, ECB::new(4, 116), ECB::new(4, 117)), ECBlocks::new(26, ECB::new(17, 42)), ECBlocks::new(28, ECB::new(17, 22), ECB::new(6, 23)), ECBlocks::new(30, ECB::new(19, 16), ECB::new(6, 17))), Version::new(22, : vec![i32; 5] = vec![6, 26, 50, 74, 98, ]
|
||||
, ECBlocks::new(28, ECB::new(2, 111), ECB::new(7, 112)), ECBlocks::new(28, ECB::new(17, 46)), ECBlocks::new(30, ECB::new(7, 24), ECB::new(16, 25)), ECBlocks::new(24, ECB::new(34, 13))), Version::new(23, : vec![i32; 5] = vec![6, 30, 54, 78, 102, ]
|
||||
, ECBlocks::new(30, ECB::new(4, 121), ECB::new(5, 122)), ECBlocks::new(28, ECB::new(4, 47), ECB::new(14, 48)), ECBlocks::new(30, ECB::new(11, 24), ECB::new(14, 25)), ECBlocks::new(30, ECB::new(16, 15), ECB::new(14, 16))), Version::new(24, : vec![i32; 5] = vec![6, 28, 54, 80, 106, ]
|
||||
, ECBlocks::new(30, ECB::new(6, 117), ECB::new(4, 118)), ECBlocks::new(28, ECB::new(6, 45), ECB::new(14, 46)), ECBlocks::new(30, ECB::new(11, 24), ECB::new(16, 25)), ECBlocks::new(30, ECB::new(30, 16), ECB::new(2, 17))), Version::new(25, : vec![i32; 5] = vec![6, 32, 58, 84, 110, ]
|
||||
, ECBlocks::new(26, ECB::new(8, 106), ECB::new(4, 107)), ECBlocks::new(28, ECB::new(8, 47), ECB::new(13, 48)), ECBlocks::new(30, ECB::new(7, 24), ECB::new(22, 25)), ECBlocks::new(30, ECB::new(22, 15), ECB::new(13, 16))), Version::new(26, : vec![i32; 5] = vec![6, 30, 58, 86, 114, ]
|
||||
, ECBlocks::new(28, ECB::new(10, 114), ECB::new(2, 115)), ECBlocks::new(28, ECB::new(19, 46), ECB::new(4, 47)), ECBlocks::new(28, ECB::new(28, 22), ECB::new(6, 23)), ECBlocks::new(30, ECB::new(33, 16), ECB::new(4, 17))), Version::new(27, : vec![i32; 5] = vec![6, 34, 62, 90, 118, ]
|
||||
, ECBlocks::new(30, ECB::new(8, 122), ECB::new(4, 123)), ECBlocks::new(28, ECB::new(22, 45), ECB::new(3, 46)), ECBlocks::new(30, ECB::new(8, 23), ECB::new(26, 24)), ECBlocks::new(30, ECB::new(12, 15), ECB::new(28, 16))), Version::new(28, : vec![i32; 6] = vec![6, 26, 50, 74, 98, 122, ]
|
||||
, ECBlocks::new(30, ECB::new(3, 117), ECB::new(10, 118)), ECBlocks::new(28, ECB::new(3, 45), ECB::new(23, 46)), ECBlocks::new(30, ECB::new(4, 24), ECB::new(31, 25)), ECBlocks::new(30, ECB::new(11, 15), ECB::new(31, 16))), Version::new(29, : vec![i32; 6] = vec![6, 30, 54, 78, 102, 126, ]
|
||||
, ECBlocks::new(30, ECB::new(7, 116), ECB::new(7, 117)), ECBlocks::new(28, ECB::new(21, 45), ECB::new(7, 46)), ECBlocks::new(30, ECB::new(1, 23), ECB::new(37, 24)), ECBlocks::new(30, ECB::new(19, 15), ECB::new(26, 16))), Version::new(30, : vec![i32; 6] = vec![6, 26, 52, 78, 104, 130, ]
|
||||
, ECBlocks::new(30, ECB::new(5, 115), ECB::new(10, 116)), ECBlocks::new(28, ECB::new(19, 47), ECB::new(10, 48)), ECBlocks::new(30, ECB::new(15, 24), ECB::new(25, 25)), ECBlocks::new(30, ECB::new(23, 15), ECB::new(25, 16))), Version::new(31, : vec![i32; 6] = vec![6, 30, 56, 82, 108, 134, ]
|
||||
, ECBlocks::new(30, ECB::new(13, 115), ECB::new(3, 116)), ECBlocks::new(28, ECB::new(2, 46), ECB::new(29, 47)), ECBlocks::new(30, ECB::new(42, 24), ECB::new(1, 25)), ECBlocks::new(30, ECB::new(23, 15), ECB::new(28, 16))), Version::new(32, : vec![i32; 6] = vec![6, 34, 60, 86, 112, 138, ]
|
||||
, ECBlocks::new(30, ECB::new(17, 115)), ECBlocks::new(28, ECB::new(10, 46), ECB::new(23, 47)), ECBlocks::new(30, ECB::new(10, 24), ECB::new(35, 25)), ECBlocks::new(30, ECB::new(19, 15), ECB::new(35, 16))), Version::new(33, : vec![i32; 6] = vec![6, 30, 58, 86, 114, 142, ]
|
||||
, ECBlocks::new(30, ECB::new(17, 115), ECB::new(1, 116)), ECBlocks::new(28, ECB::new(14, 46), ECB::new(21, 47)), ECBlocks::new(30, ECB::new(29, 24), ECB::new(19, 25)), ECBlocks::new(30, ECB::new(11, 15), ECB::new(46, 16))), Version::new(34, : vec![i32; 6] = vec![6, 34, 62, 90, 118, 146, ]
|
||||
, ECBlocks::new(30, ECB::new(13, 115), ECB::new(6, 116)), ECBlocks::new(28, ECB::new(14, 46), ECB::new(23, 47)), ECBlocks::new(30, ECB::new(44, 24), ECB::new(7, 25)), ECBlocks::new(30, ECB::new(59, 16), ECB::new(1, 17))), Version::new(35, : vec![i32; 7] = vec![6, 30, 54, 78, 102, 126, 150, ]
|
||||
, ECBlocks::new(30, ECB::new(12, 121), ECB::new(7, 122)), ECBlocks::new(28, ECB::new(12, 47), ECB::new(26, 48)), ECBlocks::new(30, ECB::new(39, 24), ECB::new(14, 25)), ECBlocks::new(30, ECB::new(22, 15), ECB::new(41, 16))), Version::new(36, : vec![i32; 7] = vec![6, 24, 50, 76, 102, 128, 154, ]
|
||||
, ECBlocks::new(30, ECB::new(6, 121), ECB::new(14, 122)), ECBlocks::new(28, ECB::new(6, 47), ECB::new(34, 48)), ECBlocks::new(30, ECB::new(46, 24), ECB::new(10, 25)), ECBlocks::new(30, ECB::new(2, 15), ECB::new(64, 16))), Version::new(37, : vec![i32; 7] = vec![6, 28, 54, 80, 106, 132, 158, ]
|
||||
, ECBlocks::new(30, ECB::new(17, 122), ECB::new(4, 123)), ECBlocks::new(28, ECB::new(29, 46), ECB::new(14, 47)), ECBlocks::new(30, ECB::new(49, 24), ECB::new(10, 25)), ECBlocks::new(30, ECB::new(24, 15), ECB::new(46, 16))), Version::new(38, : vec![i32; 7] = vec![6, 32, 58, 84, 110, 136, 162, ]
|
||||
, ECBlocks::new(30, ECB::new(4, 122), ECB::new(18, 123)), ECBlocks::new(28, ECB::new(13, 46), ECB::new(32, 47)), ECBlocks::new(30, ECB::new(48, 24), ECB::new(14, 25)), ECBlocks::new(30, ECB::new(42, 15), ECB::new(32, 16))), Version::new(39, : vec![i32; 7] = vec![6, 26, 54, 82, 110, 138, 166, ]
|
||||
, ECBlocks::new(30, ECB::new(20, 117), ECB::new(4, 118)), ECBlocks::new(28, ECB::new(40, 47), ECB::new(7, 48)), ECBlocks::new(30, ECB::new(43, 24), ECB::new(22, 25)), ECBlocks::new(30, ECB::new(10, 15), ECB::new(67, 16))), Version::new(40, : vec![i32; 7] = vec![6, 30, 58, 86, 114, 142, 170, ]
|
||||
, ECBlocks::new(30, ECB::new(19, 118), ECB::new(6, 119)), ECBlocks::new(28, ECB::new(18, 47), ECB::new(31, 48)), ECBlocks::new(30, ECB::new(34, 24), ECB::new(34, 25)), ECBlocks::new(30, ECB::new(20, 15), ECB::new(61, 16))), ]
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::detector;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates an alignment pattern, which are the smaller square patterns found in
|
||||
* all but the simplest QR Codes.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct AlignmentPattern {
|
||||
super: ResultPoint;
|
||||
|
||||
let estimated_module_size: f32;
|
||||
}
|
||||
|
||||
impl AlignmentPattern {
|
||||
|
||||
fn new( pos_x: f32, pos_y: f32, estimated_module_size: f32) -> AlignmentPattern {
|
||||
super(pos_x, pos_y);
|
||||
let .estimatedModuleSize = estimated_module_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Determines if this alignment pattern "about equals" an alignment pattern at the stated
|
||||
* position and size -- meaning, it is at nearly the same center with nearly the same size.</p>
|
||||
*/
|
||||
fn about_equals(&self, module_size: f32, i: f32, j: f32) -> bool {
|
||||
if Math::abs(i - get_y()) <= module_size && Math::abs(j - get_x()) <= module_size {
|
||||
let module_size_diff: f32 = Math::abs(module_size - self.estimated_module_size);
|
||||
return module_size_diff <= 1.0f || module_size_diff <= self.estimated_module_size;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this object's current estimate of a finder pattern position and module size
|
||||
* with a new estimate. It returns a new {@code FinderPattern} containing an average of the two.
|
||||
*/
|
||||
fn combine_estimate(&self, i: f32, j: f32, new_module_size: f32) -> AlignmentPattern {
|
||||
let combined_x: f32 = (get_x() + j) / 2.0f;
|
||||
let combined_y: f32 = (get_y() + i) / 2.0f;
|
||||
let combined_module_size: f32 = (self.estimated_module_size + new_module_size) / 2.0f;
|
||||
return AlignmentPattern::new(combined_x, combined_y, combined_module_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::detector;
|
||||
|
||||
/**
|
||||
* <p>This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder
|
||||
* patterns but are smaller and appear at regular intervals throughout the image.</p>
|
||||
*
|
||||
* <p>At the moment this only looks for the bottom-right alignment pattern.</p>
|
||||
*
|
||||
* <p>This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied,
|
||||
* pasted and stripped down here for maximum performance but does unfortunately duplicate
|
||||
* some code.</p>
|
||||
*
|
||||
* <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
struct AlignmentPatternFinder {
|
||||
|
||||
let image: BitMatrix;
|
||||
|
||||
let possible_centers: List<AlignmentPattern>;
|
||||
|
||||
let start_x: i32;
|
||||
|
||||
let start_y: i32;
|
||||
|
||||
let width: i32;
|
||||
|
||||
let height: i32;
|
||||
|
||||
let module_size: f32;
|
||||
|
||||
let cross_check_state_count: Vec<i32>;
|
||||
|
||||
let result_point_callback: ResultPointCallback;
|
||||
}
|
||||
|
||||
impl AlignmentPatternFinder {
|
||||
|
||||
/**
|
||||
* <p>Creates a finder that will look in a portion of the whole image.</p>
|
||||
*
|
||||
* @param image image to search
|
||||
* @param startX left column from which to start searching
|
||||
* @param startY top row from which to start searching
|
||||
* @param width width of region to search
|
||||
* @param height height of region to search
|
||||
* @param moduleSize estimated module size so far
|
||||
*/
|
||||
fn new( image: &BitMatrix, start_x: i32, start_y: i32, width: i32, height: i32, module_size: f32, result_point_callback: &ResultPointCallback) -> AlignmentPatternFinder {
|
||||
let .image = image;
|
||||
let .possibleCenters = ArrayList<>::new(5);
|
||||
let .startX = start_x;
|
||||
let .startY = start_y;
|
||||
let .width = width;
|
||||
let .height = height;
|
||||
let .moduleSize = module_size;
|
||||
let .crossCheckStateCount = : [i32; 3] = [0; 3];
|
||||
let .resultPointCallback = result_point_callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since
|
||||
* it's pretty performance-critical and so is written to be fast foremost.</p>
|
||||
*
|
||||
* @return {@link AlignmentPattern} if found
|
||||
* @throws NotFoundException if not found
|
||||
*/
|
||||
fn find(&self) -> /* throws NotFoundException */Result<AlignmentPattern, Rc<Exception>> {
|
||||
let start_x: i32 = self.startX;
|
||||
let height: i32 = self.height;
|
||||
let max_j: i32 = start_x + self.width;
|
||||
let middle_i: i32 = self.start_y + (height / 2);
|
||||
// We are looking for black/white/black modules in 1:1:1 ratio;
|
||||
// this tracks the number of black/white/black modules seen so far
|
||||
let state_count: [i32; 3] = [0; 3];
|
||||
{
|
||||
let i_gen: i32 = 0;
|
||||
while i_gen < height {
|
||||
{
|
||||
// Search from middle outwards
|
||||
let i: i32 = middle_i + ( if (i_gen & 0x01) == 0 { (i_gen + 1) / 2 } else { -((i_gen + 1) / 2) });
|
||||
state_count[0] = 0;
|
||||
state_count[1] = 0;
|
||||
state_count[2] = 0;
|
||||
let mut j: i32 = start_x;
|
||||
// white run continued to the left of the start point
|
||||
while j < max_j && !self.image.get(j, i) {
|
||||
j += 1;
|
||||
}
|
||||
let current_state: i32 = 0;
|
||||
while j < max_j {
|
||||
if self.image.get(j, i) {
|
||||
// Black pixel
|
||||
if current_state == 1 {
|
||||
// Counting black pixels
|
||||
state_count[1] += 1;
|
||||
} else {
|
||||
// Counting white pixels
|
||||
if current_state == 2 {
|
||||
// A winner?
|
||||
if self.found_pattern_cross(&state_count) {
|
||||
// Yes
|
||||
let confirmed: AlignmentPattern = self.handle_possible_center(&state_count, i, j);
|
||||
if confirmed != null {
|
||||
return Ok(confirmed);
|
||||
}
|
||||
}
|
||||
state_count[0] = state_count[2];
|
||||
state_count[1] = 1;
|
||||
state_count[2] = 0;
|
||||
current_state = 1;
|
||||
} else {
|
||||
state_count[current_state += 1] += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// White pixel
|
||||
if current_state == 1 {
|
||||
// Counting black pixels
|
||||
current_state += 1;
|
||||
}
|
||||
state_count[current_state] += 1;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
if self.found_pattern_cross(&state_count) {
|
||||
let confirmed: AlignmentPattern = self.handle_possible_center(&state_count, i, max_j);
|
||||
if confirmed != null {
|
||||
return Ok(confirmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
i_gen += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// any guess at all, return it.
|
||||
if !self.possible_centers.is_empty() {
|
||||
return Ok(self.possible_centers.get(0));
|
||||
}
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a count of black/white/black pixels just seen and an end position,
|
||||
* figures the location of the center of this black/white/black run.
|
||||
*/
|
||||
fn center_from_end( state_count: &Vec<i32>, end: i32) -> f32 {
|
||||
return (end - state_count[2]) - state_count[1] / 2.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stateCount count of black/white/black pixels just read
|
||||
* @return true iff the proportions of the counts is close enough to the 1/1/1 ratios
|
||||
* used by alignment patterns to be considered a match
|
||||
*/
|
||||
fn found_pattern_cross(&self, state_count: &Vec<i32>) -> bool {
|
||||
let module_size: f32 = self.moduleSize;
|
||||
let max_variance: f32 = module_size / 2.0f;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 3 {
|
||||
{
|
||||
if Math::abs(module_size - state_count[i]) >= max_variance {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>After a horizontal scan finds a potential alignment pattern, this method
|
||||
* "cross-checks" by scanning down vertically through the center of the possible
|
||||
* alignment pattern to see if the same proportion is detected.</p>
|
||||
*
|
||||
* @param startI row where an alignment pattern was detected
|
||||
* @param centerJ center of the section that appears to cross an alignment pattern
|
||||
* @param maxCount maximum reasonable number of modules that should be
|
||||
* observed in any reading state, based on the results of the horizontal scan
|
||||
* @return vertical center of alignment pattern, or {@link Float#NaN} if not found
|
||||
*/
|
||||
fn cross_check_vertical(&self, start_i: i32, center_j: i32, max_count: i32, original_state_count_total: i32) -> f32 {
|
||||
let image: BitMatrix = self.image;
|
||||
let max_i: i32 = image.get_height();
|
||||
let state_count: Vec<i32> = self.cross_check_state_count;
|
||||
state_count[0] = 0;
|
||||
state_count[1] = 0;
|
||||
state_count[2] = 0;
|
||||
// Start counting up from center
|
||||
let mut i: i32 = start_i;
|
||||
while i >= 0 && image.get(center_j, i) && state_count[1] <= max_count {
|
||||
state_count[1] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
// If already too many modules in this state or ran off the edge:
|
||||
if i < 0 || state_count[1] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
while i >= 0 && !image.get(center_j, i) && state_count[0] <= max_count {
|
||||
state_count[0] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
if state_count[0] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
// Now also count down from center
|
||||
i = start_i + 1;
|
||||
while i < max_i && image.get(center_j, i) && state_count[1] <= max_count {
|
||||
state_count[1] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if i == max_i || state_count[1] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
while i < max_i && !image.get(center_j, i) && state_count[2] <= max_count {
|
||||
state_count[2] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[2] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
let state_count_total: i32 = state_count[0] + state_count[1] + state_count[2];
|
||||
if 5 * Math::abs(state_count_total - original_state_count_total) >= 2 * original_state_count_total {
|
||||
return Float::NaN;
|
||||
}
|
||||
return if self.found_pattern_cross(&state_count) { ::center_from_end(&state_count, i) } else { Float::NaN };
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This is called when a horizontal scan finds a possible alignment pattern. It will
|
||||
* cross check with a vertical scan, and if successful, will see if this pattern had been
|
||||
* found on a previous horizontal scan. If so, we consider it confirmed and conclude we have
|
||||
* found the alignment pattern.</p>
|
||||
*
|
||||
* @param stateCount reading state module counts from horizontal scan
|
||||
* @param i row where alignment pattern may be found
|
||||
* @param j end of possible alignment pattern in row
|
||||
* @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not
|
||||
*/
|
||||
fn handle_possible_center(&self, state_count: &Vec<i32>, i: i32, j: i32) -> AlignmentPattern {
|
||||
let state_count_total: i32 = state_count[0] + state_count[1] + state_count[2];
|
||||
let center_j: f32 = ::center_from_end(&state_count, j);
|
||||
let center_i: f32 = self.cross_check_vertical(i, center_j as i32, 2 * state_count[1], state_count_total);
|
||||
if !Float::is_na_n(center_i) {
|
||||
let estimated_module_size: f32 = (state_count[0] + state_count[1] + state_count[2]) / 3.0f;
|
||||
for let center: AlignmentPattern in self.possible_centers {
|
||||
// Look for about the same center and module size:
|
||||
if center.about_equals(estimated_module_size, center_i, center_j) {
|
||||
return center.combine_estimate(center_i, center_j, estimated_module_size);
|
||||
}
|
||||
}
|
||||
// Hadn't found this before; save it
|
||||
let point: AlignmentPattern = AlignmentPattern::new(center_j, center_i, estimated_module_size);
|
||||
self.possible_centers.add(point);
|
||||
if self.result_point_callback != null {
|
||||
self.result_point_callback.found_possible_result_point(point);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,342 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::detector;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates logic that can detect a QR Code in an image, even if the QR Code
|
||||
* is rotated or skewed, or partially obscured.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct Detector {
|
||||
|
||||
let image: BitMatrix;
|
||||
|
||||
let result_point_callback: ResultPointCallback;
|
||||
}
|
||||
|
||||
impl Detector {
|
||||
|
||||
pub fn new( image: &BitMatrix) -> Detector {
|
||||
let .image = image;
|
||||
}
|
||||
|
||||
pub fn get_image(&self) -> BitMatrix {
|
||||
return self.image;
|
||||
}
|
||||
|
||||
pub fn get_result_point_callback(&self) -> ResultPointCallback {
|
||||
return self.result_point_callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a QR Code in an image.</p>
|
||||
*
|
||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
||||
* @throws NotFoundException if QR Code cannot be found
|
||||
* @throws FormatException if a QR Code cannot be decoded
|
||||
*/
|
||||
pub fn detect(&self) -> /* throws NotFoundException, FormatException */Result<DetectorResult, Rc<Exception>> {
|
||||
return Ok(self.detect(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a QR Code in an image.</p>
|
||||
*
|
||||
* @param hints optional hints to detector
|
||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
||||
* @throws NotFoundException if QR Code cannot be found
|
||||
* @throws FormatException if a QR Code cannot be decoded
|
||||
*/
|
||||
pub fn detect(&self, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, FormatException */Result<DetectorResult, Rc<Exception>> {
|
||||
self.result_point_callback = if hints == null { null } else { hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback };
|
||||
let finder: FinderPatternFinder = FinderPatternFinder::new(self.image, self.result_point_callback);
|
||||
let info: FinderPatternInfo = finder.find(&hints);
|
||||
return Ok(self.process_finder_pattern_info(info));
|
||||
}
|
||||
|
||||
pub fn process_finder_pattern_info(&self, info: &FinderPatternInfo) -> /* throws NotFoundException, FormatException */Result<DetectorResult, Rc<Exception>> {
|
||||
let top_left: FinderPattern = info.get_top_left();
|
||||
let top_right: FinderPattern = info.get_top_right();
|
||||
let bottom_left: FinderPattern = info.get_bottom_left();
|
||||
let module_size: f32 = self.calculate_module_size(top_left, top_right, bottom_left);
|
||||
if module_size < 1.0f {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let dimension: i32 = ::compute_dimension(top_left, top_right, bottom_left, module_size);
|
||||
let provisional_version: Version = Version::get_provisional_version_for_dimension(dimension);
|
||||
let modules_between_f_p_centers: i32 = provisional_version.get_dimension_for_version() - 7;
|
||||
let alignment_pattern: AlignmentPattern = null;
|
||||
// Anything above version 1 has an alignment pattern
|
||||
if provisional_version.get_alignment_pattern_centers().len() > 0 {
|
||||
// Guess where a "bottom right" finder pattern would have been
|
||||
let bottom_right_x: f32 = top_right.get_x() - top_left.get_x() + bottom_left.get_x();
|
||||
let bottom_right_y: f32 = top_right.get_y() - top_left.get_y() + bottom_left.get_y();
|
||||
// Estimate that alignment pattern is closer by 3 modules
|
||||
// from "bottom right" to known top left location
|
||||
let correction_to_top_left: f32 = 1.0f - 3.0f / modules_between_f_p_centers;
|
||||
let est_alignment_x: i32 = (top_left.get_x() + correction_to_top_left * (bottom_right_x - top_left.get_x())) as i32;
|
||||
let est_alignment_y: i32 = (top_left.get_y() + correction_to_top_left * (bottom_right_y - top_left.get_y())) as i32;
|
||||
// Kind of arbitrary -- expand search radius before giving up
|
||||
{
|
||||
let mut i: i32 = 4;
|
||||
while i <= 16 {
|
||||
{
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
alignment_pattern = self.find_alignment_in_region(module_size, est_alignment_x, est_alignment_y, i);
|
||||
break;
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( re: &NotFoundException) {
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
i <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find alignment pattern... well try anyway without it
|
||||
}
|
||||
let transform: PerspectiveTransform = ::create_transform(top_left, top_right, bottom_left, alignment_pattern, dimension);
|
||||
let bits: BitMatrix = ::sample_grid(self.image, transform, dimension);
|
||||
let mut points: Vec<ResultPoint>;
|
||||
if alignment_pattern == null {
|
||||
points = : vec![ResultPoint; 3] = vec![bottom_left, top_left, top_right, ]
|
||||
;
|
||||
} else {
|
||||
points = : vec![ResultPoint; 4] = vec![bottom_left, top_left, top_right, alignment_pattern, ]
|
||||
;
|
||||
}
|
||||
return Ok(DetectorResult::new(bits, points));
|
||||
}
|
||||
|
||||
fn create_transform( top_left: &ResultPoint, top_right: &ResultPoint, bottom_left: &ResultPoint, alignment_pattern: &ResultPoint, dimension: i32) -> PerspectiveTransform {
|
||||
let dim_minus_three: f32 = dimension - 3.5f;
|
||||
let bottom_right_x: f32;
|
||||
let bottom_right_y: f32;
|
||||
let source_bottom_right_x: f32;
|
||||
let source_bottom_right_y: f32;
|
||||
if alignment_pattern != null {
|
||||
bottom_right_x = alignment_pattern.get_x();
|
||||
bottom_right_y = alignment_pattern.get_y();
|
||||
source_bottom_right_x = dim_minus_three - 3.0f;
|
||||
source_bottom_right_y = source_bottom_right_x;
|
||||
} else {
|
||||
// Don't have an alignment pattern, just make up the bottom-right point
|
||||
bottom_right_x = (top_right.get_x() - top_left.get_x()) + bottom_left.get_x();
|
||||
bottom_right_y = (top_right.get_y() - top_left.get_y()) + bottom_left.get_y();
|
||||
source_bottom_right_x = dim_minus_three;
|
||||
source_bottom_right_y = dim_minus_three;
|
||||
}
|
||||
return PerspectiveTransform::quadrilateral_to_quadrilateral(3.5f, 3.5f, dim_minus_three, 3.5f, source_bottom_right_x, source_bottom_right_y, 3.5f, dim_minus_three, &top_left.get_x(), &top_left.get_y(), &top_right.get_x(), &top_right.get_y(), bottom_right_x, bottom_right_y, &bottom_left.get_x(), &bottom_left.get_y());
|
||||
}
|
||||
|
||||
fn sample_grid( image: &BitMatrix, transform: &PerspectiveTransform, dimension: i32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let sampler: GridSampler = GridSampler::get_instance();
|
||||
return Ok(sampler.sample_grid(image, dimension, dimension, transform));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Computes the dimension (number of modules on a size) of the QR Code based on the position
|
||||
* of the finder patterns and estimated module size.</p>
|
||||
*/
|
||||
fn compute_dimension( top_left: &ResultPoint, top_right: &ResultPoint, bottom_left: &ResultPoint, module_size: f32) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
let tltr_centers_dimension: i32 = MathUtils::round(ResultPoint::distance(top_left, top_right) / module_size);
|
||||
let tlbl_centers_dimension: i32 = MathUtils::round(ResultPoint::distance(top_left, bottom_left) / module_size);
|
||||
let mut dimension: i32 = ((tltr_centers_dimension + tlbl_centers_dimension) / 2) + 7;
|
||||
match // mod 4
|
||||
dimension & 0x03 {
|
||||
0 =>
|
||||
{
|
||||
dimension += 1;
|
||||
break;
|
||||
}
|
||||
// 1? do nothing
|
||||
2 =>
|
||||
{
|
||||
dimension -= 1;
|
||||
break;
|
||||
}
|
||||
3 =>
|
||||
{
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
}
|
||||
return Ok(dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Computes an average estimated module size based on estimated derived from the positions
|
||||
* of the three finder patterns.</p>
|
||||
*
|
||||
* @param topLeft detected top-left finder pattern center
|
||||
* @param topRight detected top-right finder pattern center
|
||||
* @param bottomLeft detected bottom-left finder pattern center
|
||||
* @return estimated module size
|
||||
*/
|
||||
pub fn calculate_module_size(&self, top_left: &ResultPoint, top_right: &ResultPoint, bottom_left: &ResultPoint) -> f32 {
|
||||
// Take the average
|
||||
return (self.calculate_module_size_one_way(top_left, top_right) + self.calculate_module_size_one_way(top_left, bottom_left)) / 2.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Estimates module size based on two finder patterns -- it uses
|
||||
* {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the
|
||||
* width of each, measuring along the axis between their centers.</p>
|
||||
*/
|
||||
fn calculate_module_size_one_way(&self, pattern: &ResultPoint, other_pattern: &ResultPoint) -> f32 {
|
||||
let module_size_est1: f32 = self.size_of_black_white_black_run_both_ways(pattern.get_x() as i32, pattern.get_y() as i32, other_pattern.get_x() as i32, other_pattern.get_y() as i32);
|
||||
let module_size_est2: f32 = self.size_of_black_white_black_run_both_ways(other_pattern.get_x() as i32, other_pattern.get_y() as i32, pattern.get_x() as i32, pattern.get_y() as i32);
|
||||
if Float::is_na_n(module_size_est1) {
|
||||
return module_size_est2 / 7.0f;
|
||||
}
|
||||
if Float::is_na_n(module_size_est2) {
|
||||
return module_size_est1 / 7.0f;
|
||||
}
|
||||
// and 1 white and 1 black module on either side. Ergo, divide sum by 14.
|
||||
return (module_size_est1 + module_size_est2) / 14.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of
|
||||
* a finder pattern by looking for a black-white-black run from the center in the direction
|
||||
* of another point (another finder pattern center), and in the opposite direction too.
|
||||
*/
|
||||
fn size_of_black_white_black_run_both_ways(&self, from_x: i32, from_y: i32, to_x: i32, to_y: i32) -> f32 {
|
||||
let mut result: f32 = self.size_of_black_white_black_run(from_x, from_y, to_x, to_y);
|
||||
// Now count other way -- don't run off image though of course
|
||||
let mut scale: f32 = 1.0f;
|
||||
let other_to_x: i32 = from_x - (to_x - from_x);
|
||||
if other_to_x < 0 {
|
||||
scale = from_x / (from_x - other_to_x) as f32;
|
||||
other_to_x = 0;
|
||||
} else if other_to_x >= self.image.get_width() {
|
||||
scale = (self.image.get_width() - 1.0 - from_x) / (other_to_x - from_x) as f32;
|
||||
other_to_x = self.image.get_width() - 1;
|
||||
}
|
||||
let other_to_y: i32 = (from_y - (to_y - from_y) * scale) as i32;
|
||||
scale = 1.0f;
|
||||
if other_to_y < 0 {
|
||||
scale = from_y / (from_y - other_to_y) as f32;
|
||||
other_to_y = 0;
|
||||
} else if other_to_y >= self.image.get_height() {
|
||||
scale = (self.image.get_height() - 1.0 - from_y) / (other_to_y - from_y) as f32;
|
||||
other_to_y = self.image.get_height() - 1;
|
||||
}
|
||||
other_to_x = (from_x + (other_to_x - from_x) * scale) as i32;
|
||||
result += self.size_of_black_white_black_run(from_x, from_y, other_to_x, other_to_y);
|
||||
// Middle pixel is double-counted this way; subtract 1
|
||||
return result - 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method traces a line from a point in the image, in the direction towards another point.
|
||||
* It begins in a black region, and keeps going until it finds white, then black, then white again.
|
||||
* It reports the distance from the start to this point.</p>
|
||||
*
|
||||
* <p>This is used when figuring out how wide a finder pattern is, when the finder pattern
|
||||
* may be skewed or rotated.</p>
|
||||
*/
|
||||
fn size_of_black_white_black_run(&self, from_x: i32, from_y: i32, to_x: i32, to_y: i32) -> f32 {
|
||||
// Mild variant of Bresenham's algorithm;
|
||||
// see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
|
||||
let steep: bool = Math::abs(to_y - from_y) > Math::abs(to_x - from_x);
|
||||
if steep {
|
||||
let mut temp: i32 = from_x;
|
||||
from_x = from_y;
|
||||
from_y = temp;
|
||||
temp = to_x;
|
||||
to_x = to_y;
|
||||
to_y = temp;
|
||||
}
|
||||
let dx: i32 = Math::abs(to_x - from_x);
|
||||
let dy: i32 = Math::abs(to_y - from_y);
|
||||
let mut error: i32 = -dx / 2;
|
||||
let xstep: i32 = if from_x < to_x { 1 } else { -1 };
|
||||
let ystep: i32 = if from_y < to_y { 1 } else { -1 };
|
||||
// In black pixels, looking for white, first or second time.
|
||||
let mut state: i32 = 0;
|
||||
// Loop up until x == toX, but not beyond
|
||||
let x_limit: i32 = to_x + xstep;
|
||||
{
|
||||
let mut x: i32 = from_x, let mut y: i32 = from_y;
|
||||
while x != x_limit {
|
||||
{
|
||||
let real_x: i32 = if steep { y } else { x };
|
||||
let real_y: i32 = if steep { x } else { y };
|
||||
// color, advance to next state or end if we are in state 2 already
|
||||
if (state == 1) == self.image.get(real_x, real_y) {
|
||||
if state == 2 {
|
||||
return MathUtils::distance(x, y, from_x, from_y);
|
||||
}
|
||||
state += 1;
|
||||
}
|
||||
error += dy;
|
||||
if error > 0 {
|
||||
if y == to_y {
|
||||
break;
|
||||
}
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
x += xstep;
|
||||
}
|
||||
}
|
||||
|
||||
// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
|
||||
if state == 2 {
|
||||
return MathUtils::distance(to_x + xstep, to_y, from_x, from_y);
|
||||
}
|
||||
// else we didn't find even black-white-black; no estimate is really possible
|
||||
return Float::NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to locate an alignment pattern in a limited region of the image, which is
|
||||
* guessed to contain it. This method uses {@link AlignmentPattern}.</p>
|
||||
*
|
||||
* @param overallEstModuleSize estimated module size so far
|
||||
* @param estAlignmentX x coordinate of center of area probably containing alignment pattern
|
||||
* @param estAlignmentY y coordinate of above
|
||||
* @param allowanceFactor number of pixels in all directions to search from the center
|
||||
* @return {@link AlignmentPattern} if found, or null otherwise
|
||||
* @throws NotFoundException if an unexpected error occurs during detection
|
||||
*/
|
||||
pub fn find_alignment_in_region(&self, overall_est_module_size: f32, est_alignment_x: i32, est_alignment_y: i32, allowance_factor: f32) -> /* throws NotFoundException */Result<AlignmentPattern, Rc<Exception>> {
|
||||
// Look for an alignment pattern (3 modules in size) around where it
|
||||
// should be
|
||||
let allowance: i32 = (allowance_factor * overall_est_module_size) as i32;
|
||||
let alignment_area_left_x: i32 = Math::max(0, est_alignment_x - allowance);
|
||||
let alignment_area_right_x: i32 = Math::min(self.image.get_width() - 1, est_alignment_x + allowance);
|
||||
if alignment_area_right_x - alignment_area_left_x < overall_est_module_size * 3.0 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let alignment_area_top_y: i32 = Math::max(0, est_alignment_y - allowance);
|
||||
let alignment_area_bottom_y: i32 = Math::min(self.image.get_height() - 1, est_alignment_y + allowance);
|
||||
if alignment_area_bottom_y - alignment_area_top_y < overall_est_module_size * 3.0 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let alignment_finder: AlignmentPatternFinder = AlignmentPatternFinder::new(self.image, alignment_area_left_x, alignment_area_top_y, alignment_area_right_x - alignment_area_left_x, alignment_area_bottom_y - alignment_area_top_y, overall_est_module_size, self.result_point_callback);
|
||||
return Ok(alignment_finder.find());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::detector;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a finder pattern, which are the three square patterns found in
|
||||
* the corners of QR Codes. It also encapsulates a count of similar finder patterns,
|
||||
* as a convenience to the finder's bookkeeping.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct FinderPattern {
|
||||
super: ResultPoint;
|
||||
|
||||
let estimated_module_size: f32;
|
||||
|
||||
let count: i32;
|
||||
}
|
||||
|
||||
impl FinderPattern {
|
||||
|
||||
fn new( pos_x: f32, pos_y: f32, estimated_module_size: f32) -> FinderPattern {
|
||||
this(pos_x, pos_y, estimated_module_size, 1);
|
||||
}
|
||||
|
||||
fn new( pos_x: f32, pos_y: f32, estimated_module_size: f32, count: i32) -> FinderPattern {
|
||||
super(pos_x, pos_y);
|
||||
let .estimatedModuleSize = estimated_module_size;
|
||||
let .count = count;
|
||||
}
|
||||
|
||||
pub fn get_estimated_module_size(&self) -> f32 {
|
||||
return self.estimated_module_size;
|
||||
}
|
||||
|
||||
pub fn get_count(&self) -> i32 {
|
||||
return self.count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Determines if this finder pattern "about equals" a finder pattern at the stated
|
||||
* position and size -- meaning, it is at nearly the same center with nearly the same size.</p>
|
||||
*/
|
||||
fn about_equals(&self, module_size: f32, i: f32, j: f32) -> bool {
|
||||
if Math::abs(i - get_y()) <= module_size && Math::abs(j - get_x()) <= module_size {
|
||||
let module_size_diff: f32 = Math::abs(module_size - self.estimated_module_size);
|
||||
return module_size_diff <= 1.0f || module_size_diff <= self.estimated_module_size;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this object's current estimate of a finder pattern position and module size
|
||||
* with a new estimate. It returns a new {@code FinderPattern} containing a weighted average
|
||||
* based on count.
|
||||
*/
|
||||
fn combine_estimate(&self, i: f32, j: f32, new_module_size: f32) -> FinderPattern {
|
||||
let combined_count: i32 = self.count + 1;
|
||||
let combined_x: f32 = (self.count * get_x() + j) / combined_count;
|
||||
let combined_y: f32 = (self.count * get_y() + i) / combined_count;
|
||||
let combined_module_size: f32 = (self.count * self.estimated_module_size + new_module_size) / combined_count;
|
||||
return FinderPattern::new(combined_x, combined_y, combined_module_size, combined_count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,728 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::detector;
|
||||
|
||||
/**
|
||||
* <p>This class attempts to find finder patterns in a QR Code. Finder patterns are the square
|
||||
* markers at three corners of a QR Code.</p>
|
||||
*
|
||||
* <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const CENTER_QUORUM: i32 = 2;
|
||||
|
||||
let module_comparator: EstimatedModuleComparator = EstimatedModuleComparator::new();
|
||||
|
||||
// 1 pixel/module times 3 modules/center
|
||||
const MIN_SKIP: i32 = 3;
|
||||
|
||||
// support up to version 20 for mobile clients
|
||||
const MAX_MODULES: i32 = 97;
|
||||
pub struct FinderPatternFinder {
|
||||
|
||||
let image: BitMatrix;
|
||||
|
||||
let possible_centers: List<FinderPattern>;
|
||||
|
||||
let has_skipped: bool;
|
||||
|
||||
let cross_check_state_count: Vec<i32>;
|
||||
|
||||
let result_point_callback: ResultPointCallback;
|
||||
}
|
||||
|
||||
impl FinderPatternFinder {
|
||||
|
||||
/**
|
||||
* <p>Creates a finder that will search the image for three finder patterns.</p>
|
||||
*
|
||||
* @param image image to search
|
||||
*/
|
||||
pub fn new( image: &BitMatrix) -> FinderPatternFinder {
|
||||
this(image, null);
|
||||
}
|
||||
|
||||
pub fn new( image: &BitMatrix, result_point_callback: &ResultPointCallback) -> FinderPatternFinder {
|
||||
let .image = image;
|
||||
let .possibleCenters = ArrayList<>::new();
|
||||
let .crossCheckStateCount = : [i32; 5] = [0; 5];
|
||||
let .resultPointCallback = result_point_callback;
|
||||
}
|
||||
|
||||
pub fn get_image(&self) -> BitMatrix {
|
||||
return self.image;
|
||||
}
|
||||
|
||||
pub fn get_possible_centers(&self) -> List<FinderPattern> {
|
||||
return self.possible_centers;
|
||||
}
|
||||
|
||||
fn find(&self, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<FinderPatternInfo, Rc<Exception>> {
|
||||
let try_harder: bool = hints != null && hints.contains_key(DecodeHintType::TRY_HARDER);
|
||||
let max_i: i32 = self.image.get_height();
|
||||
let max_j: i32 = self.image.get_width();
|
||||
// We are looking for black/white/black/white/black modules in
|
||||
// 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
|
||||
// Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
|
||||
// image, and then account for the center being 3 modules in size. This gives the smallest
|
||||
// number of pixels the center could be, so skip this often. When trying harder, look for all
|
||||
// QR versions regardless of how dense they are.
|
||||
let i_skip: i32 = (3 * max_i) / (4 * MAX_MODULES);
|
||||
if i_skip < MIN_SKIP || try_harder {
|
||||
i_skip = MIN_SKIP;
|
||||
}
|
||||
let mut done: bool = false;
|
||||
let state_count: [i32; 5] = [0; 5];
|
||||
{
|
||||
let mut i: i32 = i_skip - 1;
|
||||
while i < max_i && !done {
|
||||
{
|
||||
// Get a row of black/white values
|
||||
::do_clear_counts(&state_count);
|
||||
let current_state: i32 = 0;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < max_j {
|
||||
{
|
||||
if self.image.get(j, i) {
|
||||
// Black pixel
|
||||
if (current_state & 1) == 1 {
|
||||
// Counting white pixels
|
||||
current_state += 1;
|
||||
}
|
||||
state_count[current_state] += 1;
|
||||
} else {
|
||||
// White pixel
|
||||
if (current_state & 1) == 0 {
|
||||
// Counting black pixels
|
||||
if current_state == 4 {
|
||||
// A winner?
|
||||
if ::found_pattern_cross(&state_count) {
|
||||
// Yes
|
||||
let confirmed: bool = self.handle_possible_center(&state_count, i, j);
|
||||
if confirmed {
|
||||
// Start examining every other line. Checking each line turned out to be too
|
||||
// expensive and didn't improve performance.
|
||||
i_skip = 2;
|
||||
if self.has_skipped {
|
||||
done = self.have_multiply_confirmed_centers();
|
||||
} else {
|
||||
let row_skip: i32 = self.find_row_skip();
|
||||
if row_skip > state_count[2] {
|
||||
// Skip rows between row of lower confirmed center
|
||||
// and top of presumed third confirmed center
|
||||
// but back up a bit to get a full chance of detecting
|
||||
// it, entire width of center of finder pattern
|
||||
// Skip by rowSkip, but back off by stateCount[2] (size of last center
|
||||
// of pattern we saw) to be conservative, and also back off by iSkip which
|
||||
// is about to be re-added
|
||||
i += row_skip - state_count[2] - i_skip;
|
||||
j = max_j - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
::do_shift_counts2(&state_count);
|
||||
current_state = 3;
|
||||
continue;
|
||||
}
|
||||
// Clear state to start looking again
|
||||
current_state = 0;
|
||||
::do_clear_counts(&state_count);
|
||||
} else {
|
||||
// No, shift counts back by two
|
||||
::do_shift_counts2(&state_count);
|
||||
current_state = 3;
|
||||
}
|
||||
} else {
|
||||
state_count[current_state += 1] += 1;
|
||||
}
|
||||
} else {
|
||||
// Counting white pixels
|
||||
state_count[current_state] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ::found_pattern_cross(&state_count) {
|
||||
let confirmed: bool = self.handle_possible_center(&state_count, i, max_j);
|
||||
if confirmed {
|
||||
i_skip = state_count[0];
|
||||
if self.has_skipped {
|
||||
// Found a third one
|
||||
done = self.have_multiply_confirmed_centers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i += i_skip;
|
||||
}
|
||||
}
|
||||
|
||||
let pattern_info: Vec<FinderPattern> = self.select_best_patterns();
|
||||
ResultPoint::order_best_patterns(pattern_info);
|
||||
return Ok(FinderPatternInfo::new(pattern_info));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a count of black/white/black/white/black pixels just seen and an end position,
|
||||
* figures the location of the center of this run.
|
||||
*/
|
||||
fn center_from_end( state_count: &Vec<i32>, end: i32) -> f32 {
|
||||
return (end - state_count[4] - state_count[3]) - state_count[2] / 2.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stateCount count of black/white/black/white/black pixels just read
|
||||
* @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios
|
||||
* used by finder patterns to be considered a match
|
||||
*/
|
||||
pub fn found_pattern_cross( state_count: &Vec<i32>) -> bool {
|
||||
let total_module_size: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 5 {
|
||||
{
|
||||
let count: i32 = state_count[i];
|
||||
if count == 0 {
|
||||
return false;
|
||||
}
|
||||
total_module_size += count;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if total_module_size < 7 {
|
||||
return false;
|
||||
}
|
||||
let module_size: f32 = total_module_size / 7.0f;
|
||||
let max_variance: f32 = module_size / 2.0f;
|
||||
// Allow less than 50% variance from 1-1-3-1-1 proportions
|
||||
return Math::abs(module_size - state_count[0]) < max_variance && Math::abs(module_size - state_count[1]) < max_variance && Math::abs(3.0f * module_size - state_count[2]) < 3.0 * max_variance && Math::abs(module_size - state_count[3]) < max_variance && Math::abs(module_size - state_count[4]) < max_variance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stateCount count of black/white/black/white/black pixels just read
|
||||
* @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios
|
||||
* used by finder patterns to be considered a match
|
||||
*/
|
||||
pub fn found_pattern_diagonal( state_count: &Vec<i32>) -> bool {
|
||||
let total_module_size: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 5 {
|
||||
{
|
||||
let count: i32 = state_count[i];
|
||||
if count == 0 {
|
||||
return false;
|
||||
}
|
||||
total_module_size += count;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if total_module_size < 7 {
|
||||
return false;
|
||||
}
|
||||
let module_size: f32 = total_module_size / 7.0f;
|
||||
let max_variance: f32 = module_size / 1.333f;
|
||||
// Allow less than 75% variance from 1-1-3-1-1 proportions
|
||||
return Math::abs(module_size - state_count[0]) < max_variance && Math::abs(module_size - state_count[1]) < max_variance && Math::abs(3.0f * module_size - state_count[2]) < 3.0 * max_variance && Math::abs(module_size - state_count[3]) < max_variance && Math::abs(module_size - state_count[4]) < max_variance;
|
||||
}
|
||||
|
||||
fn get_cross_check_state_count(&self) -> Vec<i32> {
|
||||
::do_clear_counts(&self.cross_check_state_count);
|
||||
return self.cross_check_state_count;
|
||||
}
|
||||
|
||||
pub fn clear_counts(&self, counts: &Vec<i32>) {
|
||||
::do_clear_counts(&counts);
|
||||
}
|
||||
|
||||
pub fn shift_counts2(&self, state_count: &Vec<i32>) {
|
||||
::do_shift_counts2(&state_count);
|
||||
}
|
||||
|
||||
pub fn do_clear_counts( counts: &Vec<i32>) {
|
||||
Arrays::fill(&counts, 0);
|
||||
}
|
||||
|
||||
pub fn do_shift_counts2( state_count: &Vec<i32>) {
|
||||
state_count[0] = state_count[2];
|
||||
state_count[1] = state_count[3];
|
||||
state_count[2] = state_count[4];
|
||||
state_count[3] = 1;
|
||||
state_count[4] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* After a vertical and horizontal scan finds a potential finder pattern, this method
|
||||
* "cross-cross-cross-checks" by scanning down diagonally through the center of the possible
|
||||
* finder pattern to see if the same proportion is detected.
|
||||
*
|
||||
* @param centerI row where a finder pattern was detected
|
||||
* @param centerJ center of the section that appears to cross a finder pattern
|
||||
* @return true if proportions are withing expected limits
|
||||
*/
|
||||
fn cross_check_diagonal(&self, center_i: i32, center_j: i32) -> bool {
|
||||
let state_count: Vec<i32> = self.get_cross_check_state_count();
|
||||
// Start counting up, left from center finding black center mass
|
||||
let mut i: i32 = 0;
|
||||
while center_i >= i && center_j >= i && self.image.get(center_j - i, center_i - i) {
|
||||
state_count[2] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[2] == 0 {
|
||||
return false;
|
||||
}
|
||||
// Continue up, left finding white space
|
||||
while center_i >= i && center_j >= i && !self.image.get(center_j - i, center_i - i) {
|
||||
state_count[1] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[1] == 0 {
|
||||
return false;
|
||||
}
|
||||
// Continue up, left finding black border
|
||||
while center_i >= i && center_j >= i && self.image.get(center_j - i, center_i - i) {
|
||||
state_count[0] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[0] == 0 {
|
||||
return false;
|
||||
}
|
||||
let max_i: i32 = self.image.get_height();
|
||||
let max_j: i32 = self.image.get_width();
|
||||
// Now also count down, right from center
|
||||
i = 1;
|
||||
while center_i + i < max_i && center_j + i < max_j && self.image.get(center_j + i, center_i + i) {
|
||||
state_count[2] += 1;
|
||||
i += 1;
|
||||
}
|
||||
while center_i + i < max_i && center_j + i < max_j && !self.image.get(center_j + i, center_i + i) {
|
||||
state_count[3] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[3] == 0 {
|
||||
return false;
|
||||
}
|
||||
while center_i + i < max_i && center_j + i < max_j && self.image.get(center_j + i, center_i + i) {
|
||||
state_count[4] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[4] == 0 {
|
||||
return false;
|
||||
}
|
||||
return ::found_pattern_diagonal(&state_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>After a horizontal scan finds a potential finder pattern, this method
|
||||
* "cross-checks" by scanning down vertically through the center of the possible
|
||||
* finder pattern to see if the same proportion is detected.</p>
|
||||
*
|
||||
* @param startI row where a finder pattern was detected
|
||||
* @param centerJ center of the section that appears to cross a finder pattern
|
||||
* @param maxCount maximum reasonable number of modules that should be
|
||||
* observed in any reading state, based on the results of the horizontal scan
|
||||
* @return vertical center of finder pattern, or {@link Float#NaN} if not found
|
||||
*/
|
||||
fn cross_check_vertical(&self, start_i: i32, center_j: i32, max_count: i32, original_state_count_total: i32) -> f32 {
|
||||
let image: BitMatrix = self.image;
|
||||
let max_i: i32 = image.get_height();
|
||||
let state_count: Vec<i32> = self.get_cross_check_state_count();
|
||||
// Start counting up from center
|
||||
let mut i: i32 = start_i;
|
||||
while i >= 0 && image.get(center_j, i) {
|
||||
state_count[2] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
if i < 0 {
|
||||
return Float::NaN;
|
||||
}
|
||||
while i >= 0 && !image.get(center_j, i) && state_count[1] <= max_count {
|
||||
state_count[1] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
// If already too many modules in this state or ran off the edge:
|
||||
if i < 0 || state_count[1] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
while i >= 0 && image.get(center_j, i) && state_count[0] <= max_count {
|
||||
state_count[0] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
if state_count[0] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
// Now also count down from center
|
||||
i = start_i + 1;
|
||||
while i < max_i && image.get(center_j, i) {
|
||||
state_count[2] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if i == max_i {
|
||||
return Float::NaN;
|
||||
}
|
||||
while i < max_i && !image.get(center_j, i) && state_count[3] < max_count {
|
||||
state_count[3] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if i == max_i || state_count[3] >= max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
while i < max_i && image.get(center_j, i) && state_count[4] < max_count {
|
||||
state_count[4] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if state_count[4] >= max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
// If we found a finder-pattern-like section, but its size is more than 40% different than
|
||||
// the original, assume it's a false positive
|
||||
let state_count_total: i32 = state_count[0] + state_count[1] + state_count[2] + state_count[3] + state_count[4];
|
||||
if 5 * Math::abs(state_count_total - original_state_count_total) >= 2 * original_state_count_total {
|
||||
return Float::NaN;
|
||||
}
|
||||
return if ::found_pattern_cross(&state_count) { ::center_from_end(&state_count, i) } else { Float::NaN };
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical,
|
||||
* except it reads horizontally instead of vertically. This is used to cross-cross
|
||||
* check a vertical cross check and locate the real center of the alignment pattern.</p>
|
||||
*/
|
||||
fn cross_check_horizontal(&self, start_j: i32, center_i: i32, max_count: i32, original_state_count_total: i32) -> f32 {
|
||||
let image: BitMatrix = self.image;
|
||||
let max_j: i32 = image.get_width();
|
||||
let state_count: Vec<i32> = self.get_cross_check_state_count();
|
||||
let mut j: i32 = start_j;
|
||||
while j >= 0 && image.get(j, center_i) {
|
||||
state_count[2] += 1;
|
||||
j -= 1;
|
||||
}
|
||||
if j < 0 {
|
||||
return Float::NaN;
|
||||
}
|
||||
while j >= 0 && !image.get(j, center_i) && state_count[1] <= max_count {
|
||||
state_count[1] += 1;
|
||||
j -= 1;
|
||||
}
|
||||
if j < 0 || state_count[1] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
while j >= 0 && image.get(j, center_i) && state_count[0] <= max_count {
|
||||
state_count[0] += 1;
|
||||
j -= 1;
|
||||
}
|
||||
if state_count[0] > max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
j = start_j + 1;
|
||||
while j < max_j && image.get(j, center_i) {
|
||||
state_count[2] += 1;
|
||||
j += 1;
|
||||
}
|
||||
if j == max_j {
|
||||
return Float::NaN;
|
||||
}
|
||||
while j < max_j && !image.get(j, center_i) && state_count[3] < max_count {
|
||||
state_count[3] += 1;
|
||||
j += 1;
|
||||
}
|
||||
if j == max_j || state_count[3] >= max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
while j < max_j && image.get(j, center_i) && state_count[4] < max_count {
|
||||
state_count[4] += 1;
|
||||
j += 1;
|
||||
}
|
||||
if state_count[4] >= max_count {
|
||||
return Float::NaN;
|
||||
}
|
||||
// If we found a finder-pattern-like section, but its size is significantly different than
|
||||
// the original, assume it's a false positive
|
||||
let state_count_total: i32 = state_count[0] + state_count[1] + state_count[2] + state_count[3] + state_count[4];
|
||||
if 5 * Math::abs(state_count_total - original_state_count_total) >= original_state_count_total {
|
||||
return Float::NaN;
|
||||
}
|
||||
return if ::found_pattern_cross(&state_count) { ::center_from_end(&state_count, j) } else { Float::NaN };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stateCount reading state module counts from horizontal scan
|
||||
* @param i row where finder pattern may be found
|
||||
* @param j end of possible finder pattern in row
|
||||
* @param pureBarcode ignored
|
||||
* @return true if a finder pattern candidate was found this time
|
||||
* @deprecated only exists for backwards compatibility
|
||||
* @see #handlePossibleCenter(int[], int, int)
|
||||
*/
|
||||
pub fn handle_possible_center(&self, state_count: &Vec<i32>, i: i32, j: i32, pure_barcode: bool) -> bool {
|
||||
return self.handle_possible_center(&state_count, i, j);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This is called when a horizontal scan finds a possible alignment pattern. It will
|
||||
* cross check with a vertical scan, and if successful, will, ah, cross-cross-check
|
||||
* with another horizontal scan. This is needed primarily to locate the real horizontal
|
||||
* center of the pattern in cases of extreme skew.
|
||||
* And then we cross-cross-cross check with another diagonal scan.</p>
|
||||
*
|
||||
* <p>If that succeeds the finder pattern location is added to a list that tracks
|
||||
* the number of times each location has been nearly-matched as a finder pattern.
|
||||
* Each additional find is more evidence that the location is in fact a finder
|
||||
* pattern center
|
||||
*
|
||||
* @param stateCount reading state module counts from horizontal scan
|
||||
* @param i row where finder pattern may be found
|
||||
* @param j end of possible finder pattern in row
|
||||
* @return true if a finder pattern candidate was found this time
|
||||
*/
|
||||
pub fn handle_possible_center(&self, state_count: &Vec<i32>, i: i32, j: i32) -> bool {
|
||||
let state_count_total: i32 = state_count[0] + state_count[1] + state_count[2] + state_count[3] + state_count[4];
|
||||
let center_j: f32 = ::center_from_end(&state_count, j);
|
||||
let center_i: f32 = self.cross_check_vertical(i, center_j as i32, state_count[2], state_count_total);
|
||||
if !Float::is_na_n(center_i) {
|
||||
// Re-cross check
|
||||
center_j = self.cross_check_horizontal(center_j as i32, center_i as i32, state_count[2], state_count_total);
|
||||
if !Float::is_na_n(center_j) && self.cross_check_diagonal(center_i as i32, center_j as i32) {
|
||||
let estimated_module_size: f32 = state_count_total / 7.0f;
|
||||
let mut found: bool = false;
|
||||
{
|
||||
let mut index: i32 = 0;
|
||||
while index < self.possible_centers.size() {
|
||||
{
|
||||
let center: FinderPattern = self.possible_centers.get(index);
|
||||
// Look for about the same center and module size:
|
||||
if center.about_equals(estimated_module_size, center_i, center_j) {
|
||||
self.possible_centers.set(index, ¢er.combine_estimate(center_i, center_j, estimated_module_size));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
let point: FinderPattern = FinderPattern::new(center_j, center_i, estimated_module_size);
|
||||
self.possible_centers.add(point);
|
||||
if self.result_point_callback != null {
|
||||
self.result_point_callback.found_possible_result_point(point);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of rows we could safely skip during scanning, based on the first
|
||||
* two finder patterns that have been located. In some cases their position will
|
||||
* allow us to infer that the third pattern must lie below a certain point farther
|
||||
* down in the image.
|
||||
*/
|
||||
fn find_row_skip(&self) -> i32 {
|
||||
let max: i32 = self.possible_centers.size();
|
||||
if max <= 1 {
|
||||
return 0;
|
||||
}
|
||||
let first_confirmed_center: ResultPoint = null;
|
||||
for let center: FinderPattern in self.possible_centers {
|
||||
if center.get_count() >= CENTER_QUORUM {
|
||||
if first_confirmed_center == null {
|
||||
first_confirmed_center = center;
|
||||
} else {
|
||||
// We have two confirmed centers
|
||||
// How far down can we skip before resuming looking for the next
|
||||
// pattern? In the worst case, only the difference between the
|
||||
// difference in the x / y coordinates of the two centers.
|
||||
// This is the case where you find top left last.
|
||||
self.has_skipped = true;
|
||||
return (Math::abs(first_confirmed_center.get_x() - center.get_x()) - Math::abs(first_confirmed_center.get_y() - center.get_y())) as i32 / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true iff we have found at least 3 finder patterns that have been detected
|
||||
* at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the
|
||||
* candidates is "pretty similar"
|
||||
*/
|
||||
fn have_multiply_confirmed_centers(&self) -> bool {
|
||||
let confirmed_count: i32 = 0;
|
||||
let total_module_size: f32 = 0.0f;
|
||||
let max: i32 = self.possible_centers.size();
|
||||
for let pattern: FinderPattern in self.possible_centers {
|
||||
if pattern.get_count() >= CENTER_QUORUM {
|
||||
confirmed_count += 1;
|
||||
total_module_size += pattern.get_estimated_module_size();
|
||||
}
|
||||
}
|
||||
if confirmed_count < 3 {
|
||||
return false;
|
||||
}
|
||||
// OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
|
||||
// and that we need to keep looking. We detect this by asking if the estimated module sizes
|
||||
// vary too much. We arbitrarily say that when the total deviation from average exceeds
|
||||
// 5% of the total module size estimates, it's too much.
|
||||
let average: f32 = total_module_size / max;
|
||||
let total_deviation: f32 = 0.0f;
|
||||
for let pattern: FinderPattern in self.possible_centers {
|
||||
total_deviation += Math::abs(pattern.get_estimated_module_size() - average);
|
||||
}
|
||||
return total_deviation <= 0.05f * total_module_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get square of distance between a and b.
|
||||
*/
|
||||
fn squared_distance( a: &FinderPattern, b: &FinderPattern) -> f64 {
|
||||
let x: f64 = a.get_x() - b.get_x();
|
||||
let y: f64 = a.get_y() - b.get_y();
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
|
||||
* those have similar module size and form a shape closer to a isosceles right triangle.
|
||||
* @throws NotFoundException if 3 such finder patterns do not exist
|
||||
*/
|
||||
fn select_best_patterns(&self) -> /* throws NotFoundException */Result<Vec<FinderPattern>, Rc<Exception>> {
|
||||
let start_size: i32 = self.possible_centers.size();
|
||||
if start_size < 3 {
|
||||
// Couldn't find enough finder patterns
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
self.possible_centers.sort(module_comparator);
|
||||
let mut distortion: f64 = Double::MAX_VALUE;
|
||||
let best_patterns: [Option<FinderPattern>; 3] = [None; 3];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.possible_centers.size() - 2 {
|
||||
{
|
||||
let fpi: FinderPattern = self.possible_centers.get(i);
|
||||
let min_module_size: f32 = fpi.get_estimated_module_size();
|
||||
{
|
||||
let mut j: i32 = i + 1;
|
||||
while j < self.possible_centers.size() - 1 {
|
||||
{
|
||||
let fpj: FinderPattern = self.possible_centers.get(j);
|
||||
let squares0: f64 = ::squared_distance(fpi, fpj);
|
||||
{
|
||||
let mut k: i32 = j + 1;
|
||||
while k < self.possible_centers.size() {
|
||||
{
|
||||
let fpk: FinderPattern = self.possible_centers.get(k);
|
||||
let max_module_size: f32 = fpk.get_estimated_module_size();
|
||||
if max_module_size > min_module_size * 1.4f {
|
||||
// module size is not similar
|
||||
continue;
|
||||
}
|
||||
let mut a: f64 = squares0;
|
||||
let mut b: f64 = ::squared_distance(fpj, fpk);
|
||||
let mut c: f64 = ::squared_distance(fpi, fpk);
|
||||
// sorts ascending - inlined
|
||||
if a < b {
|
||||
if b > c {
|
||||
if a < c {
|
||||
let temp: f64 = b;
|
||||
b = c;
|
||||
c = temp;
|
||||
} else {
|
||||
let temp: f64 = a;
|
||||
a = c;
|
||||
c = b;
|
||||
b = temp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if b < c {
|
||||
if a < c {
|
||||
let temp: f64 = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
} else {
|
||||
let temp: f64 = a;
|
||||
a = b;
|
||||
b = c;
|
||||
c = temp;
|
||||
}
|
||||
} else {
|
||||
let temp: f64 = a;
|
||||
a = c;
|
||||
c = temp;
|
||||
}
|
||||
}
|
||||
// a^2 + b^2 = c^2 (Pythagorean theorem), and a = b (isosceles triangle).
|
||||
// Since any right triangle satisfies the formula c^2 - b^2 - a^2 = 0,
|
||||
// we need to check both two equal sides separately.
|
||||
// The value of |c^2 - 2 * b^2| + |c^2 - 2 * a^2| increases as dissimilarity
|
||||
// from isosceles right triangle.
|
||||
let d: f64 = Math::abs(c - 2.0 * b) + Math::abs(c - 2.0 * a);
|
||||
if d < distortion {
|
||||
distortion = d;
|
||||
best_patterns[0] = fpi;
|
||||
best_patterns[1] = fpj;
|
||||
best_patterns[2] = fpk;
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if distortion == Double::MAX_VALUE {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
return Ok(best_patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Orders by {@link FinderPattern#getEstimatedModuleSize()}</p>
|
||||
*/
|
||||
#[derive(Comparator<FinderPattern>, Serializable)]
|
||||
struct EstimatedModuleComparator {
|
||||
}
|
||||
|
||||
impl EstimatedModuleComparator {
|
||||
|
||||
pub fn compare(&self, center1: &FinderPattern, center2: &FinderPattern) -> i32 {
|
||||
return Float::compare(¢er1.get_estimated_module_size(), ¢er2.get_estimated_module_size());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::detector;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates information about finder patterns in an image, including the location of
|
||||
* the three finder patterns, and their estimated module size.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct FinderPatternInfo {
|
||||
|
||||
let bottom_left: FinderPattern;
|
||||
|
||||
let top_left: FinderPattern;
|
||||
|
||||
let top_right: FinderPattern;
|
||||
}
|
||||
|
||||
impl FinderPatternInfo {
|
||||
|
||||
pub fn new( pattern_centers: &Vec<FinderPattern>) -> FinderPatternInfo {
|
||||
let .bottomLeft = pattern_centers[0];
|
||||
let .topLeft = pattern_centers[1];
|
||||
let .topRight = pattern_centers[2];
|
||||
}
|
||||
|
||||
pub fn get_bottom_left(&self) -> FinderPattern {
|
||||
return self.bottom_left;
|
||||
}
|
||||
|
||||
pub fn get_top_left(&self) -> FinderPattern {
|
||||
return self.top_left;
|
||||
}
|
||||
|
||||
pub fn get_top_right(&self) -> FinderPattern {
|
||||
return self.top_right;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
struct BlockPair {
|
||||
|
||||
let data_bytes: Vec<i8>;
|
||||
|
||||
let error_correction_bytes: Vec<i8>;
|
||||
}
|
||||
|
||||
impl BlockPair {
|
||||
|
||||
fn new( data: &Vec<i8>, error_correction: &Vec<i8>) -> BlockPair {
|
||||
data_bytes = data;
|
||||
error_correction_bytes = error_correction;
|
||||
}
|
||||
|
||||
pub fn get_data_bytes(&self) -> Vec<i8> {
|
||||
return self.data_bytes;
|
||||
}
|
||||
|
||||
pub fn get_error_correction_bytes(&self) -> Vec<i8> {
|
||||
return self.error_correction_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
/**
|
||||
* JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned
|
||||
* -1, 0, and 1, I'm going to use less memory and go with bytes.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
pub struct ByteMatrix {
|
||||
|
||||
let mut bytes: Vec<Vec<i8>>;
|
||||
|
||||
let width: i32;
|
||||
|
||||
let height: i32;
|
||||
}
|
||||
|
||||
impl ByteMatrix {
|
||||
|
||||
pub fn new( width: i32, height: i32) -> ByteMatrix {
|
||||
bytes = : [[i8; width]; height] = [[0; width]; height];
|
||||
let .width = width;
|
||||
let .height = height;
|
||||
}
|
||||
|
||||
pub fn get_height(&self) -> i32 {
|
||||
return self.height;
|
||||
}
|
||||
|
||||
pub fn get_width(&self) -> i32 {
|
||||
return self.width;
|
||||
}
|
||||
|
||||
pub fn get(&self, x: i32, y: i32) -> i8 {
|
||||
return self.bytes[y][x];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y)
|
||||
*/
|
||||
pub fn get_array(&self) -> Vec<Vec<i8>> {
|
||||
return self.bytes;
|
||||
}
|
||||
|
||||
pub fn set(&self, x: i32, y: i32, value: i8) {
|
||||
self.bytes[y][x] = value;
|
||||
}
|
||||
|
||||
pub fn set(&self, x: i32, y: i32, value: i32) {
|
||||
self.bytes[y][x] = value as i8;
|
||||
}
|
||||
|
||||
pub fn set(&self, x: i32, y: i32, value: bool) {
|
||||
self.bytes[y][x] = ( if value { 1 } else { 0 }) as i8;
|
||||
}
|
||||
|
||||
pub fn clear(&self, value: i8) {
|
||||
for let a_byte: Vec<i8> in self.bytes {
|
||||
Arrays::fill(&a_byte, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(2 * self.width * self.height + 2);
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < self.height {
|
||||
{
|
||||
let bytes_y: Vec<i8> = self.bytes[y];
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < self.width {
|
||||
{
|
||||
match bytes_y[x] {
|
||||
0 =>
|
||||
{
|
||||
result.append(" 0");
|
||||
break;
|
||||
}
|
||||
1 =>
|
||||
{
|
||||
result.append(" 1");
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
result.append(" ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.append('\n');
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,789 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
|
||||
*/
|
||||
|
||||
// The original table is defined in the table 5 of JISX0510:2004 (p.19).
|
||||
const ALPHANUMERIC_TABLE: vec![Vec<i32>; 96] = vec![// 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x00-0x0f
|
||||
// 0x00-0x0f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x10-0x1f
|
||||
// 0x10-0x1f
|
||||
-1, // 0x20-0x2f
|
||||
36, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
37, // 0x20-0x2f
|
||||
38, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
39, // 0x20-0x2f
|
||||
40, // 0x20-0x2f
|
||||
// 0x20-0x2f
|
||||
-1, // 0x20-0x2f
|
||||
41, // 0x20-0x2f
|
||||
42, // 0x20-0x2f
|
||||
43, // 0x30-0x3f
|
||||
0, // 0x30-0x3f
|
||||
1, // 0x30-0x3f
|
||||
2, // 0x30-0x3f
|
||||
3, // 0x30-0x3f
|
||||
4, // 0x30-0x3f
|
||||
5, // 0x30-0x3f
|
||||
6, // 0x30-0x3f
|
||||
7, // 0x30-0x3f
|
||||
8, // 0x30-0x3f
|
||||
9, // 0x30-0x3f
|
||||
44, // 0x30-0x3f
|
||||
// 0x30-0x3f
|
||||
-1, // 0x30-0x3f
|
||||
// 0x30-0x3f
|
||||
-1, // 0x30-0x3f
|
||||
// 0x30-0x3f
|
||||
-1, // 0x30-0x3f
|
||||
// 0x30-0x3f
|
||||
-1, // 0x30-0x3f
|
||||
// 0x30-0x3f
|
||||
-1, // 0x40-0x4f
|
||||
// 0x40-0x4f
|
||||
-1, // 0x40-0x4f
|
||||
10, // 0x40-0x4f
|
||||
11, // 0x40-0x4f
|
||||
12, // 0x40-0x4f
|
||||
13, // 0x40-0x4f
|
||||
14, // 0x40-0x4f
|
||||
15, // 0x40-0x4f
|
||||
16, // 0x40-0x4f
|
||||
17, // 0x40-0x4f
|
||||
18, // 0x40-0x4f
|
||||
19, // 0x40-0x4f
|
||||
20, // 0x40-0x4f
|
||||
21, // 0x40-0x4f
|
||||
22, // 0x40-0x4f
|
||||
23, // 0x40-0x4f
|
||||
24, // 0x50-0x5f
|
||||
25, // 0x50-0x5f
|
||||
26, // 0x50-0x5f
|
||||
27, // 0x50-0x5f
|
||||
28, // 0x50-0x5f
|
||||
29, // 0x50-0x5f
|
||||
30, // 0x50-0x5f
|
||||
31, // 0x50-0x5f
|
||||
32, // 0x50-0x5f
|
||||
33, // 0x50-0x5f
|
||||
34, // 0x50-0x5f
|
||||
35, // 0x50-0x5f
|
||||
// 0x50-0x5f
|
||||
-1, // 0x50-0x5f
|
||||
// 0x50-0x5f
|
||||
-1, // 0x50-0x5f
|
||||
// 0x50-0x5f
|
||||
-1, // 0x50-0x5f
|
||||
// 0x50-0x5f
|
||||
-1, // 0x50-0x5f
|
||||
// 0x50-0x5f
|
||||
-1, ]
|
||||
;
|
||||
|
||||
const DEFAULT_BYTE_MODE_ENCODING: Charset = StandardCharsets::ISO_8859_1;
|
||||
pub struct Encoder {
|
||||
}
|
||||
|
||||
impl Encoder {
|
||||
|
||||
fn new() -> Encoder {
|
||||
}
|
||||
|
||||
// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
|
||||
// Basically it applies four rules and summate all penalties.
|
||||
fn calculate_mask_penalty( matrix: &ByteMatrix) -> i32 {
|
||||
return MaskUtil::apply_mask_penalty_rule1(matrix) + MaskUtil::apply_mask_penalty_rule2(matrix) + MaskUtil::apply_mask_penalty_rule3(matrix) + MaskUtil::apply_mask_penalty_rule4(matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content text to encode
|
||||
* @param ecLevel error correction level to use
|
||||
* @return {@link QRCode} representing the encoded QR code
|
||||
* @throws WriterException if encoding can't succeed, because of for example invalid content
|
||||
* or configuration
|
||||
*/
|
||||
pub fn encode( content: &String, ec_level: &ErrorCorrectionLevel) -> /* throws WriterException */Result<QRCode, Rc<Exception>> {
|
||||
return Ok(::encode(&content, ec_level, null));
|
||||
}
|
||||
|
||||
pub fn encode( content: &String, ec_level: &ErrorCorrectionLevel, hints: &Map<EncodeHintType, ?>) -> /* throws WriterException */Result<QRCode, Rc<Exception>> {
|
||||
let mut version: Version;
|
||||
let header_and_data_bits: BitArray;
|
||||
let mut mode: Mode;
|
||||
let has_g_s1_format_hint: bool = hints != null && hints.contains_key(EncodeHintType::GS1_FORMAT) && Boolean::parse_boolean(&hints.get(EncodeHintType::GS1_FORMAT).to_string());
|
||||
let has_compaction_hint: bool = hints != null && hints.contains_key(EncodeHintType::QR_COMPACT) && Boolean::parse_boolean(&hints.get(EncodeHintType::QR_COMPACT).to_string());
|
||||
// Determine what character encoding has been specified by the caller, if any
|
||||
let mut encoding: Charset = DEFAULT_BYTE_MODE_ENCODING;
|
||||
let has_encoding_hint: bool = hints != null && hints.contains_key(EncodeHintType::CHARACTER_SET);
|
||||
if has_encoding_hint {
|
||||
encoding = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
|
||||
}
|
||||
if has_compaction_hint {
|
||||
mode = Mode::BYTE;
|
||||
let priority_encoding: Charset = if encoding.equals(&DEFAULT_BYTE_MODE_ENCODING) { null } else { encoding };
|
||||
let rn: MinimalEncoder.ResultList = MinimalEncoder::encode(&content, null, &priority_encoding, has_g_s1_format_hint, ec_level);
|
||||
header_and_data_bits = BitArray::new();
|
||||
rn.get_bits(header_and_data_bits);
|
||||
version = rn.get_version();
|
||||
} else {
|
||||
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
|
||||
// multiple modes / segments even if that were more efficient.
|
||||
mode = ::choose_mode(&content, &encoding);
|
||||
// This will store the header information, like mode and
|
||||
// length, as well as "header" segments like an ECI segment.
|
||||
let header_bits: BitArray = BitArray::new();
|
||||
// Append ECI segment if applicable
|
||||
if mode == Mode::BYTE && has_encoding_hint {
|
||||
let eci: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i(&encoding);
|
||||
if eci != null {
|
||||
::append_e_c_i(eci, header_bits);
|
||||
}
|
||||
}
|
||||
// Append the FNC1 mode header for GS1 formatted data if applicable
|
||||
if has_g_s1_format_hint {
|
||||
// GS1 formatted codes are prefixed with a FNC1 in first position mode header
|
||||
::append_mode_info(Mode::FNC1_FIRST_POSITION, header_bits);
|
||||
}
|
||||
// (With ECI in place,) Write the mode marker
|
||||
::append_mode_info(mode, header_bits);
|
||||
// Collect data within the main segment, separately, to count its size if needed. Don't add it to
|
||||
// main payload yet.
|
||||
let data_bits: BitArray = BitArray::new();
|
||||
::append_bytes(&content, mode, data_bits, &encoding);
|
||||
if hints != null && hints.contains_key(EncodeHintType::QR_VERSION) {
|
||||
let version_number: i32 = Integer::parse_int(&hints.get(EncodeHintType::QR_VERSION).to_string());
|
||||
version = Version::get_version_for_number(version_number);
|
||||
let bits_needed: i32 = ::calculate_bits_needed(mode, header_bits, data_bits, version);
|
||||
if !::will_fit(bits_needed, version, ec_level) {
|
||||
throw WriterException::new("Data too big for requested version");
|
||||
}
|
||||
} else {
|
||||
version = ::recommend_version(ec_level, mode, header_bits, data_bits);
|
||||
}
|
||||
header_and_data_bits = BitArray::new();
|
||||
header_and_data_bits.append_bit_array(header_bits);
|
||||
// Find "length" of main segment and write it
|
||||
let num_letters: i32 = if mode == Mode::BYTE { data_bits.get_size_in_bytes() } else { content.length() };
|
||||
::append_length_info(num_letters, version, mode, header_and_data_bits);
|
||||
// Put data together into the overall payload
|
||||
header_and_data_bits.append_bit_array(data_bits);
|
||||
}
|
||||
let ec_blocks: Version.ECBlocks = version.get_e_c_blocks_for_level(ec_level);
|
||||
let num_data_bytes: i32 = version.get_total_codewords() - ec_blocks.get_total_e_c_codewords();
|
||||
// Terminate the bits properly.
|
||||
::terminate_bits(num_data_bytes, header_and_data_bits);
|
||||
// Interleave data bits with error correction code.
|
||||
let final_bits: BitArray = ::interleave_with_e_c_bytes(header_and_data_bits, &version.get_total_codewords(), num_data_bytes, &ec_blocks.get_num_blocks());
|
||||
let qr_code: QRCode = QRCode::new();
|
||||
qr_code.set_e_c_level(ec_level);
|
||||
qr_code.set_mode(mode);
|
||||
qr_code.set_version(version);
|
||||
// Choose the mask pattern and set to "qrCode".
|
||||
let dimension: i32 = version.get_dimension_for_version();
|
||||
let matrix: ByteMatrix = ByteMatrix::new(dimension, dimension);
|
||||
// Enable manual selection of the pattern to be used via hint
|
||||
let mask_pattern: i32 = -1;
|
||||
if hints != null && hints.contains_key(EncodeHintType::QR_MASK_PATTERN) {
|
||||
let hint_mask_pattern: i32 = Integer::parse_int(&hints.get(EncodeHintType::QR_MASK_PATTERN).to_string());
|
||||
mask_pattern = if QRCode::is_valid_mask_pattern(hint_mask_pattern) { hint_mask_pattern } else { -1 };
|
||||
}
|
||||
if mask_pattern == -1 {
|
||||
mask_pattern = ::choose_mask_pattern(final_bits, ec_level, version, matrix);
|
||||
}
|
||||
qr_code.set_mask_pattern(mask_pattern);
|
||||
// Build the matrix and set it to "qrCode".
|
||||
MatrixUtil::build_matrix(final_bits, ec_level, version, mask_pattern, matrix);
|
||||
qr_code.set_matrix(matrix);
|
||||
return Ok(qr_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides the smallest version of QR code that will contain all of the provided data.
|
||||
*
|
||||
* @throws WriterException if the data cannot fit in any version
|
||||
*/
|
||||
fn recommend_version( ec_level: &ErrorCorrectionLevel, mode: &Mode, header_bits: &BitArray, data_bits: &BitArray) -> /* throws WriterException */Result<Version, Rc<Exception>> {
|
||||
// Hard part: need to know version to know how many bits length takes. But need to know how many
|
||||
// bits it takes to know version. First we take a guess at version by assuming version will be
|
||||
// the minimum, 1:
|
||||
let provisional_bits_needed: i32 = ::calculate_bits_needed(mode, header_bits, data_bits, &Version::get_version_for_number(1));
|
||||
let provisional_version: Version = ::choose_version(provisional_bits_needed, ec_level);
|
||||
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
|
||||
let bits_needed: i32 = ::calculate_bits_needed(mode, header_bits, data_bits, provisional_version);
|
||||
return Ok(::choose_version(bits_needed, ec_level));
|
||||
}
|
||||
|
||||
fn calculate_bits_needed( mode: &Mode, header_bits: &BitArray, data_bits: &BitArray, version: &Version) -> i32 {
|
||||
return header_bits.get_size() + mode.get_character_count_bits(version) + data_bits.get_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the code point of the table used in alphanumeric mode or
|
||||
* -1 if there is no corresponding code in the table.
|
||||
*/
|
||||
fn get_alphanumeric_code( code: i32) -> i32 {
|
||||
if code < ALPHANUMERIC_TABLE.len() {
|
||||
return ALPHANUMERIC_TABLE[code];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
pub fn choose_mode( content: &String) -> Mode {
|
||||
return ::choose_mode(&content, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
|
||||
* if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
|
||||
*/
|
||||
fn choose_mode( content: &String, encoding: &Charset) -> Mode {
|
||||
if StringUtils::SHIFT_JIS_CHARSET::equals(&encoding) && ::is_only_double_byte_kanji(&content) {
|
||||
// Choose Kanji mode if all input are double-byte characters
|
||||
return Mode::KANJI;
|
||||
}
|
||||
let has_numeric: bool = false;
|
||||
let has_alphanumeric: bool = false;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < content.length() {
|
||||
{
|
||||
let c: char = content.char_at(i);
|
||||
if c >= '0' && c <= '9' {
|
||||
has_numeric = true;
|
||||
} else if ::get_alphanumeric_code(c) != -1 {
|
||||
has_alphanumeric = true;
|
||||
} else {
|
||||
return Mode::BYTE;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if has_alphanumeric {
|
||||
return Mode::ALPHANUMERIC;
|
||||
}
|
||||
if has_numeric {
|
||||
return Mode::NUMERIC;
|
||||
}
|
||||
return Mode::BYTE;
|
||||
}
|
||||
|
||||
fn is_only_double_byte_kanji( content: &String) -> bool {
|
||||
let bytes: Vec<i8> = content.get_bytes(StringUtils::SHIFT_JIS_CHARSET);
|
||||
let length: i32 = bytes.len();
|
||||
if length % 2 != 0 {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
{
|
||||
let byte1: i32 = bytes[i] & 0xFF;
|
||||
if (byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn choose_mask_pattern( bits: &BitArray, ec_level: &ErrorCorrectionLevel, version: &Version, matrix: &ByteMatrix) -> /* throws WriterException */Result<i32, Rc<Exception>> {
|
||||
// Lower penalty is better.
|
||||
let min_penalty: i32 = Integer::MAX_VALUE;
|
||||
let best_mask_pattern: i32 = -1;
|
||||
// We try all mask patterns to choose the best one.
|
||||
{
|
||||
let mask_pattern: i32 = 0;
|
||||
while mask_pattern < QRCode.NUM_MASK_PATTERNS {
|
||||
{
|
||||
MatrixUtil::build_matrix(bits, ec_level, version, mask_pattern, matrix);
|
||||
let penalty: i32 = ::calculate_mask_penalty(matrix);
|
||||
if penalty < min_penalty {
|
||||
min_penalty = penalty;
|
||||
best_mask_pattern = mask_pattern;
|
||||
}
|
||||
}
|
||||
mask_pattern += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(best_mask_pattern);
|
||||
}
|
||||
|
||||
fn choose_version( num_input_bits: i32, ec_level: &ErrorCorrectionLevel) -> /* throws WriterException */Result<Version, Rc<Exception>> {
|
||||
{
|
||||
let version_num: i32 = 1;
|
||||
while version_num <= 40 {
|
||||
{
|
||||
let version: Version = Version::get_version_for_number(version_num);
|
||||
if ::will_fit(num_input_bits, version, ec_level) {
|
||||
return Ok(version);
|
||||
}
|
||||
}
|
||||
version_num += 1;
|
||||
}
|
||||
}
|
||||
|
||||
throw WriterException::new("Data too big");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the number of input bits will fit in a code with the specified version and
|
||||
* error correction level.
|
||||
*/
|
||||
fn will_fit( num_input_bits: i32, version: &Version, ec_level: &ErrorCorrectionLevel) -> bool {
|
||||
// In the following comments, we use numbers of Version 7-H.
|
||||
// numBytes = 196
|
||||
let num_bytes: i32 = version.get_total_codewords();
|
||||
// getNumECBytes = 130
|
||||
let ec_blocks: Version.ECBlocks = version.get_e_c_blocks_for_level(ec_level);
|
||||
let num_ec_bytes: i32 = ec_blocks.get_total_e_c_codewords();
|
||||
// getNumDataBytes = 196 - 130 = 66
|
||||
let num_data_bytes: i32 = num_bytes - num_ec_bytes;
|
||||
let total_input_bytes: i32 = (num_input_bits + 7) / 8;
|
||||
return num_data_bytes >= total_input_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
|
||||
*/
|
||||
fn terminate_bits( num_data_bytes: i32, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let capacity: i32 = num_data_bytes * 8;
|
||||
if bits.get_size() > capacity {
|
||||
throw WriterException::new(format!("data bits cannot fit in the QR Code{} > {}", bits.get_size(), capacity));
|
||||
}
|
||||
// Append Mode.TERMINATE if there is enough space (value is 0000)
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 4 && bits.get_size() < capacity {
|
||||
{
|
||||
bits.append_bit(false);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
|
||||
// If the last byte isn't 8-bit aligned, we'll add padding bits.
|
||||
let num_bits_in_last_byte: i32 = bits.get_size() & 0x07;
|
||||
if num_bits_in_last_byte > 0 {
|
||||
{
|
||||
let mut i: i32 = num_bits_in_last_byte;
|
||||
while i < 8 {
|
||||
{
|
||||
bits.append_bit(false);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
|
||||
let num_padding_bytes: i32 = num_data_bytes - bits.get_size_in_bytes();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_padding_bytes {
|
||||
{
|
||||
bits.append_bits( if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if bits.get_size() != capacity {
|
||||
throw WriterException::new("Bits size does not equal capacity");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of data bytes and number of error correction bytes for block id "blockID". Store
|
||||
* the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
|
||||
* JISX0510:2004 (p.30)
|
||||
*/
|
||||
fn get_num_data_bytes_and_num_e_c_bytes_for_block_i_d( num_total_bytes: i32, num_data_bytes: i32, num_r_s_blocks: i32, block_i_d: i32, num_data_bytes_in_block: &Vec<i32>, num_e_c_bytes_in_block: &Vec<i32>) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
if block_i_d >= num_r_s_blocks {
|
||||
throw WriterException::new("Block ID too large");
|
||||
}
|
||||
// numRsBlocksInGroup2 = 196 % 5 = 1
|
||||
let num_rs_blocks_in_group2: i32 = num_total_bytes % num_r_s_blocks;
|
||||
// numRsBlocksInGroup1 = 5 - 1 = 4
|
||||
let num_rs_blocks_in_group1: i32 = num_r_s_blocks - num_rs_blocks_in_group2;
|
||||
// numTotalBytesInGroup1 = 196 / 5 = 39
|
||||
let num_total_bytes_in_group1: i32 = num_total_bytes / num_r_s_blocks;
|
||||
// numTotalBytesInGroup2 = 39 + 1 = 40
|
||||
let num_total_bytes_in_group2: i32 = num_total_bytes_in_group1 + 1;
|
||||
// numDataBytesInGroup1 = 66 / 5 = 13
|
||||
let num_data_bytes_in_group1: i32 = num_data_bytes / num_r_s_blocks;
|
||||
// numDataBytesInGroup2 = 13 + 1 = 14
|
||||
let num_data_bytes_in_group2: i32 = num_data_bytes_in_group1 + 1;
|
||||
// numEcBytesInGroup1 = 39 - 13 = 26
|
||||
let num_ec_bytes_in_group1: i32 = num_total_bytes_in_group1 - num_data_bytes_in_group1;
|
||||
// numEcBytesInGroup2 = 40 - 14 = 26
|
||||
let num_ec_bytes_in_group2: i32 = num_total_bytes_in_group2 - num_data_bytes_in_group2;
|
||||
// 26 = 26
|
||||
if num_ec_bytes_in_group1 != num_ec_bytes_in_group2 {
|
||||
throw WriterException::new("EC bytes mismatch");
|
||||
}
|
||||
// 5 = 4 + 1.
|
||||
if num_r_s_blocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2 {
|
||||
throw WriterException::new("RS blocks mismatch");
|
||||
}
|
||||
// 196 = (13 + 26) * 4 + (14 + 26) * 1
|
||||
if num_total_bytes != ((num_data_bytes_in_group1 + num_ec_bytes_in_group1) * num_rs_blocks_in_group1) + ((num_data_bytes_in_group2 + num_ec_bytes_in_group2) * num_rs_blocks_in_group2) {
|
||||
throw WriterException::new("Total bytes mismatch");
|
||||
}
|
||||
if block_i_d < num_rs_blocks_in_group1 {
|
||||
num_data_bytes_in_block[0] = num_data_bytes_in_group1;
|
||||
num_e_c_bytes_in_block[0] = num_ec_bytes_in_group1;
|
||||
} else {
|
||||
num_data_bytes_in_block[0] = num_data_bytes_in_group2;
|
||||
num_e_c_bytes_in_block[0] = num_ec_bytes_in_group2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interleave "bits" with corresponding error correction bytes. On success, store the result in
|
||||
* "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
|
||||
*/
|
||||
fn interleave_with_e_c_bytes( bits: &BitArray, num_total_bytes: i32, num_data_bytes: i32, num_r_s_blocks: i32) -> /* throws WriterException */Result<BitArray, Rc<Exception>> {
|
||||
// "bits" must have "getNumDataBytes" bytes of data.
|
||||
if bits.get_size_in_bytes() != num_data_bytes {
|
||||
throw WriterException::new("Number of bits and data bytes does not match");
|
||||
}
|
||||
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
|
||||
// store the divided data bytes blocks and error correction bytes blocks into "blocks".
|
||||
let data_bytes_offset: i32 = 0;
|
||||
let max_num_data_bytes: i32 = 0;
|
||||
let max_num_ec_bytes: i32 = 0;
|
||||
// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
|
||||
let blocks: Collection<BlockPair> = ArrayList<>::new(num_r_s_blocks);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_r_s_blocks {
|
||||
{
|
||||
let num_data_bytes_in_block: [i32; 1] = [0; 1];
|
||||
let num_ec_bytes_in_block: [i32; 1] = [0; 1];
|
||||
::get_num_data_bytes_and_num_e_c_bytes_for_block_i_d(num_total_bytes, num_data_bytes, num_r_s_blocks, i, &num_data_bytes_in_block, &num_ec_bytes_in_block);
|
||||
let size: i32 = num_data_bytes_in_block[0];
|
||||
let data_bytes: [i8; size] = [0; size];
|
||||
bits.to_bytes(8 * data_bytes_offset, &data_bytes, 0, size);
|
||||
let ec_bytes: Vec<i8> = ::generate_e_c_bytes(&data_bytes, num_ec_bytes_in_block[0]);
|
||||
blocks.add(BlockPair::new(&data_bytes, &ec_bytes));
|
||||
max_num_data_bytes = Math::max(max_num_data_bytes, size);
|
||||
max_num_ec_bytes = Math::max(max_num_ec_bytes, ec_bytes.len());
|
||||
data_bytes_offset += num_data_bytes_in_block[0];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if num_data_bytes != data_bytes_offset {
|
||||
throw WriterException::new("Data bytes does not match offset");
|
||||
}
|
||||
let result: BitArray = BitArray::new();
|
||||
// First, place data blocks.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max_num_data_bytes {
|
||||
{
|
||||
for let block: BlockPair in blocks {
|
||||
let data_bytes: Vec<i8> = block.get_data_bytes();
|
||||
if i < data_bytes.len() {
|
||||
result.append_bits(data_bytes[i], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Then, place error correction blocks.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max_num_ec_bytes {
|
||||
{
|
||||
for let block: BlockPair in blocks {
|
||||
let ec_bytes: Vec<i8> = block.get_error_correction_bytes();
|
||||
if i < ec_bytes.len() {
|
||||
result.append_bits(ec_bytes[i], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if num_total_bytes != result.get_size_in_bytes() {
|
||||
// Should be same.
|
||||
throw WriterException::new(format!("Interleaving error: {} and {} differ.", num_total_bytes, result.get_size_in_bytes()));
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
fn generate_e_c_bytes( data_bytes: &Vec<i8>, num_ec_bytes_in_block: i32) -> Vec<i8> {
|
||||
let num_data_bytes: i32 = data_bytes.len();
|
||||
let to_encode: [i32; num_data_bytes + num_ec_bytes_in_block] = [0; num_data_bytes + num_ec_bytes_in_block];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_data_bytes {
|
||||
{
|
||||
to_encode[i] = data_bytes[i] & 0xFF;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
ReedSolomonEncoder::new(GenericGF::QR_CODE_FIELD_256).encode(&to_encode, num_ec_bytes_in_block);
|
||||
let ec_bytes: [i8; num_ec_bytes_in_block] = [0; num_ec_bytes_in_block];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < num_ec_bytes_in_block {
|
||||
{
|
||||
ec_bytes[i] = to_encode[num_data_bytes + i] as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ec_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append mode info. On success, store the result in "bits".
|
||||
*/
|
||||
fn append_mode_info( mode: &Mode, bits: &BitArray) {
|
||||
bits.append_bits(&mode.get_bits(), 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append length info. On success, store the result in "bits".
|
||||
*/
|
||||
fn append_length_info( num_letters: i32, version: &Version, mode: &Mode, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let num_bits: i32 = mode.get_character_count_bits(version);
|
||||
if num_letters >= (1 << num_bits) {
|
||||
throw WriterException::new(format!("{} is bigger than {}", num_letters, ((1 << num_bits) - 1)));
|
||||
}
|
||||
bits.append_bits(num_letters, num_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
|
||||
*/
|
||||
fn append_bytes( content: &String, mode: &Mode, bits: &BitArray, encoding: &Charset) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
match mode {
|
||||
NUMERIC =>
|
||||
{
|
||||
::append_numeric_bytes(&content, bits);
|
||||
break;
|
||||
}
|
||||
ALPHANUMERIC =>
|
||||
{
|
||||
::append_alphanumeric_bytes(&content, bits);
|
||||
break;
|
||||
}
|
||||
BYTE =>
|
||||
{
|
||||
::append8_bit_bytes(&content, bits, &encoding);
|
||||
break;
|
||||
}
|
||||
KANJI =>
|
||||
{
|
||||
::append_kanji_bytes(&content, bits);
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw WriterException::new(format!("Invalid mode: {}", mode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn append_numeric_bytes( content: &CharSequence, bits: &BitArray) {
|
||||
let length: i32 = content.length();
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
let num1: i32 = content.char_at(i) - '0';
|
||||
if i + 2 < length {
|
||||
// Encode three numeric letters in ten bits.
|
||||
let num2: i32 = content.char_at(i + 1) - '0';
|
||||
let num3: i32 = content.char_at(i + 2) - '0';
|
||||
bits.append_bits(num1 * 100 + num2 * 10 + num3, 10);
|
||||
i += 3;
|
||||
} else if i + 1 < length {
|
||||
// Encode two numeric letters in seven bits.
|
||||
let num2: i32 = content.char_at(i + 1) - '0';
|
||||
bits.append_bits(num1 * 10 + num2, 7);
|
||||
i += 2;
|
||||
} else {
|
||||
// Encode one numeric letter in four bits.
|
||||
bits.append_bits(num1, 4);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn append_alphanumeric_bytes( content: &CharSequence, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let length: i32 = content.length();
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
let code1: i32 = ::get_alphanumeric_code(&content.char_at(i));
|
||||
if code1 == -1 {
|
||||
throw WriterException::new();
|
||||
}
|
||||
if i + 1 < length {
|
||||
let code2: i32 = ::get_alphanumeric_code(&content.char_at(i + 1));
|
||||
if code2 == -1 {
|
||||
throw WriterException::new();
|
||||
}
|
||||
// Encode two alphanumeric letters in 11 bits.
|
||||
bits.append_bits(code1 * 45 + code2, 11);
|
||||
i += 2;
|
||||
} else {
|
||||
// Encode one alphanumeric letter in six bits.
|
||||
bits.append_bits(code1, 6);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn append8_bit_bytes( content: &String, bits: &BitArray, encoding: &Charset) {
|
||||
let bytes: Vec<i8> = content.get_bytes(&encoding);
|
||||
for let b: i8 in bytes {
|
||||
bits.append_bits(b, 8);
|
||||
}
|
||||
}
|
||||
|
||||
fn append_kanji_bytes( content: &String, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let bytes: Vec<i8> = content.get_bytes(StringUtils::SHIFT_JIS_CHARSET);
|
||||
if bytes.len() % 2 != 0 {
|
||||
throw WriterException::new("Kanji byte size not even");
|
||||
}
|
||||
// bytes.length must be even
|
||||
let max_i: i32 = bytes.len() - 1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < max_i {
|
||||
{
|
||||
let byte1: i32 = bytes[i] & 0xFF;
|
||||
let byte2: i32 = bytes[i + 1] & 0xFF;
|
||||
let code: i32 = (byte1 << 8) | byte2;
|
||||
let mut subtracted: i32 = -1;
|
||||
if code >= 0x8140 && code <= 0x9ffc {
|
||||
subtracted = code - 0x8140;
|
||||
} else if code >= 0xe040 && code <= 0xebbf {
|
||||
subtracted = code - 0xc140;
|
||||
}
|
||||
if subtracted == -1 {
|
||||
throw WriterException::new("Invalid byte sequence");
|
||||
}
|
||||
let encoded: i32 = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
|
||||
bits.append_bits(encoded, 13);
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn append_e_c_i( eci: &CharacterSetECI, bits: &BitArray) {
|
||||
bits.append_bits(&Mode::ECI::get_bits(), 4);
|
||||
// This is correct for values up to 127, which is all we need now.
|
||||
bits.append_bits(&eci.get_value(), 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,303 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
/**
|
||||
* @author Satoru Takabayashi
|
||||
* @author Daniel Switkin
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
// Penalty weights from section 6.8.2.1
|
||||
const N1: i32 = 3;
|
||||
|
||||
const N2: i32 = 3;
|
||||
|
||||
const N3: i32 = 40;
|
||||
|
||||
const N4: i32 = 10;
|
||||
struct MaskUtil {
|
||||
}
|
||||
|
||||
impl MaskUtil {
|
||||
|
||||
fn new() -> MaskUtil {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
|
||||
* give penalty to them. Example: 00000 or 11111.
|
||||
*/
|
||||
fn apply_mask_penalty_rule1( matrix: &ByteMatrix) -> i32 {
|
||||
return ::apply_mask_penalty_rule1_internal(matrix, true) + ::apply_mask_penalty_rule1_internal(matrix, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
|
||||
* penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a
|
||||
* penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block.
|
||||
*/
|
||||
fn apply_mask_penalty_rule2( matrix: &ByteMatrix) -> i32 {
|
||||
let mut penalty: i32 = 0;
|
||||
let array: Vec<Vec<i8>> = matrix.get_array();
|
||||
let width: i32 = matrix.get_width();
|
||||
let height: i32 = matrix.get_height();
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < height - 1 {
|
||||
{
|
||||
let array_y: Vec<i8> = array[y];
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < width - 1 {
|
||||
{
|
||||
let value: i32 = array_y[x];
|
||||
if value == array_y[x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1] {
|
||||
penalty += 1;
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return N2 * penalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4
|
||||
* starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we
|
||||
* find patterns like 000010111010000, we give penalty once.
|
||||
*/
|
||||
fn apply_mask_penalty_rule3( matrix: &ByteMatrix) -> i32 {
|
||||
let num_penalties: i32 = 0;
|
||||
let array: Vec<Vec<i8>> = matrix.get_array();
|
||||
let width: i32 = matrix.get_width();
|
||||
let height: i32 = matrix.get_height();
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < height {
|
||||
{
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < width {
|
||||
{
|
||||
// We can at least optimize this access
|
||||
let array_y: Vec<i8> = array[y];
|
||||
if x + 6 < width && array_y[x] == 1 && array_y[x + 1] == 0 && array_y[x + 2] == 1 && array_y[x + 3] == 1 && array_y[x + 4] == 1 && array_y[x + 5] == 0 && array_y[x + 6] == 1 && (::is_white_horizontal(&array_y, x - 4, x) || ::is_white_horizontal(&array_y, x + 7, x + 11)) {
|
||||
num_penalties += 1;
|
||||
}
|
||||
if y + 6 < height && array[y][x] == 1 && array[y + 1][x] == 0 && array[y + 2][x] == 1 && array[y + 3][x] == 1 && array[y + 4][x] == 1 && array[y + 5][x] == 0 && array[y + 6][x] == 1 && (::is_white_vertical(&array, x, y - 4, y) || ::is_white_vertical(&array, x, y + 7, y + 11)) {
|
||||
num_penalties += 1;
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return num_penalties * N3;
|
||||
}
|
||||
|
||||
fn is_white_horizontal( row_array: &Vec<i8>, from: i32, to: i32) -> bool {
|
||||
if from < 0 || row_array.len() < to {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = from;
|
||||
while i < to {
|
||||
{
|
||||
if row_array[i] == 1 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn is_white_vertical( array: &Vec<Vec<i8>>, col: i32, from: i32, to: i32) -> bool {
|
||||
if from < 0 || array.len() < to {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = from;
|
||||
while i < to {
|
||||
{
|
||||
if array[i][col] == 1 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
|
||||
* penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance.
|
||||
*/
|
||||
fn apply_mask_penalty_rule4( matrix: &ByteMatrix) -> i32 {
|
||||
let num_dark_cells: i32 = 0;
|
||||
let array: Vec<Vec<i8>> = matrix.get_array();
|
||||
let width: i32 = matrix.get_width();
|
||||
let height: i32 = matrix.get_height();
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < height {
|
||||
{
|
||||
let array_y: Vec<i8> = array[y];
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < width {
|
||||
{
|
||||
if array_y[x] == 1 {
|
||||
num_dark_cells += 1;
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let num_total_cells: i32 = matrix.get_height() * matrix.get_width();
|
||||
let five_percent_variances: i32 = Math::abs(num_dark_cells * 2 - num_total_cells) * 10 / num_total_cells;
|
||||
return five_percent_variances * N4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
|
||||
* pattern conditions.
|
||||
*/
|
||||
fn get_data_mask_bit( mask_pattern: i32, x: i32, y: i32) -> bool {
|
||||
let mut intermediate: i32;
|
||||
let mut temp: i32;
|
||||
match mask_pattern {
|
||||
0 =>
|
||||
{
|
||||
intermediate = (y + x) & 0x1;
|
||||
break;
|
||||
}
|
||||
1 =>
|
||||
{
|
||||
intermediate = y & 0x1;
|
||||
break;
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
intermediate = x % 3;
|
||||
break;
|
||||
}
|
||||
3 =>
|
||||
{
|
||||
intermediate = (y + x) % 3;
|
||||
break;
|
||||
}
|
||||
4 =>
|
||||
{
|
||||
intermediate = ((y / 2) + (x / 3)) & 0x1;
|
||||
break;
|
||||
}
|
||||
5 =>
|
||||
{
|
||||
temp = y * x;
|
||||
intermediate = (temp & 0x1) + (temp % 3);
|
||||
break;
|
||||
}
|
||||
6 =>
|
||||
{
|
||||
temp = y * x;
|
||||
intermediate = ((temp & 0x1) + (temp % 3)) & 0x1;
|
||||
break;
|
||||
}
|
||||
7 =>
|
||||
{
|
||||
temp = y * x;
|
||||
intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalArgumentException::new(format!("Invalid mask pattern: {}", mask_pattern));
|
||||
}
|
||||
}
|
||||
return intermediate == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
|
||||
* vertical and horizontal orders respectively.
|
||||
*/
|
||||
fn apply_mask_penalty_rule1_internal( matrix: &ByteMatrix, is_horizontal: bool) -> i32 {
|
||||
let mut penalty: i32 = 0;
|
||||
let i_limit: i32 = if is_horizontal { matrix.get_height() } else { matrix.get_width() };
|
||||
let j_limit: i32 = if is_horizontal { matrix.get_width() } else { matrix.get_height() };
|
||||
let array: Vec<Vec<i8>> = matrix.get_array();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < i_limit {
|
||||
{
|
||||
let num_same_bit_cells: i32 = 0;
|
||||
let prev_bit: i32 = -1;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < j_limit {
|
||||
{
|
||||
let bit: i32 = if is_horizontal { array[i][j] } else { array[j][i] };
|
||||
if bit == prev_bit {
|
||||
num_same_bit_cells += 1;
|
||||
} else {
|
||||
if num_same_bit_cells >= 5 {
|
||||
penalty += N1 + (num_same_bit_cells - 5);
|
||||
}
|
||||
// Include the cell itself.
|
||||
num_same_bit_cells = 1;
|
||||
prev_bit = bit;
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if num_same_bit_cells >= 5 {
|
||||
penalty += N1 + (num_same_bit_cells - 5);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return penalty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,574 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
|
||||
*/
|
||||
|
||||
const POSITION_DETECTION_PATTERN: vec![vec![Vec<Vec<i32>>; 7]; 7] = vec![vec![1, 1, 1, 1, 1, 1, 1, ]
|
||||
, vec![1, 0, 0, 0, 0, 0, 1, ]
|
||||
, vec![1, 0, 1, 1, 1, 0, 1, ]
|
||||
, vec![1, 0, 1, 1, 1, 0, 1, ]
|
||||
, vec![1, 0, 1, 1, 1, 0, 1, ]
|
||||
, vec![1, 0, 0, 0, 0, 0, 1, ]
|
||||
, vec![1, 1, 1, 1, 1, 1, 1, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
const POSITION_ADJUSTMENT_PATTERN: vec![vec![Vec<Vec<i32>>; 5]; 5] = vec![vec![1, 1, 1, 1, 1, ]
|
||||
, vec![1, 0, 0, 0, 1, ]
|
||||
, vec![1, 0, 1, 0, 1, ]
|
||||
, vec![1, 0, 0, 0, 1, ]
|
||||
, vec![1, 1, 1, 1, 1, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
// From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu.
|
||||
const POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE: vec![vec![Vec<Vec<i32>>; 7]; 40] = vec![// Version 1
|
||||
vec![-1, -1, -1, -1, -1, -1, -1, ]
|
||||
, // Version 2
|
||||
vec![6, 18, -1, -1, -1, -1, -1, ]
|
||||
, // Version 3
|
||||
vec![6, 22, -1, -1, -1, -1, -1, ]
|
||||
, // Version 4
|
||||
vec![6, 26, -1, -1, -1, -1, -1, ]
|
||||
, // Version 5
|
||||
vec![6, 30, -1, -1, -1, -1, -1, ]
|
||||
, // Version 6
|
||||
vec![6, 34, -1, -1, -1, -1, -1, ]
|
||||
, // Version 7
|
||||
vec![6, 22, 38, -1, -1, -1, -1, ]
|
||||
, // Version 8
|
||||
vec![6, 24, 42, -1, -1, -1, -1, ]
|
||||
, // Version 9
|
||||
vec![6, 26, 46, -1, -1, -1, -1, ]
|
||||
, // Version 10
|
||||
vec![6, 28, 50, -1, -1, -1, -1, ]
|
||||
, // Version 11
|
||||
vec![6, 30, 54, -1, -1, -1, -1, ]
|
||||
, // Version 12
|
||||
vec![6, 32, 58, -1, -1, -1, -1, ]
|
||||
, // Version 13
|
||||
vec![6, 34, 62, -1, -1, -1, -1, ]
|
||||
, // Version 14
|
||||
vec![6, 26, 46, 66, -1, -1, -1, ]
|
||||
, // Version 15
|
||||
vec![6, 26, 48, 70, -1, -1, -1, ]
|
||||
, // Version 16
|
||||
vec![6, 26, 50, 74, -1, -1, -1, ]
|
||||
, // Version 17
|
||||
vec![6, 30, 54, 78, -1, -1, -1, ]
|
||||
, // Version 18
|
||||
vec![6, 30, 56, 82, -1, -1, -1, ]
|
||||
, // Version 19
|
||||
vec![6, 30, 58, 86, -1, -1, -1, ]
|
||||
, // Version 20
|
||||
vec![6, 34, 62, 90, -1, -1, -1, ]
|
||||
, // Version 21
|
||||
vec![6, 28, 50, 72, 94, -1, -1, ]
|
||||
, // Version 22
|
||||
vec![6, 26, 50, 74, 98, -1, -1, ]
|
||||
, // Version 23
|
||||
vec![6, 30, 54, 78, 102, -1, -1, ]
|
||||
, // Version 24
|
||||
vec![6, 28, 54, 80, 106, -1, -1, ]
|
||||
, // Version 25
|
||||
vec![6, 32, 58, 84, 110, -1, -1, ]
|
||||
, // Version 26
|
||||
vec![6, 30, 58, 86, 114, -1, -1, ]
|
||||
, // Version 27
|
||||
vec![6, 34, 62, 90, 118, -1, -1, ]
|
||||
, // Version 28
|
||||
vec![6, 26, 50, 74, 98, 122, -1, ]
|
||||
, // Version 29
|
||||
vec![6, 30, 54, 78, 102, 126, -1, ]
|
||||
, // Version 30
|
||||
vec![6, 26, 52, 78, 104, 130, -1, ]
|
||||
, // Version 31
|
||||
vec![6, 30, 56, 82, 108, 134, -1, ]
|
||||
, // Version 32
|
||||
vec![6, 34, 60, 86, 112, 138, -1, ]
|
||||
, // Version 33
|
||||
vec![6, 30, 58, 86, 114, 142, -1, ]
|
||||
, // Version 34
|
||||
vec![6, 34, 62, 90, 118, 146, -1, ]
|
||||
, // Version 35
|
||||
vec![6, 30, 54, 78, 102, 126, 150, ]
|
||||
, // Version 36
|
||||
vec![6, 24, 50, 76, 102, 128, 154, ]
|
||||
, // Version 37
|
||||
vec![6, 28, 54, 80, 106, 132, 158, ]
|
||||
, // Version 38
|
||||
vec![6, 32, 58, 84, 110, 136, 162, ]
|
||||
, // Version 39
|
||||
vec![6, 26, 54, 82, 110, 138, 166, ]
|
||||
, // Version 40
|
||||
vec![6, 30, 58, 86, 114, 142, 170, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
// Type info cells at the left top corner.
|
||||
const TYPE_INFO_COORDINATES: vec![vec![Vec<Vec<i32>>; 2]; 15] = vec![vec![8, 0, ]
|
||||
, vec![8, 1, ]
|
||||
, vec![8, 2, ]
|
||||
, vec![8, 3, ]
|
||||
, vec![8, 4, ]
|
||||
, vec![8, 5, ]
|
||||
, vec![8, 7, ]
|
||||
, vec![8, 8, ]
|
||||
, vec![7, 8, ]
|
||||
, vec![5, 8, ]
|
||||
, vec![4, 8, ]
|
||||
, vec![3, 8, ]
|
||||
, vec![2, 8, ]
|
||||
, vec![1, 8, ]
|
||||
, vec![0, 8, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
// From Appendix D in JISX0510:2004 (p. 67)
|
||||
// 1 1111 0010 0101
|
||||
const VERSION_INFO_POLY: i32 = 0x1f25;
|
||||
|
||||
// From Appendix C in JISX0510:2004 (p.65).
|
||||
const TYPE_INFO_POLY: i32 = 0x537;
|
||||
|
||||
const TYPE_INFO_MASK_PATTERN: i32 = 0x5412;
|
||||
struct MatrixUtil {
|
||||
}
|
||||
|
||||
impl MatrixUtil {
|
||||
|
||||
fn new() -> MatrixUtil {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// Set all cells to -1. -1 means that the cell is empty (not set yet).
|
||||
//
|
||||
// JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding
|
||||
// with the ByteMatrix initialized all to zero.
|
||||
fn clear_matrix( matrix: &ByteMatrix) {
|
||||
matrix.clear(-1 as i8);
|
||||
}
|
||||
|
||||
// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
|
||||
// success, store the result in "matrix" and return true.
|
||||
fn build_matrix( data_bits: &BitArray, ec_level: &ErrorCorrectionLevel, version: &Version, mask_pattern: i32, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
::clear_matrix(matrix);
|
||||
::embed_basic_patterns(version, matrix);
|
||||
// Type information appear with any version.
|
||||
::embed_type_info(ec_level, mask_pattern, matrix);
|
||||
// Version info appear if version >= 7.
|
||||
::maybe_embed_version_info(version, matrix);
|
||||
// Data should be embedded at end.
|
||||
::embed_data_bits(data_bits, mask_pattern, matrix);
|
||||
}
|
||||
|
||||
// Embed basic patterns. On success, modify the matrix and return true.
|
||||
// The basic patterns are:
|
||||
// - Position detection patterns
|
||||
// - Timing patterns
|
||||
// - Dark dot at the left bottom corner
|
||||
// - Position adjustment patterns, if need be
|
||||
fn embed_basic_patterns( version: &Version, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
// Let's get started with embedding big squares at corners.
|
||||
::embed_position_detection_patterns_and_separators(matrix);
|
||||
// Then, embed the dark dot at the left bottom corner.
|
||||
::embed_dark_dot_at_left_bottom_corner(matrix);
|
||||
// Position adjustment patterns appear if version >= 2.
|
||||
::maybe_embed_position_adjustment_patterns(version, matrix);
|
||||
// Timing patterns should be embedded after position adj. patterns.
|
||||
::embed_timing_patterns(matrix);
|
||||
}
|
||||
|
||||
// Embed type information. On success, modify the matrix.
|
||||
fn embed_type_info( ec_level: &ErrorCorrectionLevel, mask_pattern: i32, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let type_info_bits: BitArray = BitArray::new();
|
||||
::make_type_info_bits(ec_level, mask_pattern, type_info_bits);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < type_info_bits.get_size() {
|
||||
{
|
||||
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
|
||||
// "typeInfoBits".
|
||||
let bit: bool = type_info_bits.get(type_info_bits.get_size() - 1 - i);
|
||||
// Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
|
||||
let coordinates: Vec<i32> = TYPE_INFO_COORDINATES[i];
|
||||
let x1: i32 = coordinates[0];
|
||||
let y1: i32 = coordinates[1];
|
||||
matrix.set(x1, y1, bit);
|
||||
let mut x2: i32;
|
||||
let mut y2: i32;
|
||||
if i < 8 {
|
||||
// Right top corner.
|
||||
x2 = matrix.get_width() - i - 1;
|
||||
y2 = 8;
|
||||
} else {
|
||||
// Left bottom corner.
|
||||
x2 = 8;
|
||||
y2 = matrix.get_height() - 7 + (i - 8);
|
||||
}
|
||||
matrix.set(x2, y2, bit);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Embed version information if need be. On success, modify the matrix and return true.
|
||||
// See 8.10 of JISX0510:2004 (p.47) for how to embed version information.
|
||||
fn maybe_embed_version_info( version: &Version, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
if version.get_version_number() < 7 {
|
||||
// Don't need version info.
|
||||
return;
|
||||
}
|
||||
let version_info_bits: BitArray = BitArray::new();
|
||||
::make_version_info_bits(version, version_info_bits);
|
||||
// It will decrease from 17 to 0.
|
||||
let bit_index: i32 = 6 * 3 - 1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 6 {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < 3 {
|
||||
{
|
||||
// Place bits in LSB (least significant bit) to MSB order.
|
||||
let bit: bool = version_info_bits.get(bit_index);
|
||||
bit_index -= 1;
|
||||
// Left bottom corner.
|
||||
matrix.set(i, matrix.get_height() - 11 + j, bit);
|
||||
// Right bottom corner.
|
||||
matrix.set(matrix.get_height() - 11 + j, i, bit);
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
|
||||
// For debugging purposes, it skips masking process if "getMaskPattern" is -1.
|
||||
// See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
|
||||
fn embed_data_bits( data_bits: &BitArray, mask_pattern: i32, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let bit_index: i32 = 0;
|
||||
let mut direction: i32 = -1;
|
||||
// Start from the right bottom cell.
|
||||
let mut x: i32 = matrix.get_width() - 1;
|
||||
let mut y: i32 = matrix.get_height() - 1;
|
||||
while x > 0 {
|
||||
// Skip the vertical timing pattern.
|
||||
if x == 6 {
|
||||
x -= 1;
|
||||
}
|
||||
while y >= 0 && y < matrix.get_height() {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 2 {
|
||||
{
|
||||
let xx: i32 = x - i;
|
||||
// Skip the cell if it's not empty.
|
||||
if !::is_empty(&matrix.get(xx, y)) {
|
||||
continue;
|
||||
}
|
||||
let mut bit: bool;
|
||||
if bit_index < data_bits.get_size() {
|
||||
bit = data_bits.get(bit_index);
|
||||
bit_index += 1;
|
||||
} else {
|
||||
// Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
|
||||
// in 8.4.9 of JISX0510:2004 (p. 24).
|
||||
bit = false;
|
||||
}
|
||||
// Skip masking if mask_pattern is -1.
|
||||
if mask_pattern != -1 && MaskUtil::get_data_mask_bit(mask_pattern, xx, y) {
|
||||
bit = !bit;
|
||||
}
|
||||
matrix.set(xx, y, bit);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
y += direction;
|
||||
}
|
||||
// Reverse the direction.
|
||||
direction = -direction;
|
||||
y += direction;
|
||||
// Move to the left.
|
||||
x -= 2;
|
||||
}
|
||||
// All bits should be consumed.
|
||||
if bit_index != data_bits.get_size() {
|
||||
throw WriterException::new(format!("Not all bits consumed: {}/{}", bit_index, data_bits.get_size()));
|
||||
}
|
||||
}
|
||||
|
||||
// Return the position of the most significant bit set (to one) in the "value". The most
|
||||
// significant bit is position 32. If there is no bit set, return 0. Examples:
|
||||
// - findMSBSet(0) => 0
|
||||
// - findMSBSet(1) => 1
|
||||
// - findMSBSet(255) => 8
|
||||
fn find_m_s_b_set( value: i32) -> i32 {
|
||||
return 32 - Integer::number_of_leading_zeros(value);
|
||||
}
|
||||
|
||||
// Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH
|
||||
// code is used for encoding type information and version information.
|
||||
// Example: Calculation of version information of 7.
|
||||
// f(x) is created from 7.
|
||||
// - 7 = 000111 in 6 bits
|
||||
// - f(x) = x^2 + x^1 + x^0
|
||||
// g(x) is given by the standard (p. 67)
|
||||
// - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
|
||||
// Multiply f(x) by x^(18 - 6)
|
||||
// - f'(x) = f(x) * x^(18 - 6)
|
||||
// - f'(x) = x^14 + x^13 + x^12
|
||||
// Calculate the remainder of f'(x) / g(x)
|
||||
// x^2
|
||||
// __________________________________________________
|
||||
// g(x) )x^14 + x^13 + x^12
|
||||
// x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2
|
||||
// --------------------------------------------------
|
||||
// x^11 + x^10 + x^7 + x^4 + x^2
|
||||
//
|
||||
// The remainder is x^11 + x^10 + x^7 + x^4 + x^2
|
||||
// Encode it in binary: 110010010100
|
||||
// The return value is 0xc94 (1100 1001 0100)
|
||||
//
|
||||
// Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit
|
||||
// operations. We don't care if coefficients are positive or negative.
|
||||
fn calculate_b_c_h_code( value: i32, poly: i32) -> i32 {
|
||||
if poly == 0 {
|
||||
throw IllegalArgumentException::new("0 polynomial");
|
||||
}
|
||||
// If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
|
||||
// from 13 to make it 12.
|
||||
let msb_set_in_poly: i32 = ::find_m_s_b_set(poly);
|
||||
value <<= msb_set_in_poly - 1;
|
||||
// Do the division business using exclusive-or operations.
|
||||
while ::find_m_s_b_set(value) >= msb_set_in_poly {
|
||||
value ^= poly << (::find_m_s_b_set(value) - msb_set_in_poly);
|
||||
}
|
||||
// Now the "value" is the remainder (i.e. the BCH code)
|
||||
return value;
|
||||
}
|
||||
|
||||
// Make bit vector of type information. On success, store the result in "bits" and return true.
|
||||
// Encode error correction level and mask pattern. See 8.9 of
|
||||
// JISX0510:2004 (p.45) for details.
|
||||
fn make_type_info_bits( ec_level: &ErrorCorrectionLevel, mask_pattern: i32, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
if !QRCode::is_valid_mask_pattern(mask_pattern) {
|
||||
throw WriterException::new("Invalid mask pattern");
|
||||
}
|
||||
let type_info: i32 = (ec_level.get_bits() << 3) | mask_pattern;
|
||||
bits.append_bits(type_info, 5);
|
||||
let bch_code: i32 = ::calculate_b_c_h_code(type_info, TYPE_INFO_POLY);
|
||||
bits.append_bits(bch_code, 10);
|
||||
let mask_bits: BitArray = BitArray::new();
|
||||
mask_bits.append_bits(TYPE_INFO_MASK_PATTERN, 15);
|
||||
bits.xor(mask_bits);
|
||||
if bits.get_size() != 15 {
|
||||
// Just in case.
|
||||
throw WriterException::new(format!("should not happen but we got: {}", bits.get_size()));
|
||||
}
|
||||
}
|
||||
|
||||
// Make bit vector of version information. On success, store the result in "bits" and return true.
|
||||
// See 8.10 of JISX0510:2004 (p.45) for details.
|
||||
fn make_version_info_bits( version: &Version, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
bits.append_bits(&version.get_version_number(), 6);
|
||||
let bch_code: i32 = ::calculate_b_c_h_code(&version.get_version_number(), VERSION_INFO_POLY);
|
||||
bits.append_bits(bch_code, 12);
|
||||
if bits.get_size() != 18 {
|
||||
// Just in case.
|
||||
throw WriterException::new(format!("should not happen but we got: {}", bits.get_size()));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if "value" is empty.
|
||||
fn is_empty( value: i32) -> bool {
|
||||
return value == -1;
|
||||
}
|
||||
|
||||
fn embed_timing_patterns( matrix: &ByteMatrix) {
|
||||
// separation patterns (size 1). Thus, 8 = 7 + 1.
|
||||
{
|
||||
let mut i: i32 = 8;
|
||||
while i < matrix.get_width() - 8 {
|
||||
{
|
||||
let bit: i32 = (i + 1) % 2;
|
||||
// Horizontal line.
|
||||
if ::is_empty(&matrix.get(i, 6)) {
|
||||
matrix.set(i, 6, bit);
|
||||
}
|
||||
// Vertical line.
|
||||
if ::is_empty(&matrix.get(6, i)) {
|
||||
matrix.set(6, i, bit);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)
|
||||
fn embed_dark_dot_at_left_bottom_corner( matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
if matrix.get(8, matrix.get_height() - 8) == 0 {
|
||||
throw WriterException::new();
|
||||
}
|
||||
matrix.set(8, matrix.get_height() - 8, 1);
|
||||
}
|
||||
|
||||
fn embed_horizontal_separation_pattern( x_start: i32, y_start: i32, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < 8 {
|
||||
{
|
||||
if !::is_empty(&matrix.get(x_start + x, y_start)) {
|
||||
throw WriterException::new();
|
||||
}
|
||||
matrix.set(x_start + x, y_start, 0);
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn embed_vertical_separation_pattern( x_start: i32, y_start: i32, matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < 7 {
|
||||
{
|
||||
if !::is_empty(&matrix.get(x_start, y_start + y)) {
|
||||
throw WriterException::new();
|
||||
}
|
||||
matrix.set(x_start, y_start + y, 0);
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn embed_position_adjustment_pattern( x_start: i32, y_start: i32, matrix: &ByteMatrix) {
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < 5 {
|
||||
{
|
||||
let pattern_y: Vec<i32> = POSITION_ADJUSTMENT_PATTERN[y];
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < 5 {
|
||||
{
|
||||
matrix.set(x_start + x, y_start + y, pattern_y[x]);
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn embed_position_detection_pattern( x_start: i32, y_start: i32, matrix: &ByteMatrix) {
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < 7 {
|
||||
{
|
||||
let pattern_y: Vec<i32> = POSITION_DETECTION_PATTERN[y];
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < 7 {
|
||||
{
|
||||
matrix.set(x_start + x, y_start + y, pattern_y[x]);
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Embed position detection patterns and surrounding vertical/horizontal separators.
|
||||
fn embed_position_detection_patterns_and_separators( matrix: &ByteMatrix) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
// Embed three big squares at corners.
|
||||
let pdp_width: i32 = POSITION_DETECTION_PATTERN[0].len();
|
||||
// Left top corner.
|
||||
::embed_position_detection_pattern(0, 0, matrix);
|
||||
// Right top corner.
|
||||
::embed_position_detection_pattern(matrix.get_width() - pdp_width, 0, matrix);
|
||||
// Left bottom corner.
|
||||
::embed_position_detection_pattern(0, matrix.get_width() - pdp_width, matrix);
|
||||
// Embed horizontal separation patterns around the squares.
|
||||
let hsp_width: i32 = 8;
|
||||
// Left top corner.
|
||||
::embed_horizontal_separation_pattern(0, hsp_width - 1, matrix);
|
||||
// Right top corner.
|
||||
::embed_horizontal_separation_pattern(matrix.get_width() - hsp_width, hsp_width - 1, matrix);
|
||||
// Left bottom corner.
|
||||
::embed_horizontal_separation_pattern(0, matrix.get_width() - hsp_width, matrix);
|
||||
// Embed vertical separation patterns around the squares.
|
||||
let vsp_size: i32 = 7;
|
||||
// Left top corner.
|
||||
::embed_vertical_separation_pattern(vsp_size, 0, matrix);
|
||||
// Right top corner.
|
||||
::embed_vertical_separation_pattern(matrix.get_height() - vsp_size - 1, 0, matrix);
|
||||
// Left bottom corner.
|
||||
::embed_vertical_separation_pattern(vsp_size, matrix.get_height() - vsp_size, matrix);
|
||||
}
|
||||
|
||||
// Embed position adjustment patterns if need be.
|
||||
fn maybe_embed_position_adjustment_patterns( version: &Version, matrix: &ByteMatrix) {
|
||||
if version.get_version_number() < 2 {
|
||||
// The patterns appear if version >= 2
|
||||
return;
|
||||
}
|
||||
let index: i32 = version.get_version_number() - 1;
|
||||
let coordinates: Vec<i32> = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
|
||||
for let y: i32 in coordinates {
|
||||
if y >= 0 {
|
||||
for let x: i32 in coordinates {
|
||||
if x >= 0 && ::is_empty(&matrix.get(x, y)) {
|
||||
// If the cell is unset, we embed the position adjustment pattern here.
|
||||
// -2 is necessary since the x/y coordinates point to the center of the pattern, not the
|
||||
// left top corner.
|
||||
::embed_position_adjustment_pattern(x - 2, y - 2, matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,656 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
/**
|
||||
* Encoder that encodes minimally
|
||||
*
|
||||
* Algorithm:
|
||||
*
|
||||
* The eleventh commandment was "Thou Shalt Compute" or "Thou Shalt Not Compute" - I forget which (Alan Perilis).
|
||||
*
|
||||
* This implementation computes. As an alternative, the QR-Code specification suggests heuristics like this one:
|
||||
*
|
||||
* If initial input data is in the exclusive subset of the Alphanumeric character set AND if there are less than
|
||||
* [6,7,8] characters followed by data from the remainder of the 8-bit byte character set, THEN select the 8-
|
||||
* bit byte mode ELSE select Alphanumeric mode;
|
||||
*
|
||||
* This is probably right for 99.99% of cases but there is at least this one counter example: The string "AAAAAAa"
|
||||
* encodes 2 bits smaller as ALPHANUMERIC(AAAAAA), BYTE(a) than by encoding it as BYTE(AAAAAAa).
|
||||
* Perhaps that is the only counter example but without having proof, it remains unclear.
|
||||
*
|
||||
* ECI switching:
|
||||
*
|
||||
* In multi language content the algorithm selects the most compact representation using ECI modes.
|
||||
* For example the most compact representation of the string "\u0150\u015C" (O-double-acute, S-circumflex) is
|
||||
* ECI(UTF-8), BYTE(\u0150\u015C) while prepending one or more times the same leading character as in
|
||||
* "\u0150\u0150\u015C", the most compact representation uses two ECIs so that the string is encoded as
|
||||
* ECI(ISO-8859-2), BYTE(\u0150\u0150), ECI(ISO-8859-3), BYTE(\u015C).
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
struct MinimalEncoder {
|
||||
|
||||
let string_to_encode: String;
|
||||
|
||||
let is_g_s1: bool;
|
||||
|
||||
let mut encoders: ECIEncoderSet;
|
||||
|
||||
let ec_level: ErrorCorrectionLevel;
|
||||
}
|
||||
|
||||
impl MinimalEncoder {
|
||||
|
||||
enum VersionSize {
|
||||
|
||||
SMALL("version 1-9"), MEDIUM("version 10-26"), LARGE("version 27-40");
|
||||
|
||||
let description: String;
|
||||
|
||||
fn new( description: &String) -> VersionSize {
|
||||
let .description = description;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return self.description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MinimalEncoder
|
||||
*
|
||||
* @param stringToEncode The string to encode
|
||||
* @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
|
||||
* chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
|
||||
* charset to encode any character in the input that can be encoded by it if the charset is among the
|
||||
* supported charsets.
|
||||
* @param isGS1 {@code true} if a FNC1 is to be prepended; {@code false} otherwise
|
||||
* @param ecLevel The error correction level.
|
||||
* @see ResultList#getVersion
|
||||
*/
|
||||
fn new( string_to_encode: &String, priority_charset: &Charset, is_g_s1: bool, ec_level: &ErrorCorrectionLevel) -> MinimalEncoder {
|
||||
let .stringToEncode = string_to_encode;
|
||||
let .isGS1 = is_g_s1;
|
||||
let .encoders = ECIEncoderSet::new(&string_to_encode, &priority_charset, -1);
|
||||
let .ecLevel = ec_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the string minimally
|
||||
*
|
||||
* @param stringToEncode The string to encode
|
||||
* @param version The preferred {@link Version}. A minimal version is computed (see
|
||||
* {@link ResultList#getVersion method} when the value of the argument is null
|
||||
* @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
|
||||
* chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
|
||||
* charset to encode any character in the input that can be encoded by it if the charset is among the
|
||||
* supported charsets.
|
||||
* @param isGS1 {@code true} if a FNC1 is to be prepended; {@code false} otherwise
|
||||
* @param ecLevel The error correction level.
|
||||
* @return An instance of {@code ResultList} representing the minimal solution.
|
||||
* @see ResultList#getBits
|
||||
* @see ResultList#getVersion
|
||||
* @see ResultList#getSize
|
||||
*/
|
||||
fn encode( string_to_encode: &String, version: &Version, priority_charset: &Charset, is_g_s1: bool, ec_level: &ErrorCorrectionLevel) -> /* throws WriterException */Result<ResultList, Rc<Exception>> {
|
||||
return Ok(MinimalEncoder::new(&string_to_encode, &priority_charset, is_g_s1, ec_level).encode(version));
|
||||
}
|
||||
|
||||
fn encode(&self, version: &Version) -> /* throws WriterException */Result<ResultList, Rc<Exception>> {
|
||||
if version == null {
|
||||
// compute minimal encoding trying the three version sizes.
|
||||
let versions: vec![Vec<Version>; 3] = vec![::get_version(VersionSize::SMALL), ::get_version(VersionSize::MEDIUM), ::get_version(VersionSize::LARGE), ]
|
||||
;
|
||||
let results: vec![Vec<ResultList>; 3] = vec![self.encode_specific_version(versions[0]), self.encode_specific_version(versions[1]), self.encode_specific_version(versions[2]), ]
|
||||
;
|
||||
let smallest_size: i32 = Integer::MAX_VALUE;
|
||||
let smallest_result: i32 = -1;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 3 {
|
||||
{
|
||||
let size: i32 = results[i].get_size();
|
||||
if Encoder::will_fit(size, versions[i], self.ec_level) && size < smallest_size {
|
||||
smallest_size = size;
|
||||
smallest_result = i;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if smallest_result < 0 {
|
||||
throw WriterException::new("Data too big for any version");
|
||||
}
|
||||
return Ok(results[smallest_result]);
|
||||
} else {
|
||||
// compute minimal encoding for a given version
|
||||
let result: ResultList = self.encode_specific_version(version);
|
||||
if !Encoder::will_fit(&result.get_size(), &::get_version(&::get_version_size(&result.get_version())), self.ec_level) {
|
||||
throw WriterException::new(format!("Data too big for version{}", version));
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_version_size( version: &Version) -> VersionSize {
|
||||
return if version.get_version_number() <= 9 { VersionSize::SMALL } else { if version.get_version_number() <= 26 { VersionSize::MEDIUM } else { VersionSize::LARGE } };
|
||||
}
|
||||
|
||||
fn get_version( version_size: &VersionSize) -> Version {
|
||||
match version_size {
|
||||
SMALL =>
|
||||
{
|
||||
return Version::get_version_for_number(9);
|
||||
}
|
||||
MEDIUM =>
|
||||
{
|
||||
return Version::get_version_for_number(26);
|
||||
}
|
||||
LARGE =>
|
||||
{
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
return Version::get_version_for_number(40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_numeric( c: char) -> bool {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
fn is_double_byte_kanji( c: char) -> bool {
|
||||
return Encoder::is_only_double_byte_kanji(&String::value_of(c));
|
||||
}
|
||||
|
||||
fn is_alphanumeric( c: char) -> bool {
|
||||
return Encoder::get_alphanumeric_code(c) != -1;
|
||||
}
|
||||
|
||||
fn can_encode(&self, mode: &Mode, c: char) -> bool {
|
||||
match mode {
|
||||
KANJI =>
|
||||
{
|
||||
return ::is_double_byte_kanji(c);
|
||||
}
|
||||
ALPHANUMERIC =>
|
||||
{
|
||||
return ::is_alphanumeric(c);
|
||||
}
|
||||
NUMERIC =>
|
||||
{
|
||||
return ::is_numeric(c);
|
||||
}
|
||||
// any character can be encoded as byte(s). Up to the caller to manage splitting into
|
||||
BYTE =>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// multiple bytes when String.getBytes(Charset) return more than one byte.
|
||||
_ =>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_compacted_ordinal( mode: &Mode) -> i32 {
|
||||
if mode == null {
|
||||
return 0;
|
||||
}
|
||||
match mode {
|
||||
KANJI =>
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ALPHANUMERIC =>
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
NUMERIC =>
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
BYTE =>
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalStateException::new(format!("Illegal mode {}", mode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_edge(&self, edges: &Vec<Vec<Vec<Edge>>>, position: i32, edge: &Edge) {
|
||||
let vertex_index: i32 = position + edge.characterLength;
|
||||
let mode_edges: Vec<Edge> = edges[vertex_index][edge.charsetEncoderIndex];
|
||||
let mode_ordinal: i32 = ::get_compacted_ordinal(edge.mode);
|
||||
if mode_edges[mode_ordinal] == null || mode_edges[mode_ordinal].cachedTotalSize > edge.cachedTotalSize {
|
||||
mode_edges[mode_ordinal] = edge;
|
||||
}
|
||||
}
|
||||
|
||||
fn add_edges(&self, version: &Version, edges: &Vec<Vec<Vec<Edge>>>, from: i32, previous: &Edge) {
|
||||
let mut start: i32 = 0;
|
||||
let mut end: i32 = self.encoders.length();
|
||||
let priority_encoder_index: i32 = self.encoders.get_priority_encoder_index();
|
||||
if priority_encoder_index >= 0 && self.encoders.can_encode(&self.string_to_encode.char_at(from), priority_encoder_index) {
|
||||
start = priority_encoder_index;
|
||||
end = priority_encoder_index + 1;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = start;
|
||||
while i < end {
|
||||
{
|
||||
if self.encoders.can_encode(&self.string_to_encode.char_at(from), i) {
|
||||
self.add_edge(edges, from, Edge::new(Mode::BYTE, from, i, 1, previous, version));
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if self.can_encode(Mode::KANJI, &self.string_to_encode.char_at(from)) {
|
||||
self.add_edge(edges, from, Edge::new(Mode::KANJI, from, 0, 1, previous, version));
|
||||
}
|
||||
let input_length: i32 = self.string_to_encode.length();
|
||||
if self.can_encode(Mode::ALPHANUMERIC, &self.string_to_encode.char_at(from)) {
|
||||
self.add_edge(edges, from, Edge::new(Mode::ALPHANUMERIC, from, 0, if from + 1 >= input_length || !self.can_encode(Mode::ALPHANUMERIC, &self.string_to_encode.char_at(from + 1)) { 1 } else { 2 }, previous, version));
|
||||
}
|
||||
if self.can_encode(Mode::NUMERIC, &self.string_to_encode.char_at(from)) {
|
||||
self.add_edge(edges, from, Edge::new(Mode::NUMERIC, from, 0, if from + 1 >= input_length || !self.can_encode(Mode::NUMERIC, &self.string_to_encode.char_at(from + 1)) { 1 } else { if from + 2 >= input_length || !self.can_encode(Mode::NUMERIC, &self.string_to_encode.char_at(from + 2)) { 2 } else { 3 } }, previous, version));
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_specific_version(&self, version: &Version) -> /* throws WriterException */Result<ResultList, Rc<Exception>> {
|
||||
let input_length: i32 = self.string_to_encode.length();
|
||||
// Array that represents vertices. There is a vertex for every character, encoding and mode. The vertex contains
|
||||
// a list of all edges that lead to it that have the same encoding and mode.
|
||||
// The lists are created lazily
|
||||
// The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the
|
||||
// function getCompactedOrdinal(Mode)
|
||||
let edges: [[[Option<Edge>; 4]; self.encoders.length()]; input_length + 1] = [[[None; 4]; self.encoders.length()]; input_length + 1];
|
||||
self.add_edges(version, edges, 0, null);
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i <= input_length {
|
||||
{
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < self.encoders.length() {
|
||||
{
|
||||
{
|
||||
let mut k: i32 = 0;
|
||||
while k < 4 {
|
||||
{
|
||||
if edges[i][j][k] != null && i < input_length {
|
||||
self.add_edges(version, edges, i, edges[i][j][k]);
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let minimal_j: i32 = -1;
|
||||
let minimal_k: i32 = -1;
|
||||
let minimal_size: i32 = Integer::MAX_VALUE;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < self.encoders.length() {
|
||||
{
|
||||
{
|
||||
let mut k: i32 = 0;
|
||||
while k < 4 {
|
||||
{
|
||||
if edges[input_length][j][k] != null {
|
||||
let edge: Edge = edges[input_length][j][k];
|
||||
if edge.cachedTotalSize < minimal_size {
|
||||
minimal_size = edge.cachedTotalSize;
|
||||
minimal_j = j;
|
||||
minimal_k = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if minimal_j < 0 {
|
||||
throw WriterException::new(format!("Internal error: failed to encode \"{}\"", self.string_to_encode));
|
||||
}
|
||||
return Ok(ResultList::new(version, edges[input_length][minimal_j][minimal_k]));
|
||||
}
|
||||
|
||||
struct Edge {
|
||||
|
||||
let mode: Mode;
|
||||
|
||||
let from_position: i32;
|
||||
|
||||
let charset_encoder_index: i32;
|
||||
|
||||
let character_length: i32;
|
||||
|
||||
let previous: Edge;
|
||||
|
||||
let cached_total_size: i32;
|
||||
}
|
||||
|
||||
impl Edge {
|
||||
|
||||
fn new( mode: &Mode, from_position: i32, charset_encoder_index: i32, character_length: i32, previous: &Edge, version: &Version) -> Edge {
|
||||
let .mode = mode;
|
||||
let .fromPosition = from_position;
|
||||
let .charsetEncoderIndex = if mode == Mode::BYTE || previous == null { charset_encoder_index } else { // inherit the encoding if not of type BYTE
|
||||
previous.charsetEncoderIndex };
|
||||
let .characterLength = character_length;
|
||||
let .previous = previous;
|
||||
let mut size: i32 = if previous != null { previous.cachedTotalSize } else { 0 };
|
||||
let need_e_c_i: bool = mode == Mode::BYTE && // at the beginning and charset is not ISO-8859-1
|
||||
(previous == null && let .charsetEncoderIndex != 0) || (previous != null && let .charsetEncoderIndex != previous.charsetEncoderIndex);
|
||||
if previous == null || mode != previous.mode || need_e_c_i {
|
||||
size += 4 + mode.get_character_count_bits(version);
|
||||
}
|
||||
match mode {
|
||||
KANJI =>
|
||||
{
|
||||
size += 13;
|
||||
break;
|
||||
}
|
||||
ALPHANUMERIC =>
|
||||
{
|
||||
size += if character_length == 1 { 6 } else { 11 };
|
||||
break;
|
||||
}
|
||||
NUMERIC =>
|
||||
{
|
||||
size += if character_length == 1 { 4 } else { if character_length == 2 { 7 } else { 10 } };
|
||||
break;
|
||||
}
|
||||
BYTE =>
|
||||
{
|
||||
size += 8 * encoders.encode(&string_to_encode.substring(from_position, from_position + character_length), charset_encoder_index).len();
|
||||
if need_e_c_i {
|
||||
// the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
||||
size += 4 + 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cached_total_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ResultList {
|
||||
|
||||
let list: List<ResultList.ResultNode> = ArrayList<>::new();
|
||||
|
||||
let version: Version;
|
||||
}
|
||||
|
||||
impl ResultList {
|
||||
|
||||
fn new( version: &Version, solution: &Edge) -> ResultList {
|
||||
let mut length: i32 = 0;
|
||||
let mut current: Edge = solution;
|
||||
let contains_e_c_i: bool = false;
|
||||
while current != null {
|
||||
length += current.characterLength;
|
||||
let previous: Edge = current.previous;
|
||||
let need_e_c_i: bool = current.mode == Mode::BYTE && // at the beginning and charset is not ISO-8859-1
|
||||
(previous == null && current.charsetEncoderIndex != 0) || (previous != null && current.charsetEncoderIndex != previous.charsetEncoderIndex);
|
||||
if need_e_c_i {
|
||||
contains_e_c_i = true;
|
||||
}
|
||||
if previous == null || previous.mode != current.mode || need_e_c_i {
|
||||
list.add(0, ResultNode::new(current.mode, current.fromPosition, current.charsetEncoderIndex, length));
|
||||
length = 0;
|
||||
}
|
||||
if need_e_c_i {
|
||||
list.add(0, ResultNode::new(Mode::ECI, current.fromPosition, current.charsetEncoderIndex, 0));
|
||||
}
|
||||
current = previous;
|
||||
}
|
||||
// If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1)
|
||||
if is_g_s1 {
|
||||
let mut first: ResultNode = list.get(0);
|
||||
if first != null && first.mode != Mode::ECI && contains_e_c_i {
|
||||
// prepend a default character set ECI
|
||||
list.add(0, ResultNode::new(Mode::ECI, 0, 0, 0));
|
||||
}
|
||||
first = list.get(0);
|
||||
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
|
||||
list.add( if first.mode != Mode::ECI { 0 } else { 1 }, ResultNode::new(Mode::FNC1_FIRST_POSITION, 0, 0, 0));
|
||||
}
|
||||
// set version to smallest version into which the bits fit.
|
||||
let version_number: i32 = version.get_version_number();
|
||||
let lower_limit: i32;
|
||||
let upper_limit: i32;
|
||||
match ::get_version_size(version) {
|
||||
SMALL =>
|
||||
{
|
||||
lower_limit = 1;
|
||||
upper_limit = 9;
|
||||
break;
|
||||
}
|
||||
MEDIUM =>
|
||||
{
|
||||
lower_limit = 10;
|
||||
upper_limit = 26;
|
||||
break;
|
||||
}
|
||||
LARGE =>
|
||||
{
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
lower_limit = 27;
|
||||
upper_limit = 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let size: i32 = self.get_size(version);
|
||||
// increase version if needed
|
||||
while version_number < upper_limit && !Encoder::will_fit(size, &Version::get_version_for_number(version_number), ec_level) {
|
||||
version_number += 1;
|
||||
}
|
||||
// shrink version if possible
|
||||
while version_number > lower_limit && Encoder::will_fit(size, &Version::get_version_for_number(version_number - 1), ec_level) {
|
||||
version_number -= 1;
|
||||
}
|
||||
let .version = Version::get_version_for_number(version_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the size in bits
|
||||
*/
|
||||
fn get_size(&self) -> i32 {
|
||||
return self.get_size(self.version);
|
||||
}
|
||||
|
||||
fn get_size(&self, version: &Version) -> i32 {
|
||||
let mut result: i32 = 0;
|
||||
for let result_node: ResultNode in self.list {
|
||||
result += result_node.get_size(version);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* appends the bits
|
||||
*/
|
||||
fn get_bits(&self, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
for let result_node: ResultNode in self.list {
|
||||
result_node.get_bits(bits);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
return self.version;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
let mut previous: ResultNode = null;
|
||||
for let current: ResultNode in self.list {
|
||||
if previous != null {
|
||||
result.append(",");
|
||||
}
|
||||
result.append(¤t.to_string());
|
||||
previous = current;
|
||||
}
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
struct ResultNode {
|
||||
|
||||
let mode: Mode;
|
||||
|
||||
let from_position: i32;
|
||||
|
||||
let charset_encoder_index: i32;
|
||||
|
||||
let character_length: i32;
|
||||
}
|
||||
|
||||
impl ResultNode {
|
||||
|
||||
fn new( mode: &Mode, from_position: i32, charset_encoder_index: i32, character_length: i32) -> ResultNode {
|
||||
let .mode = mode;
|
||||
let .fromPosition = from_position;
|
||||
let .charsetEncoderIndex = charset_encoder_index;
|
||||
let .characterLength = character_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the size in bits
|
||||
*/
|
||||
fn get_size(&self, version: &Version) -> i32 {
|
||||
let mut size: i32 = 4 + self.mode.get_character_count_bits(version);
|
||||
match self.mode {
|
||||
KANJI =>
|
||||
{
|
||||
size += 13 * self.character_length;
|
||||
break;
|
||||
}
|
||||
ALPHANUMERIC =>
|
||||
{
|
||||
size += (self.character_length / 2) * 11;
|
||||
size += if (self.character_length % 2) == 1 { 6 } else { 0 };
|
||||
break;
|
||||
}
|
||||
NUMERIC =>
|
||||
{
|
||||
size += (self.character_length / 3) * 10;
|
||||
let rest: i32 = self.character_length % 3;
|
||||
size += if rest == 1 { 4 } else { if rest == 2 { 7 } else { 0 } };
|
||||
break;
|
||||
}
|
||||
BYTE =>
|
||||
{
|
||||
size += 8 * self.get_character_count_indicator();
|
||||
break;
|
||||
}
|
||||
ECI =>
|
||||
{
|
||||
// the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
||||
size += 8;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the length in characters according to the specification (differs from getCharacterLength() in BYTE mode
|
||||
* for multi byte encoded characters)
|
||||
*/
|
||||
fn get_character_count_indicator(&self) -> i32 {
|
||||
return if self.mode == Mode::BYTE { self.encoders.encode(&self.string_to_encode.substring(self.from_position, self.from_position + self.character_length), self.charset_encoder_index).len() } else { self.character_length };
|
||||
}
|
||||
|
||||
/**
|
||||
* appends the bits
|
||||
*/
|
||||
fn get_bits(&self, bits: &BitArray) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
bits.append_bits(&self.mode.get_bits(), 4);
|
||||
if self.character_length > 0 {
|
||||
let length: i32 = self.get_character_count_indicator();
|
||||
bits.append_bits(length, &self.mode.get_character_count_bits(self.version));
|
||||
}
|
||||
if self.mode == Mode::ECI {
|
||||
bits.append_bits(&self.encoders.get_e_c_i_value(self.charset_encoder_index), 8);
|
||||
} else if self.character_length > 0 {
|
||||
// append data
|
||||
Encoder::append_bytes(&self.string_to_encode.substring(self.from_position, self.from_position + self.character_length), self.mode, bits, &self.encoders.get_charset(self.charset_encoder_index));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
result.append(self.mode).append('(');
|
||||
if self.mode == Mode::ECI {
|
||||
result.append(&self.encoders.get_charset(self.charset_encoder_index).display_name());
|
||||
} else {
|
||||
result.append(&self.make_printable(&self.string_to_encode.substring(self.from_position, self.from_position + self.character_length)));
|
||||
}
|
||||
result.append(')');
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
fn make_printable(&self, s: &String) -> String {
|
||||
let result: StringBuilder = StringBuilder::new();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < s.length() {
|
||||
{
|
||||
if s.char_at(i) < 32 || s.char_at(i) > 126 {
|
||||
result.append('.');
|
||||
} else {
|
||||
result.append(&s.char_at(i));
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode::encoder;
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
|
||||
*/
|
||||
|
||||
const NUM_MASK_PATTERNS: i32 = 8;
|
||||
pub struct QRCode {
|
||||
|
||||
let mut mode: Mode;
|
||||
|
||||
let ec_level: ErrorCorrectionLevel;
|
||||
|
||||
let version: Version;
|
||||
|
||||
let mask_pattern: i32;
|
||||
|
||||
let mut matrix: ByteMatrix;
|
||||
}
|
||||
|
||||
impl QRCode {
|
||||
|
||||
pub fn new() -> QRCode {
|
||||
mask_pattern = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mode. Not relevant if {@link com.google.zxing.EncodeHintType#QR_COMPACT} is selected.
|
||||
*/
|
||||
pub fn get_mode(&self) -> Mode {
|
||||
return self.mode;
|
||||
}
|
||||
|
||||
pub fn get_e_c_level(&self) -> ErrorCorrectionLevel {
|
||||
return self.ec_level;
|
||||
}
|
||||
|
||||
pub fn get_version(&self) -> Version {
|
||||
return self.version;
|
||||
}
|
||||
|
||||
pub fn get_mask_pattern(&self) -> i32 {
|
||||
return self.mask_pattern;
|
||||
}
|
||||
|
||||
pub fn get_matrix(&self) -> ByteMatrix {
|
||||
return self.matrix;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let result: StringBuilder = StringBuilder::new(200);
|
||||
result.append("<<\n");
|
||||
result.append(" mode: ");
|
||||
result.append(self.mode);
|
||||
result.append("\n ecLevel: ");
|
||||
result.append(self.ec_level);
|
||||
result.append("\n version: ");
|
||||
result.append(self.version);
|
||||
result.append("\n maskPattern: ");
|
||||
result.append(self.mask_pattern);
|
||||
if self.matrix == null {
|
||||
result.append("\n matrix: null\n");
|
||||
} else {
|
||||
result.append("\n matrix:\n");
|
||||
result.append(self.matrix);
|
||||
}
|
||||
result.append(">>\n");
|
||||
return result.to_string();
|
||||
}
|
||||
|
||||
pub fn set_mode(&self, value: &Mode) {
|
||||
self.mode = value;
|
||||
}
|
||||
|
||||
pub fn set_e_c_level(&self, value: &ErrorCorrectionLevel) {
|
||||
self.ec_level = value;
|
||||
}
|
||||
|
||||
pub fn set_version(&self, version: &Version) {
|
||||
self.version = version;
|
||||
}
|
||||
|
||||
pub fn set_mask_pattern(&self, value: i32) {
|
||||
self.mask_pattern = value;
|
||||
}
|
||||
|
||||
pub fn set_matrix(&self, value: &ByteMatrix) {
|
||||
self.matrix = value;
|
||||
}
|
||||
|
||||
// Check if "mask_pattern" is valid.
|
||||
pub fn is_valid_mask_pattern( mask_pattern: i32) -> bool {
|
||||
return mask_pattern >= 0 && mask_pattern < NUM_MASK_PATTERNS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode;
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode QR Codes in an image.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
|
||||
#[derive(Reader)]
|
||||
pub struct QRCodeReader {
|
||||
|
||||
let decoder: Decoder = Decoder::new();
|
||||
}
|
||||
|
||||
impl QRCodeReader {
|
||||
|
||||
pub fn get_decoder(&self) -> Decoder {
|
||||
return self.decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates and decodes a QR code in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the QR code
|
||||
* @throws NotFoundException if a QR code cannot be found
|
||||
* @throws FormatException if a QR code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
|
||||
return Ok(self.decode(image, null));
|
||||
}
|
||||
|
||||
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
|
||||
let decoder_result: DecoderResult;
|
||||
let mut points: Vec<ResultPoint>;
|
||||
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
|
||||
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
|
||||
decoder_result = self.decoder.decode(bits, &hints);
|
||||
points = NO_POINTS;
|
||||
} else {
|
||||
let detector_result: DetectorResult = Detector::new(&image.get_black_matrix()).detect(&hints);
|
||||
decoder_result = self.decoder.decode(&detector_result.get_bits(), &hints);
|
||||
points = detector_result.get_points();
|
||||
}
|
||||
// If the code was mirrored: swap the bottom-left and the top-right points.
|
||||
if decoder_result.get_other() instanceof QRCodeDecoderMetaData {
|
||||
(decoder_result.get_other() as QRCodeDecoderMetaData).apply_mirrored_correction(points);
|
||||
}
|
||||
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::QR_CODE);
|
||||
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
|
||||
if byte_segments != null {
|
||||
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
|
||||
}
|
||||
let ec_level: String = decoder_result.get_e_c_level();
|
||||
if ec_level != null {
|
||||
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
|
||||
}
|
||||
if decoder_result.has_structured_append() {
|
||||
result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE, &decoder_result.get_structured_append_sequence_number());
|
||||
result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_PARITY, &decoder_result.get_structured_append_parity());
|
||||
}
|
||||
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]Q{}", decoder_result.get_symbology_modifier()));
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* This method detects a code in a "pure" image -- that is, pure monochrome image
|
||||
* which contains only an unrotated, unskewed, image of a code, with some white border
|
||||
* around it. This is a specialized method that works exceptionally fast in this special
|
||||
* case.
|
||||
*/
|
||||
fn extract_pure_bits( image: &BitMatrix) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
||||
let left_top_black: Vec<i32> = image.get_top_left_on_bit();
|
||||
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
|
||||
if left_top_black == null || right_bottom_black == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let module_size: f32 = self.module_size(&left_top_black, image);
|
||||
let mut top: i32 = left_top_black[1];
|
||||
let bottom: i32 = right_bottom_black[1];
|
||||
let mut left: i32 = left_top_black[0];
|
||||
let mut right: i32 = right_bottom_black[0];
|
||||
// Sanity check!
|
||||
if left >= right || top >= bottom {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
if bottom - top != right - left {
|
||||
// Special case, where bottom-right module wasn't black so we found something else in the last row
|
||||
// Assume it's a square, so use height as the width
|
||||
right = left + (bottom - top);
|
||||
if right >= image.get_width() {
|
||||
// Abort if that would not make sense -- off image
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
}
|
||||
let matrix_width: i32 = Math::round((right - left + 1.0) / module_size);
|
||||
let matrix_height: i32 = Math::round((bottom - top + 1.0) / module_size);
|
||||
if matrix_width <= 0 || matrix_height <= 0 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
if matrix_height != matrix_width {
|
||||
// Only possibly decode square regions
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// Push in the "border" by half the module width so that we start
|
||||
// sampling in the middle of the module. Just in case the image is a
|
||||
// little off, this will help recover.
|
||||
let nudge: i32 = (module_size / 2.0f) as i32;
|
||||
top += nudge;
|
||||
left += nudge;
|
||||
// But careful that this does not sample off the edge
|
||||
// "right" is the farthest-right valid pixel location -- right+1 is not necessarily
|
||||
// This is positive by how much the inner x loop below would be too large
|
||||
let nudged_too_far_right: i32 = left + ((matrix_width - 1.0) * module_size) as i32 - right;
|
||||
if nudged_too_far_right > 0 {
|
||||
if nudged_too_far_right > nudge {
|
||||
// Neither way fits; abort
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
left -= nudged_too_far_right;
|
||||
}
|
||||
// See logic above
|
||||
let nudged_too_far_down: i32 = top + ((matrix_height - 1.0) * module_size) as i32 - bottom;
|
||||
if nudged_too_far_down > 0 {
|
||||
if nudged_too_far_down > nudge {
|
||||
// Neither way fits; abort
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
top -= nudged_too_far_down;
|
||||
}
|
||||
// Now just read off the bits
|
||||
let bits: BitMatrix = BitMatrix::new(matrix_width, matrix_height);
|
||||
{
|
||||
let mut y: i32 = 0;
|
||||
while y < matrix_height {
|
||||
{
|
||||
let i_offset: i32 = top + (y * module_size) as i32;
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < matrix_width {
|
||||
{
|
||||
if image.get(left + (x * module_size) as i32, i_offset) {
|
||||
bits.set(x, y);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(bits);
|
||||
}
|
||||
|
||||
fn module_size( left_top_black: &Vec<i32>, image: &BitMatrix) -> /* throws NotFoundException */Result<f32, Rc<Exception>> {
|
||||
let height: i32 = image.get_height();
|
||||
let width: i32 = image.get_width();
|
||||
let mut x: i32 = left_top_black[0];
|
||||
let mut y: i32 = left_top_black[1];
|
||||
let in_black: bool = true;
|
||||
let mut transitions: i32 = 0;
|
||||
while x < width && y < height {
|
||||
if in_black != image.get(x, y) {
|
||||
if transitions += 1 == 5 {
|
||||
break;
|
||||
}
|
||||
in_black = !in_black;
|
||||
}
|
||||
x += 1;
|
||||
y += 1;
|
||||
}
|
||||
if x == width || y == height {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
return Ok((x - left_top_black[0]) / 7.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// package com::google::zxing::qrcode;
|
||||
|
||||
/**
|
||||
* This object renders a QR Code as a BitMatrix 2D array of greyscale values.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
const QUIET_ZONE_SIZE: i32 = 4;
|
||||
#[derive(Writer)]
|
||||
pub struct QRCodeWriter {
|
||||
}
|
||||
|
||||
impl QRCodeWriter {
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> /* throws WriterException */Result<BitMatrix, Rc<Exception>> {
|
||||
return Ok(self.encode(&contents, format, width, height, null));
|
||||
}
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, ?>) -> /* throws WriterException */Result<BitMatrix, Rc<Exception>> {
|
||||
if contents.is_empty() {
|
||||
throw IllegalArgumentException::new("Found empty contents");
|
||||
}
|
||||
if format != BarcodeFormat::QR_CODE {
|
||||
throw IllegalArgumentException::new(format!("Can only encode QR_CODE, but got {}", format));
|
||||
}
|
||||
if width < 0 || height < 0 {
|
||||
throw IllegalArgumentException::new(format!("Requested dimensions are too small: {}x{}", width, height));
|
||||
}
|
||||
let error_correction_level: ErrorCorrectionLevel = ErrorCorrectionLevel::L;
|
||||
let quiet_zone: i32 = QUIET_ZONE_SIZE;
|
||||
if hints != null {
|
||||
if hints.contains_key(EncodeHintType::ERROR_CORRECTION) {
|
||||
error_correction_level = ErrorCorrectionLevel::value_of(&hints.get(EncodeHintType::ERROR_CORRECTION).to_string());
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::MARGIN) {
|
||||
quiet_zone = Integer::parse_int(&hints.get(EncodeHintType::MARGIN).to_string());
|
||||
}
|
||||
}
|
||||
let code: QRCode = Encoder::encode(&contents, error_correction_level, &hints);
|
||||
return Ok(::render_result(code, width, height, quiet_zone));
|
||||
}
|
||||
|
||||
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
|
||||
// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
|
||||
fn render_result( code: &QRCode, width: i32, height: i32, quiet_zone: i32) -> BitMatrix {
|
||||
let input: ByteMatrix = code.get_matrix();
|
||||
if input == null {
|
||||
throw IllegalStateException::new();
|
||||
}
|
||||
let input_width: i32 = input.get_width();
|
||||
let input_height: i32 = input.get_height();
|
||||
let qr_width: i32 = input_width + (quiet_zone * 2);
|
||||
let qr_height: i32 = input_height + (quiet_zone * 2);
|
||||
let output_width: i32 = Math::max(width, qr_width);
|
||||
let output_height: i32 = Math::max(height, qr_height);
|
||||
let multiple: i32 = Math::min(output_width / qr_width, output_height / qr_height);
|
||||
// Padding includes both the quiet zone and the extra white pixels to accommodate the requested
|
||||
// dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
|
||||
// If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
|
||||
// handle all the padding from 100x100 (the actual QR) up to 200x160.
|
||||
let left_padding: i32 = (output_width - (input_width * multiple)) / 2;
|
||||
let top_padding: i32 = (output_height - (input_height * multiple)) / 2;
|
||||
let output: BitMatrix = BitMatrix::new(output_width, output_height);
|
||||
{
|
||||
let input_y: i32 = 0, let output_y: i32 = top_padding;
|
||||
while input_y < input_height {
|
||||
{
|
||||
// Write the contents of this row of the barcode
|
||||
{
|
||||
let input_x: i32 = 0, let output_x: i32 = left_padding;
|
||||
while input_x < input_width {
|
||||
{
|
||||
if input.get(input_x, input_y) == 1 {
|
||||
output.set_region(output_x, output_y, multiple, multiple);
|
||||
}
|
||||
}
|
||||
input_x += 1;
|
||||
output_x += multiple;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
input_y += 1;
|
||||
output_y += multiple;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user