remove qrcode

This commit is contained in:
Henry Schimke
2022-08-14 18:18:10 -05:00
parent 20c7ec32f1
commit 5d5280abfd
26 changed files with 0 additions and 6363 deletions

Binary file not shown.

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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 ;
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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];
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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.
}
}

View File

@@ -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))), ]
;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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, &center.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(&center1.get_estimated_module_size(), &center2.get_estimated_module_size());
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

@@ -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(&current.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();
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}