From db1a8ab0259557bb44b74ea958b5d080d49e7388 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 12 Aug 2022 20:54:32 -0500 Subject: [PATCH] non working move of aztec --- .../zxing/aztec/aztec_detector_result.rs | 55 - port_src/output/zxing/aztec/aztec_reader.rs | 111 -- port_src/output/zxing/aztec/aztec_writer.rs | 98 -- .../output/zxing/aztec/decoder/decoder.rs | 556 -------- .../output/zxing/aztec/detector/detector.rs | 586 -------- .../output/zxing/aztec/encoder/aztec_code.rs | 93 -- .../zxing/aztec/encoder/binary_shift_token.rs | 67 - .../output/zxing/aztec/encoder/encoder.rs | 516 ------- .../zxing/aztec/encoder/high_level_encoder.rs | 370 ----- .../zxing/aztec/encoder/simple_token.rs | 45 - port_src/output/zxing/aztec/encoder/state.rs | 211 --- port_src/output/zxing/aztec/encoder/token.rs | 46 - src/aztec.rs | 229 ++- src/aztec/decoder.rs | 548 ++++++++ src/aztec/detector.rs | 581 ++++++++ src/aztec/encoder.rs | 1242 +++++++++++++++++ 16 files changed, 2599 insertions(+), 2755 deletions(-) delete mode 100644 port_src/output/zxing/aztec/aztec_detector_result.rs delete mode 100644 port_src/output/zxing/aztec/aztec_reader.rs delete mode 100644 port_src/output/zxing/aztec/aztec_writer.rs delete mode 100644 port_src/output/zxing/aztec/decoder/decoder.rs delete mode 100644 port_src/output/zxing/aztec/detector/detector.rs delete mode 100644 port_src/output/zxing/aztec/encoder/aztec_code.rs delete mode 100644 port_src/output/zxing/aztec/encoder/binary_shift_token.rs delete mode 100644 port_src/output/zxing/aztec/encoder/encoder.rs delete mode 100644 port_src/output/zxing/aztec/encoder/high_level_encoder.rs delete mode 100644 port_src/output/zxing/aztec/encoder/simple_token.rs delete mode 100644 port_src/output/zxing/aztec/encoder/state.rs delete mode 100644 port_src/output/zxing/aztec/encoder/token.rs diff --git a/port_src/output/zxing/aztec/aztec_detector_result.rs b/port_src/output/zxing/aztec/aztec_detector_result.rs deleted file mode 100644 index e1af8b5..0000000 --- a/port_src/output/zxing/aztec/aztec_detector_result.rs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2010 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::aztec; - -/** - *

Extends {@link DetectorResult} with more information specific to the Aztec format, - * like the number of layers and whether it's compact.

- * - * @author Sean Owen - */ -pub struct AztecDetectorResult { - super: DetectorResult; - - let compact: bool; - - let nb_datablocks: i32; - - let nb_layers: i32; -} - -impl AztecDetectorResult { - - pub fn new( bits: &BitMatrix, points: &Vec, compact: bool, nb_datablocks: i32, nb_layers: i32) -> AztecDetectorResult { - super(bits, points); - let .compact = compact; - let .nbDatablocks = nb_datablocks; - let .nbLayers = nb_layers; - } - - pub fn get_nb_layers(&self) -> i32 { - return self.nb_layers; - } - - pub fn get_nb_datablocks(&self) -> i32 { - return self.nb_datablocks; - } - - pub fn is_compact(&self) -> bool { - return self.compact; - } -} - diff --git a/port_src/output/zxing/aztec/aztec_reader.rs b/port_src/output/zxing/aztec/aztec_reader.rs deleted file mode 100644 index 3d71f14..0000000 --- a/port_src/output/zxing/aztec/aztec_reader.rs +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2010 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::aztec; - -/** - * This implementation can detect and decode Aztec codes in an image. - * - * @author David Olivier - */ -#[derive(Reader)] -pub struct AztecReader { -} - -impl AztecReader { - - /** - * Locates and decodes a Data Matrix code in an image. - * - * @return a String representing the content encoded by the Data Matrix code - * @throws NotFoundException if a Data Matrix code cannot be found - * @throws FormatException if a Data Matrix code cannot be decoded - */ - pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, FormatException */Result> { - return Ok(self.decode(image, null)); - } - - pub fn decode(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException, FormatException */Result> { - let not_found_exception: NotFoundException = null; - let format_exception: FormatException = null; - let detector: Detector = Detector::new(&image.get_black_matrix()); - let mut points: Vec = null; - let decoder_result: DecoderResult = null; - let tryResult1 = 0; - 'try1: loop { - { - let detector_result: AztecDetectorResult = detector.detect(false); - points = detector_result.get_points(); - decoder_result = Decoder::new().decode(detector_result); - } - break 'try1 - } - match tryResult1 { - catch ( e: &NotFoundException) { - not_found_exception = e; - } catch ( e: &FormatException) { - format_exception = e; - } 0 => break - } - - if decoder_result == null { - let tryResult1 = 0; - 'try1: loop { - { - let detector_result: AztecDetectorResult = detector.detect(true); - points = detector_result.get_points(); - decoder_result = Decoder::new().decode(detector_result); - } - break 'try1 - } - match tryResult1 { - catch ( e: &NotFoundExceptionFormatException | ) { - if not_found_exception != null { - throw not_found_exception; - } - if format_exception != null { - throw format_exception; - } - throw e; - } 0 => break - } - - } - if hints != null { - let rpcb: ResultPointCallback = hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback; - if rpcb != null { - for let point: ResultPoint in points { - rpcb.found_possible_result_point(point); - } - } - } - let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), &decoder_result.get_num_bits(), points, BarcodeFormat::AZTEC, &System::current_time_millis()); - let byte_segments: List> = 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); - } - result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]z{}", decoder_result.get_symbology_modifier())); - return Ok(result); - } - - pub fn reset(&self) { - // do nothing - } -} - diff --git a/port_src/output/zxing/aztec/aztec_writer.rs b/port_src/output/zxing/aztec/aztec_writer.rs deleted file mode 100644 index ecb1f78..0000000 --- a/port_src/output/zxing/aztec/aztec_writer.rs +++ /dev/null @@ -1,98 +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::aztec; - -/** - * Renders an Aztec code as a {@link BitMatrix}. - */ -#[derive(Writer)] -pub struct AztecWriter { -} - -impl AztecWriter { - - pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> BitMatrix { - return ::encode(&contents, format, width, height, null); - } - - pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map) -> BitMatrix { - // Do not add any ECI code by default - let mut charset: Charset = null; - let ecc_percent: i32 = Encoder::DEFAULT_EC_PERCENT; - let mut layers: i32 = Encoder::DEFAULT_AZTEC_LAYERS; - if hints != null { - if hints.contains_key(EncodeHintType::CHARACTER_SET) { - charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string()); - } - if hints.contains_key(EncodeHintType::ERROR_CORRECTION) { - ecc_percent = Integer::parse_int(&hints.get(EncodeHintType::ERROR_CORRECTION).to_string()); - } - if hints.contains_key(EncodeHintType::AZTEC_LAYERS) { - layers = Integer::parse_int(&hints.get(EncodeHintType::AZTEC_LAYERS).to_string()); - } - } - return ::encode(&contents, format, width, height, &charset, ecc_percent, layers); - } - - fn encode( contents: &String, format: &BarcodeFormat, width: i32, height: i32, charset: &Charset, ecc_percent: i32, layers: i32) -> BitMatrix { - if format != BarcodeFormat::AZTEC { - throw IllegalArgumentException::new(format!("Can only encode AZTEC, but got {}", format)); - } - let aztec: AztecCode = Encoder::encode(&contents, ecc_percent, layers, &charset); - return ::render_result(aztec, width, height); - } - - fn render_result( code: &AztecCode, width: i32, height: i32) -> BitMatrix { - let input: BitMatrix = code.get_matrix(); - if input == null { - throw IllegalStateException::new(); - } - let input_width: i32 = input.get_width(); - let input_height: i32 = input.get_height(); - let output_width: i32 = Math::max(width, input_width); - let output_height: i32 = Math::max(height, input_height); - let multiple: i32 = Math::min(output_width / input_width, output_height / input_height); - 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) { - output.set_region(output_x, output_y, multiple, multiple); - } - } - input_x += 1; - output_x += multiple; - } - } - - } - input_y += 1; - output_y += multiple; - } - } - - return output; - } -} - diff --git a/port_src/output/zxing/aztec/decoder/decoder.rs b/port_src/output/zxing/aztec/decoder/decoder.rs deleted file mode 100644 index 3c0446c..0000000 --- a/port_src/output/zxing/aztec/decoder/decoder.rs +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright 2010 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::aztec::decoder; - -/** - *

The main class which implements Aztec Code decoding -- as opposed to locating and extracting - * the Aztec Code from an image.

- * - * @author David Olivier - */ - - const UPPER_TABLE: vec![Vec; 32] = vec!["CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS", ] -; - - const LOWER_TABLE: vec![Vec; 32] = vec!["CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS", ] -; - - const MIXED_TABLE: vec![Vec; 32] = vec!["CTRL_PS", " ", "\1", "\2", "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n", "\13", "\f", "\r", "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_", "`", "|", "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS", ] -; - - const PUNCT_TABLE: vec![Vec; 32] = vec!["FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL", ] -; - - const DIGIT_TABLE: vec![Vec; 16] = vec!["CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US", ] -; - - const DEFAULT_ENCODING: Charset = StandardCharsets::ISO_8859_1; -pub struct Decoder { - - let mut ddata: AztecDetectorResult; -} - -impl Decoder { - - enum Table { - - UPPER(), LOWER(), MIXED(), DIGIT(), PUNCT(), BINARY() - } - - pub fn decode(&self, detector_result: &AztecDetectorResult) -> /* throws FormatException */Result> { - self.ddata = detector_result; - let matrix: BitMatrix = detector_result.get_bits(); - let rawbits: Vec = self.extract_bits(matrix); - let corrected_bits: CorrectedBitsResult = self.correct_bits(&rawbits); - let raw_bytes: Vec = ::convert_bool_array_to_byte_array(corrected_bits.correctBits); - let result: String = ::get_encoded_data(corrected_bits.correctBits); - let decoder_result: DecoderResult = DecoderResult::new(&raw_bytes, &result, null, &String::format("%d%%", corrected_bits.ecLevel)); - decoder_result.set_num_bits(corrected_bits.correctBits.len()); - return Ok(decoder_result); - } - - // This method is used for testing the high-level encoder - pub fn high_level_decode( corrected_bits: &Vec) -> /* throws FormatException */Result> { - return Ok(::get_encoded_data(&corrected_bits)); - } - - /** - * Gets the string encoded in the aztec code bits - * - * @return the decoded string - */ - fn get_encoded_data( corrected_bits: &Vec) -> /* throws FormatException */Result> { - let end_index: i32 = corrected_bits.len(); - // table most recently latched to - let latch_table: Table = Table::UPPER; - // table to use for the next read - let shift_table: Table = Table::UPPER; - // Final decoded string result - // (correctedBits-5) / 4 is an upper bound on the size (all-digit result) - let result: StringBuilder = StringBuilder::new((corrected_bits.len() - 5) / 4); - // Intermediary buffer of decoded bytes, which is decoded into a string and flushed - // when character encoding changes (ECI) or input ends. - let decoded_bytes: ByteArrayOutputStream = ByteArrayOutputStream::new(); - let mut encoding: Charset = DEFAULT_ENCODING; - let mut index: i32 = 0; - while index < end_index { - if shift_table == Table::BINARY { - if end_index - index < 5 { - break; - } - let mut length: i32 = ::read_code(&corrected_bits, index, 5); - index += 5; - if length == 0 { - if end_index - index < 11 { - break; - } - length = ::read_code(&corrected_bits, index, 11) + 31; - index += 11; - } - { - let char_count: i32 = 0; - while char_count < length { - { - if end_index - index < 8 { - // Force outer loop to exit - index = end_index; - break; - } - let code: i32 = ::read_code(&corrected_bits, index, 8); - decoded_bytes.write(code as i8); - index += 8; - } - char_count += 1; - } - } - - // Go back to whatever mode we had been in - shift_table = latch_table; - } else { - let size: i32 = if shift_table == Table::DIGIT { 4 } else { 5 }; - if end_index - index < size { - break; - } - let code: i32 = ::read_code(&corrected_bits, index, size); - index += size; - let str: String = ::get_character(shift_table, code); - if "FLG(n)".equals(&str) { - if end_index - index < 3 { - break; - } - let mut n: i32 = ::read_code(&corrected_bits, index, 3); - index += 3; - // flush bytes, FLG changes state - let tryResult1 = 0; - 'try1: loop { - { - result.append(&decoded_bytes.to_string(&encoding.name())); - } - break 'try1 - } - match tryResult1 { - catch ( uee: &UnsupportedEncodingException) { - throw IllegalStateException::new(&uee); - } 0 => break - } - - decoded_bytes.reset(); - match n { - 0 => - { - // translate FNC1 as ASCII 29 - result.append(29 as char); - break; - } - 7 => - { - // FLG(7) is reserved and illegal - throw FormatException::get_format_instance(); - } - _ => - { - // ECI is decimal integer encoded as 1-6 codes in DIGIT mode - let mut eci: i32 = 0; - if end_index - index < 4 * n { - break; - } - while n -= 1 !!!check!!! post decrement > 0 { - let next_digit: i32 = ::read_code(&corrected_bits, index, 4); - index += 4; - if next_digit < 2 || next_digit > 11 { - // Not a decimal digit - throw FormatException::get_format_instance(); - } - eci = eci * 10 + (next_digit - 2); - } - let charset_e_c_i: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i_by_value(eci); - if charset_e_c_i == null { - throw FormatException::get_format_instance(); - } - encoding = charset_e_c_i.get_charset(); - } - } - // Go back to whatever mode we had been in - shift_table = latch_table; - } else if str.starts_with("CTRL_") { - // Table changes - // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked. - // That's including when that mode is a shift. - // Our test case dlusbs.png for issue #642 exercises that. - // Latch the current mode, so as to return to Upper after U/S B/S - latch_table = shift_table; - shift_table = ::get_table(&str.char_at(5)); - if str.char_at(6) == 'L' { - latch_table = shift_table; - } - } else { - // Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*. - let b: Vec = str.get_bytes(StandardCharsets::US_ASCII); - decoded_bytes.write(&b, 0, b.len()); - // Go back to whatever mode we had been in - shift_table = latch_table; - } - } - } - let tryResult1 = 0; - 'try1: loop { - { - result.append(&decoded_bytes.to_string(&encoding.name())); - } - break 'try1 - } - match tryResult1 { - catch ( uee: &UnsupportedEncodingException) { - throw IllegalStateException::new(&uee); - } 0 => break - } - - return Ok(result.to_string()); - } - - /** - * gets the table corresponding to the char passed - */ - fn get_table( t: char) -> Table { - match t { - 'L' => - { - return Table::LOWER; - } - 'P' => - { - return Table::PUNCT; - } - 'M' => - { - return Table::MIXED; - } - 'D' => - { - return Table::DIGIT; - } - 'B' => - { - return Table::BINARY; - } - 'U' => - { - } - _ => - { - return Table::UPPER; - } - } - } - - /** - * Gets the character (or string) corresponding to the passed code in the given table - * - * @param table the table used - * @param code the code of the character - */ - fn get_character( table: &Table, code: i32) -> String { - match table { - UPPER => - { - return UPPER_TABLE[code]; - } - LOWER => - { - return LOWER_TABLE[code]; - } - MIXED => - { - return MIXED_TABLE[code]; - } - PUNCT => - { - return PUNCT_TABLE[code]; - } - DIGIT => - { - return DIGIT_TABLE[code]; - } - _ => - { - // Should not reach here. - throw IllegalStateException::new("Bad table"); - } - } - } - - struct CorrectedBitsResult { - - let correct_bits: Vec; - - let ec_level: i32; - } - - impl CorrectedBitsResult { - - fn new( correct_bits: &Vec, ec_level: i32) -> CorrectedBitsResult { - let .correctBits = correct_bits; - let .ecLevel = ec_level; - } - } - - - /** - *

Performs RS error correction on an array of bits.

- * - * @return the corrected array - * @throws FormatException if the input contains too many errors - */ - fn correct_bits(&self, rawbits: &Vec) -> /* throws FormatException */Result> { - let mut gf: GenericGF; - let codeword_size: i32; - if self.ddata.get_nb_layers() <= 2 { - codeword_size = 6; - gf = GenericGF::AZTEC_DATA_6; - } else if self.ddata.get_nb_layers() <= 8 { - codeword_size = 8; - gf = GenericGF::AZTEC_DATA_8; - } else if self.ddata.get_nb_layers() <= 22 { - codeword_size = 10; - gf = GenericGF::AZTEC_DATA_10; - } else { - codeword_size = 12; - gf = GenericGF::AZTEC_DATA_12; - } - let num_data_codewords: i32 = self.ddata.get_nb_datablocks(); - let num_codewords: i32 = rawbits.len() / codeword_size; - if num_codewords < num_data_codewords { - throw FormatException::get_format_instance(); - } - let mut offset: i32 = rawbits.len() % codeword_size; - let data_words: [i32; num_codewords] = [0; num_codewords]; - { - let mut i: i32 = 0; - while i < num_codewords { - { - data_words[i] = ::read_code(&rawbits, offset, codeword_size); - } - i += 1; - offset += codeword_size; - } - } - - let tryResult1 = 0; - 'try1: loop { - { - let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(gf); - rs_decoder.decode(&data_words, num_codewords - num_data_codewords); - } - break 'try1 - } - match tryResult1 { - catch ( ex: &ReedSolomonException) { - throw FormatException::get_format_instance(ex); - } 0 => break - } - - // Now perform the unstuffing operation. - // First, count how many bits are going to be thrown out as stuffing - let mask: i32 = (1 << codeword_size) - 1; - let stuffed_bits: i32 = 0; - { - let mut i: i32 = 0; - while i < num_data_codewords { - { - let data_word: i32 = data_words[i]; - if data_word == 0 || data_word == mask { - throw FormatException::get_format_instance(); - } else if data_word == 1 || data_word == mask - 1 { - stuffed_bits += 1; - } - } - i += 1; - } - } - - // Now, actually unpack the bits and remove the stuffing - let corrected_bits: [bool; num_data_codewords * codeword_size - stuffed_bits] = [false; num_data_codewords * codeword_size - stuffed_bits]; - let mut index: i32 = 0; - { - let mut i: i32 = 0; - while i < num_data_codewords { - { - let data_word: i32 = data_words[i]; - if data_word == 1 || data_word == mask - 1 { - // next codewordSize-1 bits are all zeros or all ones - Arrays::fill(&corrected_bits, index, index + codeword_size - 1, data_word > 1); - index += codeword_size - 1; - } else { - { - let mut bit: i32 = codeword_size - 1; - while bit >= 0 { - { - corrected_bits[index += 1 !!!check!!! post increment] = (data_word & (1 << bit)) != 0; - } - bit -= 1; - } - } - - } - } - i += 1; - } - } - - return Ok(CorrectedBitsResult::new(&corrected_bits, 100 * (num_codewords - num_data_codewords) / num_codewords)); - } - - /** - * Gets the array of bits from an Aztec Code matrix - * - * @return the array of bits - */ - fn extract_bits(&self, matrix: &BitMatrix) -> Vec { - let compact: bool = self.ddata.is_compact(); - let layers: i32 = self.ddata.get_nb_layers(); - // not including alignment lines - let base_matrix_size: i32 = ( if compact { 11 } else { 14 }) + layers * 4; - let alignment_map: [i32; base_matrix_size] = [0; base_matrix_size]; - let mut rawbits: [bool; ::total_bits_in_layer(layers, compact)] = [false; ::total_bits_in_layer(layers, compact)]; - if compact { - { - let mut i: i32 = 0; - while i < alignment_map.len() { - { - alignment_map[i] = i; - } - i += 1; - } - } - - } else { - let matrix_size: i32 = base_matrix_size + 1 + 2 * ((base_matrix_size / 2 - 1) / 15); - let orig_center: i32 = base_matrix_size / 2; - let center: i32 = matrix_size / 2; - { - let mut i: i32 = 0; - while i < orig_center { - { - let new_offset: i32 = i + i / 15; - alignment_map[orig_center - i - 1] = center - new_offset - 1; - alignment_map[orig_center + i] = center + new_offset + 1; - } - i += 1; - } - } - - } - { - let mut i: i32 = 0, let row_offset: i32 = 0; - while i < layers { - { - let row_size: i32 = (layers - i) * 4 + ( if compact { 9 } else { 12 }); - // The top-left most point of this layer is (not including alignment lines) - let low: i32 = i * 2; - // The bottom-right most point of this layer is (not including alignment lines) - let high: i32 = base_matrix_size - 1 - low; - // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows - { - let mut j: i32 = 0; - while j < row_size { - { - let column_offset: i32 = j * 2; - { - let mut k: i32 = 0; - while k < 2 { - { - // left column - rawbits[row_offset + column_offset + k] = matrix.get(alignment_map[low + k], alignment_map[low + j]); - // bottom row - rawbits[row_offset + 2 * row_size + column_offset + k] = matrix.get(alignment_map[low + j], alignment_map[high - k]); - // right column - rawbits[row_offset + 4 * row_size + column_offset + k] = matrix.get(alignment_map[high - k], alignment_map[high - j]); - // top row - rawbits[row_offset + 6 * row_size + column_offset + k] = matrix.get(alignment_map[high - j], alignment_map[low + k]); - } - k += 1; - } - } - - } - j += 1; - } - } - - row_offset += row_size * 8; - } - i += 1; - } - } - - return rawbits; - } - - /** - * Reads a code of given length and at given index in an array of bits - */ - fn read_code( rawbits: &Vec, start_index: i32, length: i32) -> i32 { - let mut res: i32 = 0; - { - let mut i: i32 = start_index; - while i < start_index + length { - { - res <<= 1; - if rawbits[i] { - res |= 0x01; - } - } - i += 1; - } - } - - return res; - } - - /** - * Reads a code of length 8 in an array of bits, padding with zeros - */ - fn read_byte( rawbits: &Vec, start_index: i32) -> i8 { - let n: i32 = rawbits.len() - start_index; - if n >= 8 { - return ::read_code(&rawbits, start_index, 8) as i8; - } - return (::read_code(&rawbits, start_index, n) << (8 - n)) as i8; - } - - /** - * Packs a bit array into bytes, most significant bit first - */ - fn convert_bool_array_to_byte_array( bool_arr: &Vec) -> Vec { - let byte_arr: [i8; (bool_arr.len() + 7) / 8] = [0; (bool_arr.len() + 7) / 8]; - { - let mut i: i32 = 0; - while i < byte_arr.len() { - { - byte_arr[i] = ::read_byte(&bool_arr, 8 * i); - } - i += 1; - } - } - - return byte_arr; - } - - fn total_bits_in_layer( layers: i32, compact: bool) -> i32 { - return (( if compact { 88 } else { 112 }) + 16 * layers) * layers; - } -} - diff --git a/port_src/output/zxing/aztec/detector/detector.rs b/port_src/output/zxing/aztec/detector/detector.rs deleted file mode 100644 index 4fdadc1..0000000 --- a/port_src/output/zxing/aztec/detector/detector.rs +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright 2010 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::aztec::detector; - -/** - * Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code - * is rotated or skewed, or partially obscured. - * - * @author David Olivier - * @author Frank Yellin - */ - - const EXPECTED_CORNER_BITS: vec![Vec; 4] = vec![// 07340 XXX .XX X.. ... -0xee0, // 00734 ... XXX .XX X.. -0x1dc, // 04073 X.. ... XXX .XX -0x83b, // 03407 .XX X.. ... XXX -0x707, ] -; -pub struct Detector { - - let image: BitMatrix; - - let mut compact: bool; - - let nb_layers: i32; - - let nb_data_blocks: i32; - - let nb_center_layers: i32; - - let mut shift: i32; -} - -impl Detector { - - pub fn new( image: &BitMatrix) -> Detector { - let .image = image; - } - - pub fn detect(&self) -> /* throws NotFoundException */Result> { - return Ok(self.detect(false)); - } - - /** - * Detects an Aztec Code in an image. - * - * @param isMirror if true, image is a mirror-image of original - * @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code - * @throws NotFoundException if no Aztec Code can be found - */ - pub fn detect(&self, is_mirror: bool) -> /* throws NotFoundException */Result> { - // 1. Get the center of the aztec matrix - let p_center: Point = self.get_matrix_center(); - // 2. Get the center points of the four diagonal points just outside the bull's eye - // [topRight, bottomRight, bottomLeft, topLeft] - let bulls_eye_corners: Vec = self.get_bulls_eye_corners(p_center); - if is_mirror { - let temp: ResultPoint = bulls_eye_corners[0]; - bulls_eye_corners[0] = bulls_eye_corners[2]; - bulls_eye_corners[2] = temp; - } - // 3. Get the size of the matrix and other parameters from the bull's eye - self.extract_parameters(bulls_eye_corners); - // 4. Sample the grid - let bits: BitMatrix = self.sample_grid(self.image, bulls_eye_corners[self.shift % 4], bulls_eye_corners[(self.shift + 1) % 4], bulls_eye_corners[(self.shift + 2) % 4], bulls_eye_corners[(self.shift + 3) % 4]); - // 5. Get the corners of the matrix. - let corners: Vec = self.get_matrix_corner_points(bulls_eye_corners); - return Ok(AztecDetectorResult::new(bits, corners, self.compact, self.nb_data_blocks, self.nb_layers)); - } - - /** - * Extracts the number of data layers and data blocks from the layer around the bull's eye. - * - * @param bullsEyeCorners the array of bull's eye corners - * @throws NotFoundException in case of too many errors or invalid parameters - */ - fn extract_parameters(&self, bulls_eye_corners: &Vec) -> /* throws NotFoundException */Result> { - if !self.is_valid(bulls_eye_corners[0]) || !self.is_valid(bulls_eye_corners[1]) || !self.is_valid(bulls_eye_corners[2]) || !self.is_valid(bulls_eye_corners[3]) { - throw NotFoundException::get_not_found_instance(); - } - let length: i32 = 2 * self.nb_center_layers; - // Get the bits around the bull's eye - let sides: vec![Vec; 4] = vec![// Right side - self.sample_line(bulls_eye_corners[0], bulls_eye_corners[1], length), // Bottom - self.sample_line(bulls_eye_corners[1], bulls_eye_corners[2], length), // Left side - self.sample_line(bulls_eye_corners[2], bulls_eye_corners[3], length), // Top - self.sample_line(bulls_eye_corners[3], bulls_eye_corners[0], length), ] - ; - // bullsEyeCorners[shift] is the corner of the bulls'eye that has three - // orientation marks. - // sides[shift] is the row/column that goes from the corner with three - // orientation marks to the corner with two. - self.shift = ::get_rotation(&sides, length); - // Flatten the parameter bits into a single 28- or 40-bit long - let parameter_data: i64 = 0; - { - let mut i: i32 = 0; - while i < 4 { - { - let side: i32 = sides[(self.shift + i) % 4]; - if self.compact { - // Each side of the form ..XXXXXXX. where Xs are parameter data - parameter_data <<= 7; - parameter_data += (side >> 1) & 0x7F; - } else { - // Each side of the form ..XXXXX.XXXXX. where Xs are parameter data - parameter_data <<= 10; - parameter_data += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F); - } - } - i += 1; - } - } - - // Corrects parameter data using RS. Returns just the data portion - // without the error correction. - let corrected_data: i32 = ::get_corrected_parameter_data(parameter_data, self.compact); - if self.compact { - // 8 bits: 2 bits layers and 6 bits data blocks - self.nb_layers = (corrected_data >> 6) + 1; - self.nb_data_blocks = (corrected_data & 0x3F) + 1; - } else { - // 16 bits: 5 bits layers and 11 bits data blocks - self.nb_layers = (corrected_data >> 11) + 1; - self.nb_data_blocks = (corrected_data & 0x7FF) + 1; - } - } - - fn get_rotation( sides: &Vec, length: i32) -> /* throws NotFoundException */Result> { - // In a normal pattern, we expect to See - // ** .* D A - // * * - // - // . * - // .. .. C B - // - // Grab the 3 bits from each of the sides the form the locator pattern and concatenate - // into a 12-bit integer. Start with the bit at A - let corner_bits: i32 = 0; - for let side: i32 in sides { - // XX......X where X's are orientation marks - let t: i32 = ((side >> (length - 2)) << 1) + (side & 1); - corner_bits = (corner_bits << 3) + t; - } - // Mov the bottom bit to the top, so that the three bits of the locator pattern at A are - // together. cornerBits is now: - // 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D - corner_bits = ((corner_bits & 1) << 11) + (corner_bits >> 1); - // can easily tolerate two errors. - { - let mut shift: i32 = 0; - while shift < 4 { - { - if Integer::bit_count(corner_bits ^ EXPECTED_CORNER_BITS[shift]) <= 2 { - return Ok(shift); - } - } - shift += 1; - } - } - - throw NotFoundException::get_not_found_instance(); - } - - /** - * Corrects the parameter bits using Reed-Solomon algorithm. - * - * @param parameterData parameter bits - * @param compact true if this is a compact Aztec code - * @throws NotFoundException if the array contains too many errors - */ - fn get_corrected_parameter_data( parameter_data: i64, compact: bool) -> /* throws NotFoundException */Result> { - let num_codewords: i32; - let num_data_codewords: i32; - if compact { - num_codewords = 7; - num_data_codewords = 2; - } else { - num_codewords = 10; - num_data_codewords = 4; - } - let num_e_c_codewords: i32 = num_codewords - num_data_codewords; - let parameter_words: [i32; num_codewords] = [0; num_codewords]; - { - let mut i: i32 = num_codewords - 1; - while i >= 0 { - { - parameter_words[i] = parameter_data as i32 & 0xF; - parameter_data >>= 4; - } - i -= 1; - } - } - - let tryResult1 = 0; - 'try1: loop { - { - let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(GenericGF::AZTEC_PARAM); - rs_decoder.decode(¶meter_words, num_e_c_codewords); - } - break 'try1 - } - match tryResult1 { - catch ( ignored: &ReedSolomonException) { - throw NotFoundException::get_not_found_instance(); - } 0 => break - } - - // Toss the error correction. Just return the data as an integer - let mut result: i32 = 0; - { - let mut i: i32 = 0; - while i < num_data_codewords { - { - result = (result << 4) + parameter_words[i]; - } - i += 1; - } - } - - return Ok(result); - } - - /** - * Finds the corners of a bull-eye centered on the passed point. - * This returns the centers of the diagonal points just outside the bull's eye - * Returns [topRight, bottomRight, bottomLeft, topLeft] - * - * @param pCenter Center point - * @return The corners of the bull-eye - * @throws NotFoundException If no valid bull-eye can be found - */ - fn get_bulls_eye_corners(&self, p_center: &Point) -> /* throws NotFoundException */Result, Rc> { - let mut pina: Point = p_center; - let mut pinb: Point = p_center; - let mut pinc: Point = p_center; - let mut pind: Point = p_center; - let mut color: bool = true; - { - self.nb_center_layers = 1; - while self.nb_center_layers < 9 { - { - let pouta: Point = self.get_first_different(pina, color, 1, -1); - let poutb: Point = self.get_first_different(pinb, color, 1, 1); - let poutc: Point = self.get_first_different(pinc, color, -1, 1); - let poutd: Point = self.get_first_different(pind, color, -1, -1); - if self.nb_center_layers > 2 { - let q: f32 = ::distance(poutd, pouta) * self.nb_center_layers / (::distance(pind, pina) * (self.nb_center_layers + 2)); - if q < 0.75 || q > 1.25 || !self.is_white_or_black_rectangle(pouta, poutb, poutc, poutd) { - break; - } - } - pina = pouta; - pinb = poutb; - pinc = poutc; - pind = poutd; - color = !color; - } - self.nb_center_layers += 1; - } - } - - if self.nb_center_layers != 5 && self.nb_center_layers != 7 { - throw NotFoundException::get_not_found_instance(); - } - self.compact = self.nb_center_layers == 5; - // Expand the square by .5 pixel in each direction so that we're on the border - // between the white square and the black square - let pinax: ResultPoint = ResultPoint::new(pina.get_x() + 0.5f, pina.get_y() - 0.5f); - let pinbx: ResultPoint = ResultPoint::new(pinb.get_x() + 0.5f, pinb.get_y() + 0.5f); - let pincx: ResultPoint = ResultPoint::new(pinc.get_x() - 0.5f, pinc.get_y() + 0.5f); - let pindx: ResultPoint = ResultPoint::new(pind.get_x() - 0.5f, pind.get_y() - 0.5f); - // just outside the bull's eye. - return Ok(::expand_square( : vec![ResultPoint; 4] = vec![pinax, pinbx, pincx, pindx, ] - , 2 * self.nb_center_layers - 3, 2 * self.nb_center_layers)); - } - - /** - * Finds a candidate center point of an Aztec code from an image - * - * @return the center point - */ - fn get_matrix_center(&self) -> Point { - let point_a: ResultPoint; - let point_b: ResultPoint; - let point_c: ResultPoint; - let point_d: ResultPoint; - //Get a white rectangle that can be the border of the matrix in center bull's eye or - let tryResult1 = 0; - 'try1: loop { - { - let corner_points: Vec = WhiteRectangleDetector::new(self.image).detect(); - point_a = corner_points[0]; - point_b = corner_points[1]; - point_c = corner_points[2]; - point_d = corner_points[3]; - } - break 'try1 - } - match tryResult1 { - catch ( e: &NotFoundException) { - let cx: i32 = self.image.get_width() / 2; - let cy: i32 = self.image.get_height() / 2; - point_a = self.get_first_different(Point::new(cx + 7, cy - 7), false, 1, -1).to_result_point(); - point_b = self.get_first_different(Point::new(cx + 7, cy + 7), false, 1, 1).to_result_point(); - point_c = self.get_first_different(Point::new(cx - 7, cy + 7), false, -1, 1).to_result_point(); - point_d = self.get_first_different(Point::new(cx - 7, cy - 7), false, -1, -1).to_result_point(); - } 0 => break - } - - //Compute the center of the rectangle - let mut cx: i32 = MathUtils::round((point_a.get_x() + point_d.get_x() + point_b.get_x() + point_c.get_x()) / 4.0f); - let mut cy: i32 = MathUtils::round((point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f); - // in order to compute a more accurate center. - let tryResult1 = 0; - 'try1: loop { - { - let corner_points: Vec = WhiteRectangleDetector::new(self.image, 15, cx, cy).detect(); - point_a = corner_points[0]; - point_b = corner_points[1]; - point_c = corner_points[2]; - point_d = corner_points[3]; - } - break 'try1 - } - match tryResult1 { - catch ( e: &NotFoundException) { - point_a = self.get_first_different(Point::new(cx + 7, cy - 7), false, 1, -1).to_result_point(); - point_b = self.get_first_different(Point::new(cx + 7, cy + 7), false, 1, 1).to_result_point(); - point_c = self.get_first_different(Point::new(cx - 7, cy + 7), false, -1, 1).to_result_point(); - point_d = self.get_first_different(Point::new(cx - 7, cy - 7), false, -1, -1).to_result_point(); - } 0 => break - } - - // Recompute the center of the rectangle - cx = MathUtils::round((point_a.get_x() + point_d.get_x() + point_b.get_x() + point_c.get_x()) / 4.0f); - cy = MathUtils::round((point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f); - return Point::new(cx, cy); - } - - /** - * Gets the Aztec code corners from the bull's eye corners and the parameters. - * - * @param bullsEyeCorners the array of bull's eye corners - * @return the array of aztec code corners - */ - fn get_matrix_corner_points(&self, bulls_eye_corners: &Vec) -> Vec { - return ::expand_square(bulls_eye_corners, 2 * self.nb_center_layers, &self.get_dimension()); - } - - /** - * Creates a BitMatrix by sampling the provided image. - * topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the - * diagonal just outside the bull's eye. - */ - fn sample_grid(&self, image: &BitMatrix, top_left: &ResultPoint, top_right: &ResultPoint, bottom_right: &ResultPoint, bottom_left: &ResultPoint) -> /* throws NotFoundException */Result> { - let sampler: GridSampler = GridSampler::get_instance(); - let dimension: i32 = self.get_dimension(); - let low: f32 = dimension / 2.0f - self.nb_center_layers; - let high: f32 = dimension / 2.0f + self.nb_center_layers; - return Ok(sampler.sample_grid(image, dimension, dimension, // topleft - low, // topleft - low, // topright - high, // topright - low, // bottomright - high, // bottomright - high, // bottomleft - low, // bottomleft - high, &top_left.get_x(), &top_left.get_y(), &top_right.get_x(), &top_right.get_y(), &bottom_right.get_x(), &bottom_right.get_y(), &bottom_left.get_x(), &bottom_left.get_y())); - } - - /** - * Samples a line. - * - * @param p1 start point (inclusive) - * @param p2 end point (exclusive) - * @param size number of bits - * @return the array of bits as an int (first bit is high-order bit of result) - */ - fn sample_line(&self, p1: &ResultPoint, p2: &ResultPoint, size: i32) -> i32 { - let mut result: i32 = 0; - let d: f32 = ::distance(p1, p2); - let module_size: f32 = d / size; - let px: f32 = p1.get_x(); - let py: f32 = p1.get_y(); - let dx: f32 = module_size * (p2.get_x() - p1.get_x()) / d; - let dy: f32 = module_size * (p2.get_y() - p1.get_y()) / d; - { - let mut i: i32 = 0; - while i < size { - { - if self.image.get(&MathUtils::round(px + i * dx), &MathUtils::round(py + i * dy)) { - result |= 1 << (size - i - 1); - } - } - i += 1; - } - } - - return result; - } - - /** - * @return true if the border of the rectangle passed in parameter is compound of white points only - * or black points only - */ - fn is_white_or_black_rectangle(&self, p1: &Point, p2: &Point, p3: &Point, p4: &Point) -> bool { - let corr: i32 = 3; - p1 = Point::new(&Math::max(0, p1.get_x() - corr), &Math::min(self.image.get_height() - 1, p1.get_y() + corr)); - p2 = Point::new(&Math::max(0, p2.get_x() - corr), &Math::max(0, p2.get_y() - corr)); - p3 = Point::new(&Math::min(self.image.get_width() - 1, p3.get_x() + corr), &Math::max(0, &Math::min(self.image.get_height() - 1, p3.get_y() - corr))); - p4 = Point::new(&Math::min(self.image.get_width() - 1, p4.get_x() + corr), &Math::min(self.image.get_height() - 1, p4.get_y() + corr)); - let c_init: i32 = self.get_color(p4, p1); - if c_init == 0 { - return false; - } - let mut c: i32 = self.get_color(p1, p2); - if c != c_init { - return false; - } - c = self.get_color(p2, p3); - if c != c_init { - return false; - } - c = self.get_color(p3, p4); - return c == c_init; - } - - /** - * Gets the color of a segment - * - * @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else - */ - fn get_color(&self, p1: &Point, p2: &Point) -> i32 { - let d: f32 = ::distance(p1, p2); - if d == 0.0f { - return 0; - } - let dx: f32 = (p2.get_x() - p1.get_x()) / d; - let dy: f32 = (p2.get_y() - p1.get_y()) / d; - let mut error: i32 = 0; - let mut px: f32 = p1.get_x(); - let mut py: f32 = p1.get_y(); - let color_model: bool = self.image.get(&p1.get_x(), &p1.get_y()); - let i_max: i32 = Math::floor(d) as i32; - { - let mut i: i32 = 0; - while i < i_max { - { - if self.image.get(&MathUtils::round(px), &MathUtils::round(py)) != color_model { - error += 1; - } - px += dx; - py += dy; - } - i += 1; - } - } - - let err_ratio: f32 = error / d; - if err_ratio > 0.1f && err_ratio < 0.9f { - return 0; - } - return if (err_ratio <= 0.1f) == color_model { 1 } else { -1 }; - } - - /** - * Gets the coordinate of the first point with a different color in the given direction - */ - fn get_first_different(&self, init: &Point, color: bool, dx: i32, dy: i32) -> Point { - let mut x: i32 = init.get_x() + dx; - let mut y: i32 = init.get_y() + dy; - while self.is_valid(x, y) && self.image.get(x, y) == color { - x += dx; - y += dy; - } - x -= dx; - y -= dy; - while self.is_valid(x, y) && self.image.get(x, y) == color { - x += dx; - } - x -= dx; - while self.is_valid(x, y) && self.image.get(x, y) == color { - y += dy; - } - y -= dy; - return Point::new(x, y); - } - - /** - * Expand the square represented by the corner points by pushing out equally in all directions - * - * @param cornerPoints the corners of the square, which has the bull's eye at its center - * @param oldSide the original length of the side of the square in the target bit matrix - * @param newSide the new length of the size of the square in the target bit matrix - * @return the corners of the expanded square - */ - fn expand_square( corner_points: &Vec, old_side: i32, new_side: i32) -> Vec { - let ratio: f32 = new_side / (2.0f * old_side); - let mut dx: f32 = corner_points[0].get_x() - corner_points[2].get_x(); - let mut dy: f32 = corner_points[0].get_y() - corner_points[2].get_y(); - let mut centerx: f32 = (corner_points[0].get_x() + corner_points[2].get_x()) / 2.0f; - let mut centery: f32 = (corner_points[0].get_y() + corner_points[2].get_y()) / 2.0f; - let result0: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy); - let result2: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy); - dx = corner_points[1].get_x() - corner_points[3].get_x(); - dy = corner_points[1].get_y() - corner_points[3].get_y(); - centerx = (corner_points[1].get_x() + corner_points[3].get_x()) / 2.0f; - centery = (corner_points[1].get_y() + corner_points[3].get_y()) / 2.0f; - let result1: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy); - let result3: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy); - return : vec![ResultPoint; 4] = vec![result0, result1, result2, result3, ] - ; - } - - fn is_valid(&self, x: i32, y: i32) -> bool { - return x >= 0 && x < self.image.get_width() && y >= 0 && y < self.image.get_height(); - } - - fn is_valid(&self, point: &ResultPoint) -> bool { - let x: i32 = MathUtils::round(&point.get_x()); - let y: i32 = MathUtils::round(&point.get_y()); - return self.is_valid(x, y); - } - - fn distance( a: &Point, b: &Point) -> f32 { - return MathUtils::distance(&a.get_x(), &a.get_y(), &b.get_x(), &b.get_y()); - } - - fn distance( a: &ResultPoint, b: &ResultPoint) -> f32 { - return MathUtils::distance(&a.get_x(), &a.get_y(), &b.get_x(), &b.get_y()); - } - - fn get_dimension(&self) -> i32 { - if self.compact { - return 4 * self.nb_layers + 11; - } - return 4 * self.nb_layers + 2 * ((2 * self.nb_layers + 6) / 15) + 15; - } - - struct Point { - - let x: i32; - - let y: i32; - } - - impl Point { - - fn to_result_point(&self) -> ResultPoint { - return ResultPoint::new(self.x, self.y); - } - - fn new( x: i32, y: i32) -> Point { - let .x = x; - let .y = y; - } - - fn get_x(&self) -> i32 { - return self.x; - } - - fn get_y(&self) -> i32 { - return self.y; - } - - pub fn to_string(&self) -> String { - return format!("<{} {}>", self.x, self.y); - } - } - -} - diff --git a/port_src/output/zxing/aztec/encoder/aztec_code.rs b/port_src/output/zxing/aztec/encoder/aztec_code.rs deleted file mode 100644 index 8aac172..0000000 --- a/port_src/output/zxing/aztec/encoder/aztec_code.rs +++ /dev/null @@ -1,93 +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::aztec::encoder; - -/** - * Aztec 2D code representation - * - * @author Rustam Abdullaev - */ -pub struct AztecCode { - - let compact: bool; - - let size: i32; - - let layers: i32; - - let code_words: i32; - - let matrix: BitMatrix; -} - -impl AztecCode { - - /** - * @return {@code true} if compact instead of full mode - */ - pub fn is_compact(&self) -> bool { - return self.compact; - } - - pub fn set_compact(&self, compact: bool) { - self.compact = compact; - } - - /** - * @return size in pixels (width and height) - */ - pub fn get_size(&self) -> i32 { - return self.size; - } - - pub fn set_size(&self, size: i32) { - self.size = size; - } - - /** - * @return number of levels - */ - pub fn get_layers(&self) -> i32 { - return self.layers; - } - - pub fn set_layers(&self, layers: i32) { - self.layers = layers; - } - - /** - * @return number of data codewords - */ - pub fn get_code_words(&self) -> i32 { - return self.code_words; - } - - pub fn set_code_words(&self, code_words: i32) { - self.codeWords = code_words; - } - - /** - * @return the symbol image - */ - pub fn get_matrix(&self) -> BitMatrix { - return self.matrix; - } - - pub fn set_matrix(&self, matrix: &BitMatrix) { - self.matrix = matrix; - } -} - diff --git a/port_src/output/zxing/aztec/encoder/binary_shift_token.rs b/port_src/output/zxing/aztec/encoder/binary_shift_token.rs deleted file mode 100644 index d9a3f3b..0000000 --- a/port_src/output/zxing/aztec/encoder/binary_shift_token.rs +++ /dev/null @@ -1,67 +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::aztec::encoder; - -struct BinaryShiftToken { - super: Token; - - let binary_shift_start: i32; - - let binary_shift_byte_count: i32; -} - -impl BinaryShiftToken { - - fn new( previous: &Token, binary_shift_start: i32, binary_shift_byte_count: i32) -> BinaryShiftToken { - super(previous); - let .binaryShiftStart = binary_shift_start; - let .binaryShiftByteCount = binary_shift_byte_count; - } - - pub fn append_to(&self, bit_array: &BitArray, text: &Vec) { - let bsbc: i32 = self.binary_shift_byte_count; - { - let mut i: i32 = 0; - while i < bsbc { - { - if i == 0 || (i == 31 && bsbc <= 62) { - // We need a header before the first character, and before - // character 31 when the total byte code is <= 62 - // BINARY_SHIFT - bit_array.append_bits(31, 5); - if bsbc > 62 { - bit_array.append_bits(bsbc - 31, 16); - } else if i == 0 { - // 1 <= binaryShiftByteCode <= 62 - bit_array.append_bits(&Math::min(bsbc, 31), 5); - } else { - // 32 <= binaryShiftCount <= 62 and i == 31 - bit_array.append_bits(bsbc - 31, 5); - } - } - bit_array.append_bits(text[self.binary_shift_start + i], 8); - } - i += 1; - } - } - - } - - pub fn to_string(&self) -> String { - return format!("<{}::{}>", self.binary_shift_start, (self.binary_shift_start + self.binary_shift_byte_count - 1)); - } -} - diff --git a/port_src/output/zxing/aztec/encoder/encoder.rs b/port_src/output/zxing/aztec/encoder/encoder.rs deleted file mode 100644 index 4bc61bc..0000000 --- a/port_src/output/zxing/aztec/encoder/encoder.rs +++ /dev/null @@ -1,516 +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::aztec::encoder; - -/** - * Generates Aztec 2D barcodes. - * - * @author Rustam Abdullaev - */ - -// default minimal percentage of error check words - const DEFAULT_EC_PERCENT: i32 = 33; - - const DEFAULT_AZTEC_LAYERS: i32 = 0; - - const MAX_NB_BITS: i32 = 32; - - const MAX_NB_BITS_COMPACT: i32 = 4; - - const WORD_SIZE: vec![Vec; 33] = vec![4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, ] -; -pub struct Encoder { -} - -impl Encoder { - - fn new() -> Encoder { - } - - /** - * Encodes the given string content as an Aztec symbol (without ECI code) - * - * @param data input data string; must be encodable as ISO/IEC 8859-1 (Latin-1) - * @return Aztec symbol matrix with metadata - */ - pub fn encode( data: &String) -> AztecCode { - return ::encode(&data.get_bytes(StandardCharsets::ISO_8859_1)); - } - - /** - * Encodes the given string content as an Aztec symbol (without ECI code) - * - * @param data input data string; must be encodable as ISO/IEC 8859-1 (Latin-1) - * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, - * a minimum of 23% + 3 words is recommended) - * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers - * @return Aztec symbol matrix with metadata - */ - pub fn encode( data: &String, min_e_c_c_percent: i32, user_specified_layers: i32) -> AztecCode { - return ::encode(&data.get_bytes(StandardCharsets::ISO_8859_1), min_e_c_c_percent, user_specified_layers, null); - } - - /** - * Encodes the given string content as an Aztec symbol - * - * @param data input data string - * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, - * a minimum of 23% + 3 words is recommended) - * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers - * @param charset character set in which to encode string using ECI; if null, no ECI code - * will be inserted, and the string must be encodable as ISO/IEC 8859-1 - * (Latin-1), the default encoding of the symbol. - * @return Aztec symbol matrix with metadata - */ - pub fn encode( data: &String, min_e_c_c_percent: i32, user_specified_layers: i32, charset: &Charset) -> AztecCode { - let bytes: Vec = data.get_bytes( if null != charset { charset } else { StandardCharsets::ISO_8859_1 }); - return ::encode(&bytes, min_e_c_c_percent, user_specified_layers, &charset); - } - - /** - * Encodes the given binary content as an Aztec symbol (without ECI code) - * - * @param data input data string - * @return Aztec symbol matrix with metadata - */ - pub fn encode( data: &Vec) -> AztecCode { - return ::encode(&data, DEFAULT_EC_PERCENT, DEFAULT_AZTEC_LAYERS, null); - } - - /** - * Encodes the given binary content as an Aztec symbol (without ECI code) - * - * @param data input data string - * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, - * a minimum of 23% + 3 words is recommended) - * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers - * @return Aztec symbol matrix with metadata - */ - pub fn encode( data: &Vec, min_e_c_c_percent: i32, user_specified_layers: i32) -> AztecCode { - return ::encode(&data, min_e_c_c_percent, user_specified_layers, null); - } - - /** - * Encodes the given binary content as an Aztec symbol - * - * @param data input data string - * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, - * a minimum of 23% + 3 words is recommended) - * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers - * @param charset character set to mark using ECI; if null, no ECI code will be inserted, and the - * default encoding of ISO/IEC 8859-1 will be assuming by readers. - * @return Aztec symbol matrix with metadata - */ - pub fn encode( data: &Vec, min_e_c_c_percent: i32, user_specified_layers: i32, charset: &Charset) -> AztecCode { - // High-level encode - let bits: BitArray = HighLevelEncoder::new(&data, &charset).encode(); - // stuff bits and choose symbol size - let ecc_bits: i32 = bits.get_size() * min_e_c_c_percent / 100 + 11; - let total_size_bits: i32 = bits.get_size() + ecc_bits; - let mut compact: bool; - let mut layers: i32; - let total_bits_in_layer: i32; - let word_size: i32; - let stuffed_bits: BitArray; - if user_specified_layers != DEFAULT_AZTEC_LAYERS { - compact = user_specified_layers < 0; - layers = Math::abs(user_specified_layers); - if layers > ( if compact { MAX_NB_BITS_COMPACT } else { MAX_NB_BITS }) { - throw IllegalArgumentException::new(&String::format("Illegal value %s for layers", user_specified_layers)); - } - total_bits_in_layer = self.total_bits_in_layer(layers, compact); - word_size = WORD_SIZE[layers]; - let usable_bits_in_layers: i32 = total_bits_in_layer - (total_bits_in_layer % word_size); - stuffed_bits = ::stuff_bits(bits, word_size); - if stuffed_bits.get_size() + ecc_bits > usable_bits_in_layers { - throw IllegalArgumentException::new("Data to large for user specified layer"); - } - if compact && stuffed_bits.get_size() > word_size * 64 { - // Compact format only allows 64 data words, though C4 can hold more words than that - throw IllegalArgumentException::new("Data to large for user specified layer"); - } - } else { - word_size = 0; - stuffed_bits = null; - // is the same size, but has more data. - { - let mut i: i32 = 0; - loop { - { - if i > MAX_NB_BITS { - throw IllegalArgumentException::new("Data too large for an Aztec code"); - } - compact = i <= 3; - layers = if compact { i + 1 } else { i }; - total_bits_in_layer = self.total_bits_in_layer(layers, compact); - if total_size_bits > total_bits_in_layer { - continue; - } - // wordSize has changed - if stuffed_bits == null || word_size != WORD_SIZE[layers] { - word_size = WORD_SIZE[layers]; - stuffed_bits = ::stuff_bits(bits, word_size); - } - let usable_bits_in_layers: i32 = total_bits_in_layer - (total_bits_in_layer % word_size); - if compact && stuffed_bits.get_size() > word_size * 64 { - // Compact format only allows 64 data words, though C4 can hold more words than that - continue; - } - if stuffed_bits.get_size() + ecc_bits <= usable_bits_in_layers { - break; - } - } - i += 1; - } - } - - } - let message_bits: BitArray = ::generate_check_words(stuffed_bits, total_bits_in_layer, word_size); - // generate mode message - let message_size_in_words: i32 = stuffed_bits.get_size() / word_size; - let mode_message: BitArray = ::generate_mode_message(compact, layers, message_size_in_words); - // allocate symbol - // not including alignment lines - let base_matrix_size: i32 = ( if compact { 11 } else { 14 }) + layers * 4; - let alignment_map: [i32; base_matrix_size] = [0; base_matrix_size]; - let matrix_size: i32; - if compact { - // no alignment marks in compact mode, alignmentMap is a no-op - matrix_size = base_matrix_size; - { - let mut i: i32 = 0; - while i < alignment_map.len() { - { - alignment_map[i] = i; - } - i += 1; - } - } - - } else { - matrix_size = base_matrix_size + 1 + 2 * ((base_matrix_size / 2 - 1) / 15); - let orig_center: i32 = base_matrix_size / 2; - let center: i32 = matrix_size / 2; - { - let mut i: i32 = 0; - while i < orig_center { - { - let new_offset: i32 = i + i / 15; - alignment_map[orig_center - i - 1] = center - new_offset - 1; - alignment_map[orig_center + i] = center + new_offset + 1; - } - i += 1; - } - } - - } - let matrix: BitMatrix = BitMatrix::new(matrix_size); - // draw data bits - { - let mut i: i32 = 0, let row_offset: i32 = 0; - while i < layers { - { - let row_size: i32 = (layers - i) * 4 + ( if compact { 9 } else { 12 }); - { - let mut j: i32 = 0; - while j < row_size { - { - let column_offset: i32 = j * 2; - { - let mut k: i32 = 0; - while k < 2 { - { - if message_bits.get(row_offset + column_offset + k) { - matrix.set(alignment_map[i * 2 + k], alignment_map[i * 2 + j]); - } - if message_bits.get(row_offset + row_size * 2 + column_offset + k) { - matrix.set(alignment_map[i * 2 + j], alignment_map[base_matrix_size - 1 - i * 2 - k]); - } - if message_bits.get(row_offset + row_size * 4 + column_offset + k) { - matrix.set(alignment_map[base_matrix_size - 1 - i * 2 - k], alignment_map[base_matrix_size - 1 - i * 2 - j]); - } - if message_bits.get(row_offset + row_size * 6 + column_offset + k) { - matrix.set(alignment_map[base_matrix_size - 1 - i * 2 - j], alignment_map[i * 2 + k]); - } - } - k += 1; - } - } - - } - j += 1; - } - } - - row_offset += row_size * 8; - } - i += 1; - } - } - - // draw mode message - ::draw_mode_message(matrix, compact, matrix_size, mode_message); - // draw alignment marks - if compact { - ::draw_bulls_eye(matrix, matrix_size / 2, 5); - } else { - ::draw_bulls_eye(matrix, matrix_size / 2, 7); - { - let mut i: i32 = 0, let mut j: i32 = 0; - while i < base_matrix_size / 2 - 1 { - { - { - let mut k: i32 = (matrix_size / 2) & 1; - while k < matrix_size { - { - matrix.set(matrix_size / 2 - j, k); - matrix.set(matrix_size / 2 + j, k); - matrix.set(k, matrix_size / 2 - j); - matrix.set(k, matrix_size / 2 + j); - } - k += 2; - } - } - - } - i += 15; - j += 16; - } - } - - } - let aztec: AztecCode = AztecCode::new(); - aztec.set_compact(compact); - aztec.set_size(matrix_size); - aztec.set_layers(layers); - aztec.set_code_words(message_size_in_words); - aztec.set_matrix(matrix); - return aztec; - } - - fn draw_bulls_eye( matrix: &BitMatrix, center: i32, size: i32) { - { - let mut i: i32 = 0; - while i < size { - { - { - let mut j: i32 = center - i; - while j <= center + i { - { - matrix.set(j, center - i); - matrix.set(j, center + i); - matrix.set(center - i, j); - matrix.set(center + i, j); - } - j += 1; - } - } - - } - i += 2; - } - } - - matrix.set(center - size, center - size); - matrix.set(center - size + 1, center - size); - matrix.set(center - size, center - size + 1); - matrix.set(center + size, center - size); - matrix.set(center + size, center - size + 1); - matrix.set(center + size, center + size - 1); - } - - fn generate_mode_message( compact: bool, layers: i32, message_size_in_words: i32) -> BitArray { - let mode_message: BitArray = BitArray::new(); - if compact { - mode_message.append_bits(layers - 1, 2); - mode_message.append_bits(message_size_in_words - 1, 6); - mode_message = ::generate_check_words(mode_message, 28, 4); - } else { - mode_message.append_bits(layers - 1, 5); - mode_message.append_bits(message_size_in_words - 1, 11); - mode_message = ::generate_check_words(mode_message, 40, 4); - } - return mode_message; - } - - fn draw_mode_message( matrix: &BitMatrix, compact: bool, matrix_size: i32, mode_message: &BitArray) { - let center: i32 = matrix_size / 2; - if compact { - { - let mut i: i32 = 0; - while i < 7 { - { - let offset: i32 = center - 3 + i; - if mode_message.get(i) { - matrix.set(offset, center - 5); - } - if mode_message.get(i + 7) { - matrix.set(center + 5, offset); - } - if mode_message.get(20 - i) { - matrix.set(offset, center + 5); - } - if mode_message.get(27 - i) { - matrix.set(center - 5, offset); - } - } - i += 1; - } - } - - } else { - { - let mut i: i32 = 0; - while i < 10 { - { - let offset: i32 = center - 5 + i + i / 5; - if mode_message.get(i) { - matrix.set(offset, center - 7); - } - if mode_message.get(i + 10) { - matrix.set(center + 7, offset); - } - if mode_message.get(29 - i) { - matrix.set(offset, center + 7); - } - if mode_message.get(39 - i) { - matrix.set(center - 7, offset); - } - } - i += 1; - } - } - - } - } - - fn generate_check_words( bit_array: &BitArray, total_bits: i32, word_size: i32) -> BitArray { - // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed - let message_size_in_words: i32 = bit_array.get_size() / word_size; - let rs: ReedSolomonEncoder = ReedSolomonEncoder::new(&::get_g_f(word_size)); - let total_words: i32 = total_bits / word_size; - let message_words: Vec = ::bits_to_words(bit_array, word_size, total_words); - rs.encode(&message_words, total_words - message_size_in_words); - let start_pad: i32 = total_bits % word_size; - let message_bits: BitArray = BitArray::new(); - message_bits.append_bits(0, start_pad); - for let message_word: i32 in message_words { - message_bits.append_bits(message_word, word_size); - } - return message_bits; - } - - fn bits_to_words( stuffed_bits: &BitArray, word_size: i32, total_words: i32) -> Vec { - let mut message: [i32; total_words] = [0; total_words]; - let mut i: i32; - let mut n: i32; - { - i = 0; - n = stuffed_bits.get_size() / word_size; - while i < n { - { - let mut value: i32 = 0; - { - let mut j: i32 = 0; - while j < word_size { - { - value |= if stuffed_bits.get(i * word_size + j) { (1 << word_size - j - 1) } else { 0 }; - } - j += 1; - } - } - - message[i] = value; - } - i += 1; - } - } - - return message; - } - - fn get_g_f( word_size: i32) -> GenericGF { - match word_size { - 4 => - { - return GenericGF::AZTEC_PARAM; - } - 6 => - { - return GenericGF::AZTEC_DATA_6; - } - 8 => - { - return GenericGF::AZTEC_DATA_8; - } - 10 => - { - return GenericGF::AZTEC_DATA_10; - } - 12 => - { - return GenericGF::AZTEC_DATA_12; - } - _ => - { - throw IllegalArgumentException::new(format!("Unsupported word size {}", word_size)); - } - } - } - - fn stuff_bits( bits: &BitArray, word_size: i32) -> BitArray { - let out: BitArray = BitArray::new(); - let n: i32 = bits.get_size(); - let mask: i32 = (1 << word_size) - 2; - { - let mut i: i32 = 0; - while i < n { - { - let mut word: i32 = 0; - { - let mut j: i32 = 0; - while j < word_size { - { - if i + j >= n || bits.get(i + j) { - word |= 1 << (word_size - 1 - j); - } - } - j += 1; - } - } - - if (word & mask) == mask { - out.append_bits(word & mask, word_size); - i -= 1; - } else if (word & mask) == 0 { - out.append_bits(word | 1, word_size); - i -= 1; - } else { - out.append_bits(word, word_size); - } - } - i += word_size; - } - } - - return out; - } - - fn total_bits_in_layer( layers: i32, compact: bool) -> i32 { - return (( if compact { 88 } else { 112 }) + 16 * layers) * layers; - } -} - diff --git a/port_src/output/zxing/aztec/encoder/high_level_encoder.rs b/port_src/output/zxing/aztec/encoder/high_level_encoder.rs deleted file mode 100644 index e3de129..0000000 --- a/port_src/output/zxing/aztec/encoder/high_level_encoder.rs +++ /dev/null @@ -1,370 +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::aztec::encoder; - -/** - * This produces nearly optimal encodings of text into the first-level of - * encoding used by Aztec code. - * - * It uses a dynamic algorithm. For each prefix of the string, it determines - * a set of encodings that could lead to this prefix. We repeatedly add a - * character and generate a new set of optimal encodings until we have read - * through the entire input. - * - * @author Frank Yellin - * @author Rustam Abdullaev - */ - - const MODE_NAMES: vec![Vec; 5] = vec!["UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT", ] -; - -// 5 bits - const MODE_UPPER: i32 = 0; - -// 5 bits - const MODE_LOWER: i32 = 1; - -// 4 bits - const MODE_DIGIT: i32 = 2; - -// 5 bits - const MODE_MIXED: i32 = 3; - -// 5 bits - const MODE_PUNCT: i32 = 4; - -// The Latch Table shows, for each pair of Modes, the optimal method for -// getting from one mode to another. In the worst possible case, this can -// be up to 14 bits. In the best possible case, we are already there! -// The high half-word of each entry gives the number of bits. -// The low half-word of each entry are the actual bits necessary to change - const LATCH_TABLE: vec![vec![Vec>; 5]; 5] = vec![vec![0, // UPPER -> LOWER -(5 << 16) + 28, // UPPER -> DIGIT -(5 << 16) + 30, // UPPER -> MIXED -(5 << 16) + 29, // UPPER -> MIXED -> PUNCT -(10 << 16) + (29 << 5) + 30, ] -, vec![// LOWER -> DIGIT -> UPPER -(9 << 16) + (30 << 4) + 14, 0, // LOWER -> DIGIT -(5 << 16) + 30, // LOWER -> MIXED -(5 << 16) + 29, // LOWER -> MIXED -> PUNCT -(10 << 16) + (29 << 5) + 30, ] -, vec![// DIGIT -> UPPER -(4 << 16) + 14, // DIGIT -> UPPER -> LOWER -(9 << 16) + (14 << 5) + 28, 0, // DIGIT -> UPPER -> MIXED -(9 << 16) + (14 << 5) + 29, (14 << 16) + (14 << 10) + (29 << 5) + 30, ] -, vec![// MIXED -> UPPER -(5 << 16) + 29, // MIXED -> LOWER -(5 << 16) + 28, // MIXED -> UPPER -> DIGIT -(10 << 16) + (29 << 5) + 30, 0, // MIXED -> PUNCT -(5 << 16) + 30, ] -, vec![// PUNCT -> UPPER -(5 << 16) + 31, // PUNCT -> UPPER -> LOWER -(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> DIGIT -(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> MIXED -(10 << 16) + (31 << 5) + 29, 0, ] -, ] -; - -// A reverse mapping from [mode][char] to the encoding for that character -// in that mode. An entry of 0 indicates no mapping exists. - const CHAR_MAP: [[i32; 256]; 5] = [[0; 256]; 5]; - -// A map showing the available shift codes. (The shifts to BINARY are not -// shown -// mode shift codes, per table - const SHIFT_TABLE: [[i32; 6]; 6] = [[0; 6]; 6]; -pub struct HighLevelEncoder { - - let text: Vec; - - let mut charset: Charset; -} - -impl HighLevelEncoder { - - static { - CHAR_MAP[MODE_UPPER][' '] = 1; - { - let mut c: i32 = 'A'; - while c <= 'Z' { - { - CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2; - } - c += 1; - } - } - - CHAR_MAP[MODE_LOWER][' '] = 1; - { - let mut c: i32 = 'a'; - while c <= 'z' { - { - CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2; - } - c += 1; - } - } - - CHAR_MAP[MODE_DIGIT][' '] = 1; - { - let mut c: i32 = '0'; - while c <= '9' { - { - CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2; - } - c += 1; - } - } - - CHAR_MAP[MODE_DIGIT][','] = 12; - CHAR_MAP[MODE_DIGIT]['.'] = 13; - let mixed_table: vec![Vec; 28] = vec!['\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n', '\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^', '_', '`', '|', '~', '\177', ] - ; - { - let mut i: i32 = 0; - while i < mixed_table.len() { - { - CHAR_MAP[MODE_MIXED][mixed_table[i]] = i; - } - i += 1; - } - } - - let punct_table: vec![Vec; 31] = vec!['\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', ] - ; - { - let mut i: i32 = 0; - while i < punct_table.len() { - { - if punct_table[i] > 0 { - CHAR_MAP[MODE_PUNCT][punct_table[i]] = i; - } - } - i += 1; - } - } - - } - - static { - for let table: Vec in SHIFT_TABLE { - Arrays::fill(&table, -1); - } - SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0; - SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0; - SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28; - SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0; - SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0; - SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15; - } - - pub fn new( text: &Vec) -> HighLevelEncoder { - let .text = text; - let .charset = null; - } - - pub fn new( text: &Vec, charset: &Charset) -> HighLevelEncoder { - let .text = text; - let .charset = charset; - } - - /** - * @return text represented by this encoder encoded as a {@link BitArray} - */ - pub fn encode(&self) -> BitArray { - let initial_state: State = State::INITIAL_STATE; - if self.charset != null { - let eci: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i(&self.charset); - if null == eci { - throw IllegalArgumentException::new(format!("No ECI code for character set {}", self.charset)); - } - initial_state = initial_state.append_f_l_gn(&eci.get_value()); - } - let mut states: Collection = Collections::singleton_list(initial_state); - { - let mut index: i32 = 0; - while index < self.text.len() { - { - let pair_code: i32; - let next_char: i32 = if index + 1 < self.text.len() { self.text[index + 1] } else { 0 }; - match self.text[index] { - '\r' => - { - pair_code = if next_char == '\n' { 2 } else { 0 }; - break; - } - '.' => - { - pair_code = if next_char == ' ' { 3 } else { 0 }; - break; - } - ',' => - { - pair_code = if next_char == ' ' { 4 } else { 0 }; - break; - } - ':' => - { - pair_code = if next_char == ' ' { 5 } else { 0 }; - break; - } - _ => - { - pair_code = 0; - } - } - if pair_code > 0 { - // We have one of the four special PUNCT pairs. Treat them specially. - // Get a new set of states for the two new characters. - states = ::update_state_list_for_pair(&states, index, pair_code); - index += 1; - } else { - // Get a new set of states for the new character. - states = self.update_state_list_for_char(&states, index); - } - } - index += 1; - } - } - - // We are left with a set of states. Find the shortest one. - let min_state: State = Collections::min(&states, Comparator::new() { - - pub fn compare(&self, a: &State, b: &State) -> i32 { - return a.get_bit_count() - b.get_bit_count(); - } - }); - // Convert it to a bit array, and return. - return min_state.to_bit_array(&self.text); - } - - // We update a set of states for a new character by updating each state - // for the new character, merging the results, and then removing the - // non-optimal states. - fn update_state_list_for_char(&self, states: &Iterable, index: i32) -> Collection { - let result: Collection = LinkedList<>::new(); - for let state: State in states { - self.update_state_for_char(state, index, &result); - } - return ::simplify_states(&result); - } - - // Return a set of states that represent the possible ways of updating this - // state for the next character. The resulting set of states are added to - // the "result" list. - fn update_state_for_char(&self, state: &State, index: i32, result: &Collection) { - let ch: char = (self.text[index] & 0xFF) as char; - let char_in_current_table: bool = CHAR_MAP[state.get_mode()][ch] > 0; - let state_no_binary: State = null; - { - let mut mode: i32 = 0; - while mode <= MODE_PUNCT { - { - let char_in_mode: i32 = CHAR_MAP[mode][ch]; - if char_in_mode > 0 { - if state_no_binary == null { - // Only create stateNoBinary the first time it's required. - state_no_binary = state.end_binary_shift(index); - } - // Try generating the character by latching to its mode - if !char_in_current_table || mode == state.get_mode() || mode == MODE_DIGIT { - // If the character is in the current table, we don't want to latch to - // any other mode except possibly digit (which uses only 4 bits). Any - // other latch would be equally successful *after* this character, and - // so wouldn't save any bits. - let latch_state: State = state_no_binary.latch_and_append(mode, char_in_mode); - result.add(latch_state); - } - // Try generating the character by switching to its mode. - if !char_in_current_table && SHIFT_TABLE[state.get_mode()][mode] >= 0 { - // It never makes sense to temporarily shift to another mode if the - // character exists in the current mode. That can never save bits. - let shift_state: State = state_no_binary.shift_and_append(mode, char_in_mode); - result.add(shift_state); - } - } - } - mode += 1; - } - } - - if state.get_binary_shift_byte_count() > 0 || CHAR_MAP[state.get_mode()][ch] == 0 { - // It's never worthwhile to go into binary shift mode if you're not already - // in binary shift mode, and the character exists in your current mode. - // That can never save bits over just outputting the char in the current mode. - let binary_state: State = state.add_binary_shift_char(index); - result.add(binary_state); - } - } - - fn update_state_list_for_pair( states: &Iterable, index: i32, pair_code: i32) -> Collection { - let result: Collection = LinkedList<>::new(); - for let state: State in states { - ::update_state_for_pair(state, index, pair_code, &result); - } - return ::simplify_states(&result); - } - - fn update_state_for_pair( state: &State, index: i32, pair_code: i32, result: &Collection) { - let state_no_binary: State = state.end_binary_shift(index); - // Possibility 1. Latch to MODE_PUNCT, and then append this code - result.add(&state_no_binary.latch_and_append(MODE_PUNCT, pair_code)); - if state.get_mode() != MODE_PUNCT { - // Possibility 2. Shift to MODE_PUNCT, and then append this code. - // Every state except MODE_PUNCT (handled above) can shift - result.add(&state_no_binary.shift_and_append(MODE_PUNCT, pair_code)); - } - if pair_code == 3 || pair_code == 4 { - // both characters are in DIGITS. Sometimes better to just add two digits - let digit_state: State = state_no_binary.latch_and_append(MODE_DIGIT, // period or comma in DIGIT - 16 - pair_code).latch_and_append(MODE_DIGIT, // space in DIGIT - 1); - result.add(digit_state); - } - if state.get_binary_shift_byte_count() > 0 { - // It only makes sense to do the characters as binary if we're already - // in binary mode. - let binary_state: State = state.add_binary_shift_char(index).add_binary_shift_char(index + 1); - result.add(binary_state); - } - } - - fn simplify_states( states: &Iterable) -> Collection { - let result: Deque = LinkedList<>::new(); - for let new_state: State in states { - let mut add: bool = true; - { - let iterator: Iterator = result.iterator(); - while iterator.has_next(){ - let old_state: State = iterator.next(); - if old_state.is_better_than_or_equal_to(new_state) { - add = false; - break; - } - if new_state.is_better_than_or_equal_to(old_state) { - iterator.remove(); - } - } - } - - if add { - result.add_first(new_state); - } - } - return result; - } -} - diff --git a/port_src/output/zxing/aztec/encoder/simple_token.rs b/port_src/output/zxing/aztec/encoder/simple_token.rs deleted file mode 100644 index 2a332f6..0000000 --- a/port_src/output/zxing/aztec/encoder/simple_token.rs +++ /dev/null @@ -1,45 +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::aztec::encoder; - -struct SimpleToken { - super: Token; - - // For normal words, indicates value and bitCount - let value: i16; - - let bit_count: i16; -} - -impl SimpleToken { - - fn new( previous: &Token, value: i32, bit_count: i32) -> SimpleToken { - super(previous); - let .value = value as i16; - let .bitCount = bit_count as i16; - } - - fn append_to(&self, bit_array: &BitArray, text: &Vec) { - bit_array.append_bits(self.value, self.bit_count); - } - - pub fn to_string(&self) -> String { - let mut value: i32 = self.value & ((1 << self.bit_count) - 1); - value |= 1 << self.bit_count; - return '<' + Integer::to_binary_string(value | (1 << self.bit_count))::substring(1) + '>'; - } -} - diff --git a/port_src/output/zxing/aztec/encoder/state.rs b/port_src/output/zxing/aztec/encoder/state.rs deleted file mode 100644 index fa4f17a..0000000 --- a/port_src/output/zxing/aztec/encoder/state.rs +++ /dev/null @@ -1,211 +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::aztec::encoder; - -/** - * State represents all information about a sequence necessary to generate the current output. - * Note that a state is immutable. - */ - - const INITIAL_STATE: State = State::new(Token::EMPTY, HighLevelEncoder::MODE_UPPER, 0, 0); -struct State { - - // The current mode of the encoding (or the mode to which we'll return if - // we're in Binary Shift mode. - let mode: i32; - - // The list of tokens that we output. If we are in Binary Shift mode, this - // token list does *not* yet included the token for those bytes - let token: Token; - - // If non-zero, the number of most recent bytes that should be output - // in Binary Shift mode. - let binary_shift_byte_count: i32; - - // The total number of bits generated (including Binary Shift). - let bit_count: i32; - - let binary_shift_cost: i32; -} - -impl State { - - fn new( token: &Token, mode: i32, binary_bytes: i32, bit_count: i32) -> State { - let .token = token; - let .mode = mode; - let .binaryShiftByteCount = binary_bytes; - let .bitCount = bit_count; - let .binaryShiftCost = ::calculate_binary_shift_cost(binary_bytes); - } - - fn get_mode(&self) -> i32 { - return self.mode; - } - - fn get_token(&self) -> Token { - return self.token; - } - - fn get_binary_shift_byte_count(&self) -> i32 { - return self.binary_shift_byte_count; - } - - fn get_bit_count(&self) -> i32 { - return self.bit_count; - } - - fn append_f_l_gn(&self, eci: i32) -> State { - // 0: FLG(n) - let result: State = self.shift_and_append(HighLevelEncoder::MODE_PUNCT, 0); - let mut token: Token = result.token; - let bits_added: i32 = 3; - if eci < 0 { - // 0: FNC1 - token = token.add(0, 3); - } else if eci > 999999 { - throw IllegalArgumentException::new("ECI code must be between 0 and 999999"); - } else { - let eci_digits: Vec = Integer::to_string(eci)::get_bytes(StandardCharsets::ISO_8859_1); - // 1-6: number of ECI digits - token = token.add(eci_digits.len(), 3); - for let eci_digit: i8 in eci_digits { - token = token.add(eci_digit - '0' + 2, 4); - } - bits_added += eci_digits.len() * 4; - } - return State::new(token, self.mode, 0, self.bit_count + bits_added); - } - - // Create a new state representing this state with a latch to a (not - // necessary different) mode, and then a code. - fn latch_and_append(&self, mode: i32, value: i32) -> State { - let bit_count: i32 = self.bitCount; - let mut token: Token = self.token; - if mode != self.mode { - let latch: i32 = HighLevelEncoder::LATCH_TABLE[self.mode][mode]; - token = token.add(latch & 0xFFFF, latch >> 16); - bit_count += latch >> 16; - } - let latch_mode_bit_count: i32 = if mode == HighLevelEncoder::MODE_DIGIT { 4 } else { 5 }; - token = token.add(value, latch_mode_bit_count); - return State::new(token, mode, 0, bit_count + latch_mode_bit_count); - } - - // Create a new state representing this state, with a temporary shift - // to a different mode to output a single value. - fn shift_and_append(&self, mode: i32, value: i32) -> State { - let mut token: Token = self.token; - let this_mode_bit_count: i32 = if self.mode == HighLevelEncoder::MODE_DIGIT { 4 } else { 5 }; - // Shifts exist only to UPPER and PUNCT, both with tokens size 5. - token = token.add(HighLevelEncoder::SHIFT_TABLE[self.mode][mode], this_mode_bit_count); - token = token.add(value, 5); - return State::new(token, self.mode, 0, self.bitCount + this_mode_bit_count + 5); - } - - // Create a new state representing this state, but an additional character - // output in Binary Shift mode. - fn add_binary_shift_char(&self, index: i32) -> State { - let mut token: Token = self.token; - let mut mode: i32 = self.mode; - let bit_count: i32 = self.bitCount; - if self.mode == HighLevelEncoder::MODE_PUNCT || self.mode == HighLevelEncoder::MODE_DIGIT { - let latch: i32 = HighLevelEncoder::LATCH_TABLE[mode][HighLevelEncoder::MODE_UPPER]; - token = token.add(latch & 0xFFFF, latch >> 16); - bit_count += latch >> 16; - mode = HighLevelEncoder::MODE_UPPER; - } - let delta_bit_count: i32 = if (self.binary_shift_byte_count == 0 || self.binary_shift_byte_count == 31) { 18 } else { if (self.binary_shift_byte_count == 62) { 9 } else { 8 } }; - let mut result: State = State::new(token, mode, self.binary_shift_byte_count + 1, bit_count + delta_bit_count); - if result.binaryShiftByteCount == 2047 + 31 { - // The string is as long as it's allowed to be. We should end it. - result = result.end_binary_shift(index + 1); - } - return result; - } - - // Create the state identical to this one, but we are no longer in - // Binary Shift mode. - fn end_binary_shift(&self, index: i32) -> State { - if self.binary_shift_byte_count == 0 { - return self; - } - let mut token: Token = self.token; - token = token.add_binary_shift(index - self.binary_shift_byte_count, self.binary_shift_byte_count); - return State::new(token, self.mode, 0, self.bitCount); - } - - // Returns true if "this" state is better (or equal) to be in than "that" - // state under all possible circumstances. - fn is_better_than_or_equal_to(&self, other: &State) -> bool { - let new_mode_bit_count: i32 = self.bitCount + (HighLevelEncoder::LATCH_TABLE[self.mode][other.mode] >> 16); - if self.binaryShiftByteCount < other.binaryShiftByteCount { - // add additional B/S encoding cost of other, if any - new_mode_bit_count += other.binaryShiftCost - self.binaryShiftCost; - } else if self.binaryShiftByteCount > other.binaryShiftByteCount && other.binaryShiftByteCount > 0 { - // maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it) - new_mode_bit_count += 10; - } - return new_mode_bit_count <= other.bitCount; - } - - fn to_bit_array(&self, text: &Vec) -> BitArray { - let symbols: List = ArrayList<>::new(); - { - let mut token: Token = self.end_binary_shift(text.len()).token; - while token != null { - { - symbols.add(token); - } - token = token.get_previous(); - } - } - - let bit_array: BitArray = BitArray::new(); - // Add each token to the result in forward order - { - let mut i: i32 = symbols.size() - 1; - while i >= 0 { - { - symbols.get(i).append_to(bit_array, &text); - } - i -= 1; - } - } - - return bit_array; - } - - pub fn to_string(&self) -> String { - return String::format("%s bits=%d bytes=%d", HighLevelEncoder::MODE_NAMES[self.mode], self.bit_count, self.binary_shift_byte_count); - } - - fn calculate_binary_shift_cost( binary_shift_byte_count: i32) -> i32 { - if binary_shift_byte_count > 62 { - // B/S with extended length - return 21; - } - if binary_shift_byte_count > 31 { - // two B/S - return 20; - } - if binary_shift_byte_count > 0 { - // one B/S - return 10; - } - return 0; - } -} - diff --git a/port_src/output/zxing/aztec/encoder/token.rs b/port_src/output/zxing/aztec/encoder/token.rs deleted file mode 100644 index 04bd0f5..0000000 --- a/port_src/output/zxing/aztec/encoder/token.rs +++ /dev/null @@ -1,46 +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::aztec::encoder; - - - const EMPTY: Token = SimpleToken::new(null, 0, 0); -struct Token { - - let previous: Token; -} - -impl Token { - - fn new( previous: &Token) -> Token { - let .previous = previous; - } - - fn get_previous(&self) -> Token { - return self.previous; - } - - fn add(&self, value: i32, bit_count: i32) -> Token { - return SimpleToken::new(self, value, bit_count); - } - - fn add_binary_shift(&self, start: i32, byte_count: i32) -> Token { - //int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21); - return BinaryShiftToken::new(self, start, byte_count); - } - - fn append_to(&self, bit_array: &BitArray, text: &Vec) ; -} - diff --git a/src/aztec.rs b/src/aztec.rs index 9f06192..25fa82c 100644 --- a/src/aztec.rs +++ b/src/aztec.rs @@ -1,5 +1,232 @@ +pub mod decoder; +pub mod detector; +pub mod encoder; + +use crate::{ResultPoint,BarcodeFormat,EncodeHintType,Writer,Reader}; +use crate::common::{BitMatrix,DetectorResult,DecoderResult}; +use crate::{BarcodeFormat,BinaryBitmap,DecodeHintType,FormatException,NotFoundException,Reader,Result,ResultMetadataType,ResultPoint,ResultPointCallback}; +use crate::aztec::decoder::Decoder; +use crate::aztec::detector::Detector; + +use crate::aztec::encoder{AztecCode,Encoder}; + + // AztecDetectorResult.java +/** + *

Extends {@link DetectorResult} with more information specific to the Aztec format, + * like the number of layers and whether it's compact.

+ * + * @author Sean Owen + */ +pub struct AztecDetectorResult { + super: DetectorResult; + + let compact: bool; + + let nb_datablocks: i32; + + let nb_layers: i32; +} + +impl DetectorResult for AztecDetectorResult { + +} + +impl AztecDetectorResult { + + pub fn new( bits: &BitMatrix, points: &Vec, compact: bool, nb_datablocks: i32, nb_layers: i32) -> AztecDetectorResult { + super(bits, points); + let .compact = compact; + let .nbDatablocks = nb_datablocks; + let .nbLayers = nb_layers; + } + + pub fn get_nb_layers(&self) -> i32 { + return self.nb_layers; + } + + pub fn get_nb_datablocks(&self) -> i32 { + return self.nb_datablocks; + } + + pub fn is_compact(&self) -> bool { + return self.compact; + } +} // AztecReader.java -// AztecWriter.java \ No newline at end of file +/** + * This implementation can detect and decode Aztec codes in an image. + * + * @author David Olivier + */ +pub struct AztecReader { +} + +impl Reader for AztecReader { + + /** + * Locates and decodes a Data Matrix code in an image. + * + * @return a String representing the content encoded by the Data Matrix code + * @throws NotFoundException if a Data Matrix code cannot be found + * @throws FormatException if a Data Matrix code cannot be decoded + */ + pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, FormatException */Result> { + return Ok(self.decode(image, null)); + } + + pub fn decode(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException, FormatException */Result> { + let not_found_exception: NotFoundException = null; + let format_exception: FormatException = null; + let detector: Detector = Detector::new(&image.get_black_matrix()); + let mut points: Vec = null; + let decoder_result: DecoderResult = null; + let tryResult1 = 0; + 'try1: loop { + { + let detector_result: AztecDetectorResult = detector.detect(false); + points = detector_result.get_points(); + decoder_result = Decoder::new().decode(detector_result); + } + break 'try1 + } + match tryResult1 { + catch ( e: &NotFoundException) { + not_found_exception = e; + } catch ( e: &FormatException) { + format_exception = e; + } 0 => break + } + + if decoder_result == null { + let tryResult1 = 0; + 'try1: loop { + { + let detector_result: AztecDetectorResult = detector.detect(true); + points = detector_result.get_points(); + decoder_result = Decoder::new().decode(detector_result); + } + break 'try1 + } + match tryResult1 { + catch ( e: &NotFoundExceptionFormatException | ) { + if not_found_exception != null { + throw not_found_exception; + } + if format_exception != null { + throw format_exception; + } + throw e; + } 0 => break + } + + } + if hints != null { + let rpcb: ResultPointCallback = hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback; + if rpcb != null { + for let point: ResultPoint in points { + rpcb.found_possible_result_point(point); + } + } + } + let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), &decoder_result.get_num_bits(), points, BarcodeFormat::AZTEC, &System::current_time_millis()); + let byte_segments: List> = 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); + } + result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]z{}", decoder_result.get_symbology_modifier())); + return Ok(result); + } + + pub fn reset(&self) { + // do nothing + } +} + +// AztecWriter.java + +/** + * Renders an Aztec code as a {@link BitMatrix}. + */ +pub struct AztecWriter { +} + +impl Writer for AztecWriter { + + pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> BitMatrix { + return ::encode(&contents, format, width, height, null); + } + + pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map) -> BitMatrix { + // Do not add any ECI code by default + let mut charset: Charset = null; + let ecc_percent: i32 = Encoder::DEFAULT_EC_PERCENT; + let mut layers: i32 = Encoder::DEFAULT_AZTEC_LAYERS; + if hints != null { + if hints.contains_key(EncodeHintType::CHARACTER_SET) { + charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string()); + } + if hints.contains_key(EncodeHintType::ERROR_CORRECTION) { + ecc_percent = Integer::parse_int(&hints.get(EncodeHintType::ERROR_CORRECTION).to_string()); + } + if hints.contains_key(EncodeHintType::AZTEC_LAYERS) { + layers = Integer::parse_int(&hints.get(EncodeHintType::AZTEC_LAYERS).to_string()); + } + } + return ::encode(&contents, format, width, height, &charset, ecc_percent, layers); + } + + fn encode( contents: &String, format: &BarcodeFormat, width: i32, height: i32, charset: &Charset, ecc_percent: i32, layers: i32) -> BitMatrix { + if format != BarcodeFormat::AZTEC { + throw IllegalArgumentException::new(format!("Can only encode AZTEC, but got {}", format)); + } + let aztec: AztecCode = Encoder::encode(&contents, ecc_percent, layers, &charset); + return ::render_result(aztec, width, height); + } + + fn render_result( code: &AztecCode, width: i32, height: i32) -> BitMatrix { + let input: BitMatrix = code.get_matrix(); + if input == null { + throw IllegalStateException::new(); + } + let input_width: i32 = input.get_width(); + let input_height: i32 = input.get_height(); + let output_width: i32 = Math::max(width, input_width); + let output_height: i32 = Math::max(height, input_height); + let multiple: i32 = Math::min(output_width / input_width, output_height / input_height); + 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) { + output.set_region(output_x, output_y, multiple, multiple); + } + } + input_x += 1; + output_x += multiple; + } + } + + } + input_y += 1; + output_y += multiple; + } + } + + return output; + } +} \ No newline at end of file diff --git a/src/aztec/decoder.rs b/src/aztec/decoder.rs index e69de29..db3bc99 100644 --- a/src/aztec/decoder.rs +++ b/src/aztec/decoder.rs @@ -0,0 +1,548 @@ +import com.google.zxing.FormatException; +import com.google.zxing.aztec.AztecDetectorResult; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.CharacterSetECI; +import com.google.zxing.common.DecoderResult; +import com.google.zxing.common.reedsolomon.GenericGF; +import com.google.zxing.common.reedsolomon.ReedSolomonDecoder; +import com.google.zxing.common.reedsolomon.ReedSolomonException; + +/** + *

The main class which implements Aztec Code decoding -- as opposed to locating and extracting + * the Aztec Code from an image.

+ * + * @author David Olivier + */ + +const UPPER_TABLE: vec![Vec; 32] = vec!["CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS", ] +; + + const LOWER_TABLE: vec![Vec; 32] = vec!["CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS", ] +; + + const MIXED_TABLE: vec![Vec; 32] = vec!["CTRL_PS", " ", "\1", "\2", "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n", "\13", "\f", "\r", "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_", "`", "|", "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS", ] +; + + const PUNCT_TABLE: vec![Vec; 32] = vec!["FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL", ] +; + + const DIGIT_TABLE: vec![Vec; 16] = vec!["CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US", ] +; + + const DEFAULT_ENCODING: Charset = StandardCharsets::ISO_8859_1; +pub struct Decoder { + + let mut ddata: AztecDetectorResult; +} + +impl Decoder { + + enum Table { + + UPPER(), LOWER(), MIXED(), DIGIT(), PUNCT(), BINARY() + } + + pub fn decode(&self, detector_result: &AztecDetectorResult) -> /* throws FormatException */Result> { + self.ddata = detector_result; + let matrix: BitMatrix = detector_result.get_bits(); + let rawbits: Vec = self.extract_bits(matrix); + let corrected_bits: CorrectedBitsResult = self.correct_bits(&rawbits); + let raw_bytes: Vec = ::convert_bool_array_to_byte_array(corrected_bits.correctBits); + let result: String = ::get_encoded_data(corrected_bits.correctBits); + let decoder_result: DecoderResult = DecoderResult::new(&raw_bytes, &result, null, &String::format("%d%%", corrected_bits.ecLevel)); + decoder_result.set_num_bits(corrected_bits.correctBits.len()); + return Ok(decoder_result); + } + + // This method is used for testing the high-level encoder + pub fn high_level_decode( corrected_bits: &Vec) -> /* throws FormatException */Result> { + return Ok(::get_encoded_data(&corrected_bits)); + } + + /** + * Gets the string encoded in the aztec code bits + * + * @return the decoded string + */ + fn get_encoded_data( corrected_bits: &Vec) -> /* throws FormatException */Result> { + let end_index: i32 = corrected_bits.len(); + // table most recently latched to + let latch_table: Table = Table::UPPER; + // table to use for the next read + let shift_table: Table = Table::UPPER; + // Final decoded string result + // (correctedBits-5) / 4 is an upper bound on the size (all-digit result) + let result: StringBuilder = StringBuilder::new((corrected_bits.len() - 5) / 4); + // Intermediary buffer of decoded bytes, which is decoded into a string and flushed + // when character encoding changes (ECI) or input ends. + let decoded_bytes: ByteArrayOutputStream = ByteArrayOutputStream::new(); + let mut encoding: Charset = DEFAULT_ENCODING; + let mut index: i32 = 0; + while index < end_index { + if shift_table == Table::BINARY { + if end_index - index < 5 { + break; + } + let mut length: i32 = ::read_code(&corrected_bits, index, 5); + index += 5; + if length == 0 { + if end_index - index < 11 { + break; + } + length = ::read_code(&corrected_bits, index, 11) + 31; + index += 11; + } + { + let char_count: i32 = 0; + while char_count < length { + { + if end_index - index < 8 { + // Force outer loop to exit + index = end_index; + break; + } + let code: i32 = ::read_code(&corrected_bits, index, 8); + decoded_bytes.write(code as i8); + index += 8; + } + char_count += 1; + } + } + + // Go back to whatever mode we had been in + shift_table = latch_table; + } else { + let size: i32 = if shift_table == Table::DIGIT { 4 } else { 5 }; + if end_index - index < size { + break; + } + let code: i32 = ::read_code(&corrected_bits, index, size); + index += size; + let str: String = ::get_character(shift_table, code); + if "FLG(n)".equals(&str) { + if end_index - index < 3 { + break; + } + let mut n: i32 = ::read_code(&corrected_bits, index, 3); + index += 3; + // flush bytes, FLG changes state + let tryResult1 = 0; + 'try1: loop { + { + result.append(&decoded_bytes.to_string(&encoding.name())); + } + break 'try1 + } + match tryResult1 { + catch ( uee: &UnsupportedEncodingException) { + throw IllegalStateException::new(&uee); + } 0 => break + } + + decoded_bytes.reset(); + match n { + 0 => + { + // translate FNC1 as ASCII 29 + result.append(29 as char); + break; + } + 7 => + { + // FLG(7) is reserved and illegal + throw FormatException::get_format_instance(); + } + _ => + { + // ECI is decimal integer encoded as 1-6 codes in DIGIT mode + let mut eci: i32 = 0; + if end_index - index < 4 * n { + break; + } + while n -= 1 !!!check!!! post decrement > 0 { + let next_digit: i32 = ::read_code(&corrected_bits, index, 4); + index += 4; + if next_digit < 2 || next_digit > 11 { + // Not a decimal digit + throw FormatException::get_format_instance(); + } + eci = eci * 10 + (next_digit - 2); + } + let charset_e_c_i: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i_by_value(eci); + if charset_e_c_i == null { + throw FormatException::get_format_instance(); + } + encoding = charset_e_c_i.get_charset(); + } + } + // Go back to whatever mode we had been in + shift_table = latch_table; + } else if str.starts_with("CTRL_") { + // Table changes + // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked. + // That's including when that mode is a shift. + // Our test case dlusbs.png for issue #642 exercises that. + // Latch the current mode, so as to return to Upper after U/S B/S + latch_table = shift_table; + shift_table = ::get_table(&str.char_at(5)); + if str.char_at(6) == 'L' { + latch_table = shift_table; + } + } else { + // Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*. + let b: Vec = str.get_bytes(StandardCharsets::US_ASCII); + decoded_bytes.write(&b, 0, b.len()); + // Go back to whatever mode we had been in + shift_table = latch_table; + } + } + } + let tryResult1 = 0; + 'try1: loop { + { + result.append(&decoded_bytes.to_string(&encoding.name())); + } + break 'try1 + } + match tryResult1 { + catch ( uee: &UnsupportedEncodingException) { + throw IllegalStateException::new(&uee); + } 0 => break + } + + return Ok(result.to_string()); + } + + /** + * gets the table corresponding to the char passed + */ + fn get_table( t: char) -> Table { + match t { + 'L' => + { + return Table::LOWER; + } + 'P' => + { + return Table::PUNCT; + } + 'M' => + { + return Table::MIXED; + } + 'D' => + { + return Table::DIGIT; + } + 'B' => + { + return Table::BINARY; + } + 'U' => + { + } + _ => + { + return Table::UPPER; + } + } + } + + /** + * Gets the character (or string) corresponding to the passed code in the given table + * + * @param table the table used + * @param code the code of the character + */ + fn get_character( table: &Table, code: i32) -> String { + match table { + UPPER => + { + return UPPER_TABLE[code]; + } + LOWER => + { + return LOWER_TABLE[code]; + } + MIXED => + { + return MIXED_TABLE[code]; + } + PUNCT => + { + return PUNCT_TABLE[code]; + } + DIGIT => + { + return DIGIT_TABLE[code]; + } + _ => + { + // Should not reach here. + throw IllegalStateException::new("Bad table"); + } + } + } + + struct CorrectedBitsResult { + + let correct_bits: Vec; + + let ec_level: i32; + } + + impl CorrectedBitsResult { + + fn new( correct_bits: &Vec, ec_level: i32) -> CorrectedBitsResult { + let .correctBits = correct_bits; + let .ecLevel = ec_level; + } + } + + + /** + *

Performs RS error correction on an array of bits.

+ * + * @return the corrected array + * @throws FormatException if the input contains too many errors + */ + fn correct_bits(&self, rawbits: &Vec) -> /* throws FormatException */Result> { + let mut gf: GenericGF; + let codeword_size: i32; + if self.ddata.get_nb_layers() <= 2 { + codeword_size = 6; + gf = GenericGF::AZTEC_DATA_6; + } else if self.ddata.get_nb_layers() <= 8 { + codeword_size = 8; + gf = GenericGF::AZTEC_DATA_8; + } else if self.ddata.get_nb_layers() <= 22 { + codeword_size = 10; + gf = GenericGF::AZTEC_DATA_10; + } else { + codeword_size = 12; + gf = GenericGF::AZTEC_DATA_12; + } + let num_data_codewords: i32 = self.ddata.get_nb_datablocks(); + let num_codewords: i32 = rawbits.len() / codeword_size; + if num_codewords < num_data_codewords { + throw FormatException::get_format_instance(); + } + let mut offset: i32 = rawbits.len() % codeword_size; + let data_words: [i32; num_codewords] = [0; num_codewords]; + { + let mut i: i32 = 0; + while i < num_codewords { + { + data_words[i] = ::read_code(&rawbits, offset, codeword_size); + } + i += 1; + offset += codeword_size; + } + } + + let tryResult1 = 0; + 'try1: loop { + { + let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(gf); + rs_decoder.decode(&data_words, num_codewords - num_data_codewords); + } + break 'try1 + } + match tryResult1 { + catch ( ex: &ReedSolomonException) { + throw FormatException::get_format_instance(ex); + } 0 => break + } + + // Now perform the unstuffing operation. + // First, count how many bits are going to be thrown out as stuffing + let mask: i32 = (1 << codeword_size) - 1; + let stuffed_bits: i32 = 0; + { + let mut i: i32 = 0; + while i < num_data_codewords { + { + let data_word: i32 = data_words[i]; + if data_word == 0 || data_word == mask { + throw FormatException::get_format_instance(); + } else if data_word == 1 || data_word == mask - 1 { + stuffed_bits += 1; + } + } + i += 1; + } + } + + // Now, actually unpack the bits and remove the stuffing + let corrected_bits: [bool; num_data_codewords * codeword_size - stuffed_bits] = [false; num_data_codewords * codeword_size - stuffed_bits]; + let mut index: i32 = 0; + { + let mut i: i32 = 0; + while i < num_data_codewords { + { + let data_word: i32 = data_words[i]; + if data_word == 1 || data_word == mask - 1 { + // next codewordSize-1 bits are all zeros or all ones + Arrays::fill(&corrected_bits, index, index + codeword_size - 1, data_word > 1); + index += codeword_size - 1; + } else { + { + let mut bit: i32 = codeword_size - 1; + while bit >= 0 { + { + corrected_bits[index += 1 !!!check!!! post increment] = (data_word & (1 << bit)) != 0; + } + bit -= 1; + } + } + + } + } + i += 1; + } + } + + return Ok(CorrectedBitsResult::new(&corrected_bits, 100 * (num_codewords - num_data_codewords) / num_codewords)); + } + + /** + * Gets the array of bits from an Aztec Code matrix + * + * @return the array of bits + */ + fn extract_bits(&self, matrix: &BitMatrix) -> Vec { + let compact: bool = self.ddata.is_compact(); + let layers: i32 = self.ddata.get_nb_layers(); + // not including alignment lines + let base_matrix_size: i32 = ( if compact { 11 } else { 14 }) + layers * 4; + let alignment_map: [i32; base_matrix_size] = [0; base_matrix_size]; + let mut rawbits: [bool; ::total_bits_in_layer(layers, compact)] = [false; ::total_bits_in_layer(layers, compact)]; + if compact { + { + let mut i: i32 = 0; + while i < alignment_map.len() { + { + alignment_map[i] = i; + } + i += 1; + } + } + + } else { + let matrix_size: i32 = base_matrix_size + 1 + 2 * ((base_matrix_size / 2 - 1) / 15); + let orig_center: i32 = base_matrix_size / 2; + let center: i32 = matrix_size / 2; + { + let mut i: i32 = 0; + while i < orig_center { + { + let new_offset: i32 = i + i / 15; + alignment_map[orig_center - i - 1] = center - new_offset - 1; + alignment_map[orig_center + i] = center + new_offset + 1; + } + i += 1; + } + } + + } + { + let mut i: i32 = 0, let row_offset: i32 = 0; + while i < layers { + { + let row_size: i32 = (layers - i) * 4 + ( if compact { 9 } else { 12 }); + // The top-left most point of this layer is (not including alignment lines) + let low: i32 = i * 2; + // The bottom-right most point of this layer is (not including alignment lines) + let high: i32 = base_matrix_size - 1 - low; + // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows + { + let mut j: i32 = 0; + while j < row_size { + { + let column_offset: i32 = j * 2; + { + let mut k: i32 = 0; + while k < 2 { + { + // left column + rawbits[row_offset + column_offset + k] = matrix.get(alignment_map[low + k], alignment_map[low + j]); + // bottom row + rawbits[row_offset + 2 * row_size + column_offset + k] = matrix.get(alignment_map[low + j], alignment_map[high - k]); + // right column + rawbits[row_offset + 4 * row_size + column_offset + k] = matrix.get(alignment_map[high - k], alignment_map[high - j]); + // top row + rawbits[row_offset + 6 * row_size + column_offset + k] = matrix.get(alignment_map[high - j], alignment_map[low + k]); + } + k += 1; + } + } + + } + j += 1; + } + } + + row_offset += row_size * 8; + } + i += 1; + } + } + + return rawbits; + } + + /** + * Reads a code of given length and at given index in an array of bits + */ + fn read_code( rawbits: &Vec, start_index: i32, length: i32) -> i32 { + let mut res: i32 = 0; + { + let mut i: i32 = start_index; + while i < start_index + length { + { + res <<= 1; + if rawbits[i] { + res |= 0x01; + } + } + i += 1; + } + } + + return res; + } + + /** + * Reads a code of length 8 in an array of bits, padding with zeros + */ + fn read_byte( rawbits: &Vec, start_index: i32) -> i8 { + let n: i32 = rawbits.len() - start_index; + if n >= 8 { + return ::read_code(&rawbits, start_index, 8) as i8; + } + return (::read_code(&rawbits, start_index, n) << (8 - n)) as i8; + } + + /** + * Packs a bit array into bytes, most significant bit first + */ + fn convert_bool_array_to_byte_array( bool_arr: &Vec) -> Vec { + let byte_arr: [i8; (bool_arr.len() + 7) / 8] = [0; (bool_arr.len() + 7) / 8]; + { + let mut i: i32 = 0; + while i < byte_arr.len() { + { + byte_arr[i] = ::read_byte(&bool_arr, 8 * i); + } + i += 1; + } + } + + return byte_arr; + } + + fn total_bits_in_layer( layers: i32, compact: bool) -> i32 { + return (( if compact { 88 } else { 112 }) + 16 * layers) * layers; + } +} + diff --git a/src/aztec/detector.rs b/src/aztec/detector.rs index e69de29..82941c4 100644 --- a/src/aztec/detector.rs +++ b/src/aztec/detector.rs @@ -0,0 +1,581 @@ +import com.google.zxing.NotFoundException; +import com.google.zxing.ResultPoint; +import com.google.zxing.aztec.AztecDetectorResult; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.GridSampler; +import com.google.zxing.common.detector.MathUtils; +import com.google.zxing.common.detector.WhiteRectangleDetector; +import com.google.zxing.common.reedsolomon.GenericGF; +import com.google.zxing.common.reedsolomon.ReedSolomonDecoder; +import com.google.zxing.common.reedsolomon.ReedSolomonException; + + +/** + * Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code + * is rotated or skewed, or partially obscured. + * + * @author David Olivier + * @author Frank Yellin + */ + +const EXPECTED_CORNER_BITS: vec![Vec; 4] = vec![// 07340 XXX .XX X.. ... +0xee0, // 00734 ... XXX .XX X.. +0x1dc, // 04073 X.. ... XXX .XX +0x83b, // 03407 .XX X.. ... XXX +0x707, ] +; +pub struct Detector { + + let image: BitMatrix; + + let mut compact: bool; + + let nb_layers: i32; + + let nb_data_blocks: i32; + + let nb_center_layers: i32; + + let mut shift: i32; +} + +impl Detector { + + pub fn new( image: &BitMatrix) -> Detector { + let .image = image; + } + + pub fn detect(&self) -> /* throws NotFoundException */Result> { + return Ok(self.detect(false)); + } + + /** + * Detects an Aztec Code in an image. + * + * @param isMirror if true, image is a mirror-image of original + * @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code + * @throws NotFoundException if no Aztec Code can be found + */ + pub fn detect(&self, is_mirror: bool) -> /* throws NotFoundException */Result> { + // 1. Get the center of the aztec matrix + let p_center: Point = self.get_matrix_center(); + // 2. Get the center points of the four diagonal points just outside the bull's eye + // [topRight, bottomRight, bottomLeft, topLeft] + let bulls_eye_corners: Vec = self.get_bulls_eye_corners(p_center); + if is_mirror { + let temp: ResultPoint = bulls_eye_corners[0]; + bulls_eye_corners[0] = bulls_eye_corners[2]; + bulls_eye_corners[2] = temp; + } + // 3. Get the size of the matrix and other parameters from the bull's eye + self.extract_parameters(bulls_eye_corners); + // 4. Sample the grid + let bits: BitMatrix = self.sample_grid(self.image, bulls_eye_corners[self.shift % 4], bulls_eye_corners[(self.shift + 1) % 4], bulls_eye_corners[(self.shift + 2) % 4], bulls_eye_corners[(self.shift + 3) % 4]); + // 5. Get the corners of the matrix. + let corners: Vec = self.get_matrix_corner_points(bulls_eye_corners); + return Ok(AztecDetectorResult::new(bits, corners, self.compact, self.nb_data_blocks, self.nb_layers)); + } + + /** + * Extracts the number of data layers and data blocks from the layer around the bull's eye. + * + * @param bullsEyeCorners the array of bull's eye corners + * @throws NotFoundException in case of too many errors or invalid parameters + */ + fn extract_parameters(&self, bulls_eye_corners: &Vec) -> /* throws NotFoundException */Result> { + if !self.is_valid(bulls_eye_corners[0]) || !self.is_valid(bulls_eye_corners[1]) || !self.is_valid(bulls_eye_corners[2]) || !self.is_valid(bulls_eye_corners[3]) { + throw NotFoundException::get_not_found_instance(); + } + let length: i32 = 2 * self.nb_center_layers; + // Get the bits around the bull's eye + let sides: vec![Vec; 4] = vec![// Right side + self.sample_line(bulls_eye_corners[0], bulls_eye_corners[1], length), // Bottom + self.sample_line(bulls_eye_corners[1], bulls_eye_corners[2], length), // Left side + self.sample_line(bulls_eye_corners[2], bulls_eye_corners[3], length), // Top + self.sample_line(bulls_eye_corners[3], bulls_eye_corners[0], length), ] + ; + // bullsEyeCorners[shift] is the corner of the bulls'eye that has three + // orientation marks. + // sides[shift] is the row/column that goes from the corner with three + // orientation marks to the corner with two. + self.shift = ::get_rotation(&sides, length); + // Flatten the parameter bits into a single 28- or 40-bit long + let parameter_data: i64 = 0; + { + let mut i: i32 = 0; + while i < 4 { + { + let side: i32 = sides[(self.shift + i) % 4]; + if self.compact { + // Each side of the form ..XXXXXXX. where Xs are parameter data + parameter_data <<= 7; + parameter_data += (side >> 1) & 0x7F; + } else { + // Each side of the form ..XXXXX.XXXXX. where Xs are parameter data + parameter_data <<= 10; + parameter_data += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F); + } + } + i += 1; + } + } + + // Corrects parameter data using RS. Returns just the data portion + // without the error correction. + let corrected_data: i32 = ::get_corrected_parameter_data(parameter_data, self.compact); + if self.compact { + // 8 bits: 2 bits layers and 6 bits data blocks + self.nb_layers = (corrected_data >> 6) + 1; + self.nb_data_blocks = (corrected_data & 0x3F) + 1; + } else { + // 16 bits: 5 bits layers and 11 bits data blocks + self.nb_layers = (corrected_data >> 11) + 1; + self.nb_data_blocks = (corrected_data & 0x7FF) + 1; + } + } + + fn get_rotation( sides: &Vec, length: i32) -> /* throws NotFoundException */Result> { + // In a normal pattern, we expect to See + // ** .* D A + // * * + // + // . * + // .. .. C B + // + // Grab the 3 bits from each of the sides the form the locator pattern and concatenate + // into a 12-bit integer. Start with the bit at A + let corner_bits: i32 = 0; + for let side: i32 in sides { + // XX......X where X's are orientation marks + let t: i32 = ((side >> (length - 2)) << 1) + (side & 1); + corner_bits = (corner_bits << 3) + t; + } + // Mov the bottom bit to the top, so that the three bits of the locator pattern at A are + // together. cornerBits is now: + // 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D + corner_bits = ((corner_bits & 1) << 11) + (corner_bits >> 1); + // can easily tolerate two errors. + { + let mut shift: i32 = 0; + while shift < 4 { + { + if Integer::bit_count(corner_bits ^ EXPECTED_CORNER_BITS[shift]) <= 2 { + return Ok(shift); + } + } + shift += 1; + } + } + + throw NotFoundException::get_not_found_instance(); + } + + /** + * Corrects the parameter bits using Reed-Solomon algorithm. + * + * @param parameterData parameter bits + * @param compact true if this is a compact Aztec code + * @throws NotFoundException if the array contains too many errors + */ + fn get_corrected_parameter_data( parameter_data: i64, compact: bool) -> /* throws NotFoundException */Result> { + let num_codewords: i32; + let num_data_codewords: i32; + if compact { + num_codewords = 7; + num_data_codewords = 2; + } else { + num_codewords = 10; + num_data_codewords = 4; + } + let num_e_c_codewords: i32 = num_codewords - num_data_codewords; + let parameter_words: [i32; num_codewords] = [0; num_codewords]; + { + let mut i: i32 = num_codewords - 1; + while i >= 0 { + { + parameter_words[i] = parameter_data as i32 & 0xF; + parameter_data >>= 4; + } + i -= 1; + } + } + + let tryResult1 = 0; + 'try1: loop { + { + let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(GenericGF::AZTEC_PARAM); + rs_decoder.decode(¶meter_words, num_e_c_codewords); + } + break 'try1 + } + match tryResult1 { + catch ( ignored: &ReedSolomonException) { + throw NotFoundException::get_not_found_instance(); + } 0 => break + } + + // Toss the error correction. Just return the data as an integer + let mut result: i32 = 0; + { + let mut i: i32 = 0; + while i < num_data_codewords { + { + result = (result << 4) + parameter_words[i]; + } + i += 1; + } + } + + return Ok(result); + } + + /** + * Finds the corners of a bull-eye centered on the passed point. + * This returns the centers of the diagonal points just outside the bull's eye + * Returns [topRight, bottomRight, bottomLeft, topLeft] + * + * @param pCenter Center point + * @return The corners of the bull-eye + * @throws NotFoundException If no valid bull-eye can be found + */ + fn get_bulls_eye_corners(&self, p_center: &Point) -> /* throws NotFoundException */Result, Rc> { + let mut pina: Point = p_center; + let mut pinb: Point = p_center; + let mut pinc: Point = p_center; + let mut pind: Point = p_center; + let mut color: bool = true; + { + self.nb_center_layers = 1; + while self.nb_center_layers < 9 { + { + let pouta: Point = self.get_first_different(pina, color, 1, -1); + let poutb: Point = self.get_first_different(pinb, color, 1, 1); + let poutc: Point = self.get_first_different(pinc, color, -1, 1); + let poutd: Point = self.get_first_different(pind, color, -1, -1); + if self.nb_center_layers > 2 { + let q: f32 = ::distance(poutd, pouta) * self.nb_center_layers / (::distance(pind, pina) * (self.nb_center_layers + 2)); + if q < 0.75 || q > 1.25 || !self.is_white_or_black_rectangle(pouta, poutb, poutc, poutd) { + break; + } + } + pina = pouta; + pinb = poutb; + pinc = poutc; + pind = poutd; + color = !color; + } + self.nb_center_layers += 1; + } + } + + if self.nb_center_layers != 5 && self.nb_center_layers != 7 { + throw NotFoundException::get_not_found_instance(); + } + self.compact = self.nb_center_layers == 5; + // Expand the square by .5 pixel in each direction so that we're on the border + // between the white square and the black square + let pinax: ResultPoint = ResultPoint::new(pina.get_x() + 0.5f, pina.get_y() - 0.5f); + let pinbx: ResultPoint = ResultPoint::new(pinb.get_x() + 0.5f, pinb.get_y() + 0.5f); + let pincx: ResultPoint = ResultPoint::new(pinc.get_x() - 0.5f, pinc.get_y() + 0.5f); + let pindx: ResultPoint = ResultPoint::new(pind.get_x() - 0.5f, pind.get_y() - 0.5f); + // just outside the bull's eye. + return Ok(::expand_square( : vec![ResultPoint; 4] = vec![pinax, pinbx, pincx, pindx, ] + , 2 * self.nb_center_layers - 3, 2 * self.nb_center_layers)); + } + + /** + * Finds a candidate center point of an Aztec code from an image + * + * @return the center point + */ + fn get_matrix_center(&self) -> Point { + let point_a: ResultPoint; + let point_b: ResultPoint; + let point_c: ResultPoint; + let point_d: ResultPoint; + //Get a white rectangle that can be the border of the matrix in center bull's eye or + let tryResult1 = 0; + 'try1: loop { + { + let corner_points: Vec = WhiteRectangleDetector::new(self.image).detect(); + point_a = corner_points[0]; + point_b = corner_points[1]; + point_c = corner_points[2]; + point_d = corner_points[3]; + } + break 'try1 + } + match tryResult1 { + catch ( e: &NotFoundException) { + let cx: i32 = self.image.get_width() / 2; + let cy: i32 = self.image.get_height() / 2; + point_a = self.get_first_different(Point::new(cx + 7, cy - 7), false, 1, -1).to_result_point(); + point_b = self.get_first_different(Point::new(cx + 7, cy + 7), false, 1, 1).to_result_point(); + point_c = self.get_first_different(Point::new(cx - 7, cy + 7), false, -1, 1).to_result_point(); + point_d = self.get_first_different(Point::new(cx - 7, cy - 7), false, -1, -1).to_result_point(); + } 0 => break + } + + //Compute the center of the rectangle + let mut cx: i32 = MathUtils::round((point_a.get_x() + point_d.get_x() + point_b.get_x() + point_c.get_x()) / 4.0f); + let mut cy: i32 = MathUtils::round((point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f); + // in order to compute a more accurate center. + let tryResult1 = 0; + 'try1: loop { + { + let corner_points: Vec = WhiteRectangleDetector::new(self.image, 15, cx, cy).detect(); + point_a = corner_points[0]; + point_b = corner_points[1]; + point_c = corner_points[2]; + point_d = corner_points[3]; + } + break 'try1 + } + match tryResult1 { + catch ( e: &NotFoundException) { + point_a = self.get_first_different(Point::new(cx + 7, cy - 7), false, 1, -1).to_result_point(); + point_b = self.get_first_different(Point::new(cx + 7, cy + 7), false, 1, 1).to_result_point(); + point_c = self.get_first_different(Point::new(cx - 7, cy + 7), false, -1, 1).to_result_point(); + point_d = self.get_first_different(Point::new(cx - 7, cy - 7), false, -1, -1).to_result_point(); + } 0 => break + } + + // Recompute the center of the rectangle + cx = MathUtils::round((point_a.get_x() + point_d.get_x() + point_b.get_x() + point_c.get_x()) / 4.0f); + cy = MathUtils::round((point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f); + return Point::new(cx, cy); + } + + /** + * Gets the Aztec code corners from the bull's eye corners and the parameters. + * + * @param bullsEyeCorners the array of bull's eye corners + * @return the array of aztec code corners + */ + fn get_matrix_corner_points(&self, bulls_eye_corners: &Vec) -> Vec { + return ::expand_square(bulls_eye_corners, 2 * self.nb_center_layers, &self.get_dimension()); + } + + /** + * Creates a BitMatrix by sampling the provided image. + * topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the + * diagonal just outside the bull's eye. + */ + fn sample_grid(&self, image: &BitMatrix, top_left: &ResultPoint, top_right: &ResultPoint, bottom_right: &ResultPoint, bottom_left: &ResultPoint) -> /* throws NotFoundException */Result> { + let sampler: GridSampler = GridSampler::get_instance(); + let dimension: i32 = self.get_dimension(); + let low: f32 = dimension / 2.0f - self.nb_center_layers; + let high: f32 = dimension / 2.0f + self.nb_center_layers; + return Ok(sampler.sample_grid(image, dimension, dimension, // topleft + low, // topleft + low, // topright + high, // topright + low, // bottomright + high, // bottomright + high, // bottomleft + low, // bottomleft + high, &top_left.get_x(), &top_left.get_y(), &top_right.get_x(), &top_right.get_y(), &bottom_right.get_x(), &bottom_right.get_y(), &bottom_left.get_x(), &bottom_left.get_y())); + } + + /** + * Samples a line. + * + * @param p1 start point (inclusive) + * @param p2 end point (exclusive) + * @param size number of bits + * @return the array of bits as an int (first bit is high-order bit of result) + */ + fn sample_line(&self, p1: &ResultPoint, p2: &ResultPoint, size: i32) -> i32 { + let mut result: i32 = 0; + let d: f32 = ::distance(p1, p2); + let module_size: f32 = d / size; + let px: f32 = p1.get_x(); + let py: f32 = p1.get_y(); + let dx: f32 = module_size * (p2.get_x() - p1.get_x()) / d; + let dy: f32 = module_size * (p2.get_y() - p1.get_y()) / d; + { + let mut i: i32 = 0; + while i < size { + { + if self.image.get(&MathUtils::round(px + i * dx), &MathUtils::round(py + i * dy)) { + result |= 1 << (size - i - 1); + } + } + i += 1; + } + } + + return result; + } + + /** + * @return true if the border of the rectangle passed in parameter is compound of white points only + * or black points only + */ + fn is_white_or_black_rectangle(&self, p1: &Point, p2: &Point, p3: &Point, p4: &Point) -> bool { + let corr: i32 = 3; + p1 = Point::new(&Math::max(0, p1.get_x() - corr), &Math::min(self.image.get_height() - 1, p1.get_y() + corr)); + p2 = Point::new(&Math::max(0, p2.get_x() - corr), &Math::max(0, p2.get_y() - corr)); + p3 = Point::new(&Math::min(self.image.get_width() - 1, p3.get_x() + corr), &Math::max(0, &Math::min(self.image.get_height() - 1, p3.get_y() - corr))); + p4 = Point::new(&Math::min(self.image.get_width() - 1, p4.get_x() + corr), &Math::min(self.image.get_height() - 1, p4.get_y() + corr)); + let c_init: i32 = self.get_color(p4, p1); + if c_init == 0 { + return false; + } + let mut c: i32 = self.get_color(p1, p2); + if c != c_init { + return false; + } + c = self.get_color(p2, p3); + if c != c_init { + return false; + } + c = self.get_color(p3, p4); + return c == c_init; + } + + /** + * Gets the color of a segment + * + * @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else + */ + fn get_color(&self, p1: &Point, p2: &Point) -> i32 { + let d: f32 = ::distance(p1, p2); + if d == 0.0f { + return 0; + } + let dx: f32 = (p2.get_x() - p1.get_x()) / d; + let dy: f32 = (p2.get_y() - p1.get_y()) / d; + let mut error: i32 = 0; + let mut px: f32 = p1.get_x(); + let mut py: f32 = p1.get_y(); + let color_model: bool = self.image.get(&p1.get_x(), &p1.get_y()); + let i_max: i32 = Math::floor(d) as i32; + { + let mut i: i32 = 0; + while i < i_max { + { + if self.image.get(&MathUtils::round(px), &MathUtils::round(py)) != color_model { + error += 1; + } + px += dx; + py += dy; + } + i += 1; + } + } + + let err_ratio: f32 = error / d; + if err_ratio > 0.1f && err_ratio < 0.9f { + return 0; + } + return if (err_ratio <= 0.1f) == color_model { 1 } else { -1 }; + } + + /** + * Gets the coordinate of the first point with a different color in the given direction + */ + fn get_first_different(&self, init: &Point, color: bool, dx: i32, dy: i32) -> Point { + let mut x: i32 = init.get_x() + dx; + let mut y: i32 = init.get_y() + dy; + while self.is_valid(x, y) && self.image.get(x, y) == color { + x += dx; + y += dy; + } + x -= dx; + y -= dy; + while self.is_valid(x, y) && self.image.get(x, y) == color { + x += dx; + } + x -= dx; + while self.is_valid(x, y) && self.image.get(x, y) == color { + y += dy; + } + y -= dy; + return Point::new(x, y); + } + + /** + * Expand the square represented by the corner points by pushing out equally in all directions + * + * @param cornerPoints the corners of the square, which has the bull's eye at its center + * @param oldSide the original length of the side of the square in the target bit matrix + * @param newSide the new length of the size of the square in the target bit matrix + * @return the corners of the expanded square + */ + fn expand_square( corner_points: &Vec, old_side: i32, new_side: i32) -> Vec { + let ratio: f32 = new_side / (2.0f * old_side); + let mut dx: f32 = corner_points[0].get_x() - corner_points[2].get_x(); + let mut dy: f32 = corner_points[0].get_y() - corner_points[2].get_y(); + let mut centerx: f32 = (corner_points[0].get_x() + corner_points[2].get_x()) / 2.0f; + let mut centery: f32 = (corner_points[0].get_y() + corner_points[2].get_y()) / 2.0f; + let result0: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy); + let result2: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy); + dx = corner_points[1].get_x() - corner_points[3].get_x(); + dy = corner_points[1].get_y() - corner_points[3].get_y(); + centerx = (corner_points[1].get_x() + corner_points[3].get_x()) / 2.0f; + centery = (corner_points[1].get_y() + corner_points[3].get_y()) / 2.0f; + let result1: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy); + let result3: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy); + return : vec![ResultPoint; 4] = vec![result0, result1, result2, result3, ] + ; + } + + fn is_valid(&self, x: i32, y: i32) -> bool { + return x >= 0 && x < self.image.get_width() && y >= 0 && y < self.image.get_height(); + } + + fn is_valid(&self, point: &ResultPoint) -> bool { + let x: i32 = MathUtils::round(&point.get_x()); + let y: i32 = MathUtils::round(&point.get_y()); + return self.is_valid(x, y); + } + + fn distance( a: &Point, b: &Point) -> f32 { + return MathUtils::distance(&a.get_x(), &a.get_y(), &b.get_x(), &b.get_y()); + } + + fn distance( a: &ResultPoint, b: &ResultPoint) -> f32 { + return MathUtils::distance(&a.get_x(), &a.get_y(), &b.get_x(), &b.get_y()); + } + + fn get_dimension(&self) -> i32 { + if self.compact { + return 4 * self.nb_layers + 11; + } + return 4 * self.nb_layers + 2 * ((2 * self.nb_layers + 6) / 15) + 15; + } + + struct Point { + + let x: i32; + + let y: i32; + } + + impl Point { + + fn to_result_point(&self) -> ResultPoint { + return ResultPoint::new(self.x, self.y); + } + + fn new( x: i32, y: i32) -> Point { + let .x = x; + let .y = y; + } + + fn get_x(&self) -> i32 { + return self.x; + } + + fn get_y(&self) -> i32 { + return self.y; + } + + pub fn to_string(&self) -> String { + return format!("<{} {}>", self.x, self.y); + } + } + +} + diff --git a/src/aztec/encoder.rs b/src/aztec/encoder.rs index e69de29..1628bfb 100644 --- a/src/aztec/encoder.rs +++ b/src/aztec/encoder.rs @@ -0,0 +1,1242 @@ +use crate::common::{BitArray,BitMatrix,CharacterSetECI}; +use crate::common::reedsolomon{GenericGF,ReedSolomonEncoder}; + +// Token.java +const EMPTY: Token = SimpleToken::new(null, 0, 0); + +pub trait Token { + + fn new( previous: &Token) -> Token { + let .previous = previous; + } + + fn get_previous(&self) -> Token { + return self.previous; + } + + fn add(&self, value: i32, bit_count: i32) -> Token { + return SimpleToken::new(self, value, bit_count); + } + + fn add_binary_shift(&self, start: i32, byte_count: i32) -> Token { + //int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21); + return BinaryShiftToken::new(self, start, byte_count); + } + + fn append_to(&self, bit_array: &BitArray, text: &Vec) ; +} + +// AztecCode.java +/** + * Aztec 2D code representation + * + * @author Rustam Abdullaev + */ +pub struct AztecCode { + + let compact: bool; + + let size: i32; + + let layers: i32; + + let code_words: i32; + + let matrix: BitMatrix; +} + +impl AztecCode { + + /** + * @return {@code true} if compact instead of full mode + */ + pub fn is_compact(&self) -> bool { + return self.compact; + } + + pub fn set_compact(&self, compact: bool) { + self.compact = compact; + } + + /** + * @return size in pixels (width and height) + */ + pub fn get_size(&self) -> i32 { + return self.size; + } + + pub fn set_size(&self, size: i32) { + self.size = size; + } + + /** + * @return number of levels + */ + pub fn get_layers(&self) -> i32 { + return self.layers; + } + + pub fn set_layers(&self, layers: i32) { + self.layers = layers; + } + + /** + * @return number of data codewords + */ + pub fn get_code_words(&self) -> i32 { + return self.code_words; + } + + pub fn set_code_words(&self, code_words: i32) { + self.codeWords = code_words; + } + + /** + * @return the symbol image + */ + pub fn get_matrix(&self) -> BitMatrix { + return self.matrix; + } + + pub fn set_matrix(&self, matrix: &BitMatrix) { + self.matrix = matrix; + } +} + +// Encoder.java + +/** + * Generates Aztec 2D barcodes. + * + * @author Rustam Abdullaev + */ + +// default minimal percentage of error check words +const DEFAULT_EC_PERCENT: i32 = 33; + +const DEFAULT_AZTEC_LAYERS: i32 = 0; + +const MAX_NB_BITS: i32 = 32; + +const MAX_NB_BITS_COMPACT: i32 = 4; + +const WORD_SIZE: vec![Vec; 33] = vec![4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, ] +; +pub struct Encoder { +} + +impl Encoder { + + fn new() -> Encoder { + } + + /** + * Encodes the given string content as an Aztec symbol (without ECI code) + * + * @param data input data string; must be encodable as ISO/IEC 8859-1 (Latin-1) + * @return Aztec symbol matrix with metadata + */ + pub fn encode( data: &String) -> AztecCode { + return ::encode(&data.get_bytes(StandardCharsets::ISO_8859_1)); + } + + /** + * Encodes the given string content as an Aztec symbol (without ECI code) + * + * @param data input data string; must be encodable as ISO/IEC 8859-1 (Latin-1) + * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, + * a minimum of 23% + 3 words is recommended) + * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers + * @return Aztec symbol matrix with metadata + */ + pub fn encode( data: &String, min_e_c_c_percent: i32, user_specified_layers: i32) -> AztecCode { + return ::encode(&data.get_bytes(StandardCharsets::ISO_8859_1), min_e_c_c_percent, user_specified_layers, null); + } + + /** + * Encodes the given string content as an Aztec symbol + * + * @param data input data string + * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, + * a minimum of 23% + 3 words is recommended) + * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers + * @param charset character set in which to encode string using ECI; if null, no ECI code + * will be inserted, and the string must be encodable as ISO/IEC 8859-1 + * (Latin-1), the default encoding of the symbol. + * @return Aztec symbol matrix with metadata + */ + pub fn encode( data: &String, min_e_c_c_percent: i32, user_specified_layers: i32, charset: &Charset) -> AztecCode { + let bytes: Vec = data.get_bytes( if null != charset { charset } else { StandardCharsets::ISO_8859_1 }); + return ::encode(&bytes, min_e_c_c_percent, user_specified_layers, &charset); + } + + /** + * Encodes the given binary content as an Aztec symbol (without ECI code) + * + * @param data input data string + * @return Aztec symbol matrix with metadata + */ + pub fn encode( data: &Vec) -> AztecCode { + return ::encode(&data, DEFAULT_EC_PERCENT, DEFAULT_AZTEC_LAYERS, null); + } + + /** + * Encodes the given binary content as an Aztec symbol (without ECI code) + * + * @param data input data string + * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, + * a minimum of 23% + 3 words is recommended) + * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers + * @return Aztec symbol matrix with metadata + */ + pub fn encode( data: &Vec, min_e_c_c_percent: i32, user_specified_layers: i32) -> AztecCode { + return ::encode(&data, min_e_c_c_percent, user_specified_layers, null); + } + + /** + * Encodes the given binary content as an Aztec symbol + * + * @param data input data string + * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, + * a minimum of 23% + 3 words is recommended) + * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers + * @param charset character set to mark using ECI; if null, no ECI code will be inserted, and the + * default encoding of ISO/IEC 8859-1 will be assuming by readers. + * @return Aztec symbol matrix with metadata + */ + pub fn encode( data: &Vec, min_e_c_c_percent: i32, user_specified_layers: i32, charset: &Charset) -> AztecCode { + // High-level encode + let bits: BitArray = HighLevelEncoder::new(&data, &charset).encode(); + // stuff bits and choose symbol size + let ecc_bits: i32 = bits.get_size() * min_e_c_c_percent / 100 + 11; + let total_size_bits: i32 = bits.get_size() + ecc_bits; + let mut compact: bool; + let mut layers: i32; + let total_bits_in_layer: i32; + let word_size: i32; + let stuffed_bits: BitArray; + if user_specified_layers != DEFAULT_AZTEC_LAYERS { + compact = user_specified_layers < 0; + layers = Math::abs(user_specified_layers); + if layers > ( if compact { MAX_NB_BITS_COMPACT } else { MAX_NB_BITS }) { + throw IllegalArgumentException::new(&String::format("Illegal value %s for layers", user_specified_layers)); + } + total_bits_in_layer = self.total_bits_in_layer(layers, compact); + word_size = WORD_SIZE[layers]; + let usable_bits_in_layers: i32 = total_bits_in_layer - (total_bits_in_layer % word_size); + stuffed_bits = ::stuff_bits(bits, word_size); + if stuffed_bits.get_size() + ecc_bits > usable_bits_in_layers { + throw IllegalArgumentException::new("Data to large for user specified layer"); + } + if compact && stuffed_bits.get_size() > word_size * 64 { + // Compact format only allows 64 data words, though C4 can hold more words than that + throw IllegalArgumentException::new("Data to large for user specified layer"); + } + } else { + word_size = 0; + stuffed_bits = null; + // is the same size, but has more data. + { + let mut i: i32 = 0; + loop { + { + if i > MAX_NB_BITS { + throw IllegalArgumentException::new("Data too large for an Aztec code"); + } + compact = i <= 3; + layers = if compact { i + 1 } else { i }; + total_bits_in_layer = self.total_bits_in_layer(layers, compact); + if total_size_bits > total_bits_in_layer { + continue; + } + // wordSize has changed + if stuffed_bits == null || word_size != WORD_SIZE[layers] { + word_size = WORD_SIZE[layers]; + stuffed_bits = ::stuff_bits(bits, word_size); + } + let usable_bits_in_layers: i32 = total_bits_in_layer - (total_bits_in_layer % word_size); + if compact && stuffed_bits.get_size() > word_size * 64 { + // Compact format only allows 64 data words, though C4 can hold more words than that + continue; + } + if stuffed_bits.get_size() + ecc_bits <= usable_bits_in_layers { + break; + } + } + i += 1; + } + } + + } + let message_bits: BitArray = ::generate_check_words(stuffed_bits, total_bits_in_layer, word_size); + // generate mode message + let message_size_in_words: i32 = stuffed_bits.get_size() / word_size; + let mode_message: BitArray = ::generate_mode_message(compact, layers, message_size_in_words); + // allocate symbol + // not including alignment lines + let base_matrix_size: i32 = ( if compact { 11 } else { 14 }) + layers * 4; + let alignment_map: [i32; base_matrix_size] = [0; base_matrix_size]; + let matrix_size: i32; + if compact { + // no alignment marks in compact mode, alignmentMap is a no-op + matrix_size = base_matrix_size; + { + let mut i: i32 = 0; + while i < alignment_map.len() { + { + alignment_map[i] = i; + } + i += 1; + } + } + + } else { + matrix_size = base_matrix_size + 1 + 2 * ((base_matrix_size / 2 - 1) / 15); + let orig_center: i32 = base_matrix_size / 2; + let center: i32 = matrix_size / 2; + { + let mut i: i32 = 0; + while i < orig_center { + { + let new_offset: i32 = i + i / 15; + alignment_map[orig_center - i - 1] = center - new_offset - 1; + alignment_map[orig_center + i] = center + new_offset + 1; + } + i += 1; + } + } + + } + let matrix: BitMatrix = BitMatrix::new(matrix_size); + // draw data bits + { + let mut i: i32 = 0, let row_offset: i32 = 0; + while i < layers { + { + let row_size: i32 = (layers - i) * 4 + ( if compact { 9 } else { 12 }); + { + let mut j: i32 = 0; + while j < row_size { + { + let column_offset: i32 = j * 2; + { + let mut k: i32 = 0; + while k < 2 { + { + if message_bits.get(row_offset + column_offset + k) { + matrix.set(alignment_map[i * 2 + k], alignment_map[i * 2 + j]); + } + if message_bits.get(row_offset + row_size * 2 + column_offset + k) { + matrix.set(alignment_map[i * 2 + j], alignment_map[base_matrix_size - 1 - i * 2 - k]); + } + if message_bits.get(row_offset + row_size * 4 + column_offset + k) { + matrix.set(alignment_map[base_matrix_size - 1 - i * 2 - k], alignment_map[base_matrix_size - 1 - i * 2 - j]); + } + if message_bits.get(row_offset + row_size * 6 + column_offset + k) { + matrix.set(alignment_map[base_matrix_size - 1 - i * 2 - j], alignment_map[i * 2 + k]); + } + } + k += 1; + } + } + + } + j += 1; + } + } + + row_offset += row_size * 8; + } + i += 1; + } + } + + // draw mode message + ::draw_mode_message(matrix, compact, matrix_size, mode_message); + // draw alignment marks + if compact { + ::draw_bulls_eye(matrix, matrix_size / 2, 5); + } else { + ::draw_bulls_eye(matrix, matrix_size / 2, 7); + { + let mut i: i32 = 0, let mut j: i32 = 0; + while i < base_matrix_size / 2 - 1 { + { + { + let mut k: i32 = (matrix_size / 2) & 1; + while k < matrix_size { + { + matrix.set(matrix_size / 2 - j, k); + matrix.set(matrix_size / 2 + j, k); + matrix.set(k, matrix_size / 2 - j); + matrix.set(k, matrix_size / 2 + j); + } + k += 2; + } + } + + } + i += 15; + j += 16; + } + } + + } + let aztec: AztecCode = AztecCode::new(); + aztec.set_compact(compact); + aztec.set_size(matrix_size); + aztec.set_layers(layers); + aztec.set_code_words(message_size_in_words); + aztec.set_matrix(matrix); + return aztec; + } + + fn draw_bulls_eye( matrix: &BitMatrix, center: i32, size: i32) { + { + let mut i: i32 = 0; + while i < size { + { + { + let mut j: i32 = center - i; + while j <= center + i { + { + matrix.set(j, center - i); + matrix.set(j, center + i); + matrix.set(center - i, j); + matrix.set(center + i, j); + } + j += 1; + } + } + + } + i += 2; + } + } + + matrix.set(center - size, center - size); + matrix.set(center - size + 1, center - size); + matrix.set(center - size, center - size + 1); + matrix.set(center + size, center - size); + matrix.set(center + size, center - size + 1); + matrix.set(center + size, center + size - 1); + } + + fn generate_mode_message( compact: bool, layers: i32, message_size_in_words: i32) -> BitArray { + let mode_message: BitArray = BitArray::new(); + if compact { + mode_message.append_bits(layers - 1, 2); + mode_message.append_bits(message_size_in_words - 1, 6); + mode_message = ::generate_check_words(mode_message, 28, 4); + } else { + mode_message.append_bits(layers - 1, 5); + mode_message.append_bits(message_size_in_words - 1, 11); + mode_message = ::generate_check_words(mode_message, 40, 4); + } + return mode_message; + } + + fn draw_mode_message( matrix: &BitMatrix, compact: bool, matrix_size: i32, mode_message: &BitArray) { + let center: i32 = matrix_size / 2; + if compact { + { + let mut i: i32 = 0; + while i < 7 { + { + let offset: i32 = center - 3 + i; + if mode_message.get(i) { + matrix.set(offset, center - 5); + } + if mode_message.get(i + 7) { + matrix.set(center + 5, offset); + } + if mode_message.get(20 - i) { + matrix.set(offset, center + 5); + } + if mode_message.get(27 - i) { + matrix.set(center - 5, offset); + } + } + i += 1; + } + } + + } else { + { + let mut i: i32 = 0; + while i < 10 { + { + let offset: i32 = center - 5 + i + i / 5; + if mode_message.get(i) { + matrix.set(offset, center - 7); + } + if mode_message.get(i + 10) { + matrix.set(center + 7, offset); + } + if mode_message.get(29 - i) { + matrix.set(offset, center + 7); + } + if mode_message.get(39 - i) { + matrix.set(center - 7, offset); + } + } + i += 1; + } + } + + } + } + + fn generate_check_words( bit_array: &BitArray, total_bits: i32, word_size: i32) -> BitArray { + // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed + let message_size_in_words: i32 = bit_array.get_size() / word_size; + let rs: ReedSolomonEncoder = ReedSolomonEncoder::new(&::get_g_f(word_size)); + let total_words: i32 = total_bits / word_size; + let message_words: Vec = ::bits_to_words(bit_array, word_size, total_words); + rs.encode(&message_words, total_words - message_size_in_words); + let start_pad: i32 = total_bits % word_size; + let message_bits: BitArray = BitArray::new(); + message_bits.append_bits(0, start_pad); + for let message_word: i32 in message_words { + message_bits.append_bits(message_word, word_size); + } + return message_bits; + } + + fn bits_to_words( stuffed_bits: &BitArray, word_size: i32, total_words: i32) -> Vec { + let mut message: [i32; total_words] = [0; total_words]; + let mut i: i32; + let mut n: i32; + { + i = 0; + n = stuffed_bits.get_size() / word_size; + while i < n { + { + let mut value: i32 = 0; + { + let mut j: i32 = 0; + while j < word_size { + { + value |= if stuffed_bits.get(i * word_size + j) { (1 << word_size - j - 1) } else { 0 }; + } + j += 1; + } + } + + message[i] = value; + } + i += 1; + } + } + + return message; + } + + fn get_g_f( word_size: i32) -> GenericGF { + match word_size { + 4 => + { + return GenericGF::AZTEC_PARAM; + } + 6 => + { + return GenericGF::AZTEC_DATA_6; + } + 8 => + { + return GenericGF::AZTEC_DATA_8; + } + 10 => + { + return GenericGF::AZTEC_DATA_10; + } + 12 => + { + return GenericGF::AZTEC_DATA_12; + } + _ => + { + throw IllegalArgumentException::new(format!("Unsupported word size {}", word_size)); + } + } + } + + fn stuff_bits( bits: &BitArray, word_size: i32) -> BitArray { + let out: BitArray = BitArray::new(); + let n: i32 = bits.get_size(); + let mask: i32 = (1 << word_size) - 2; + { + let mut i: i32 = 0; + while i < n { + { + let mut word: i32 = 0; + { + let mut j: i32 = 0; + while j < word_size { + { + if i + j >= n || bits.get(i + j) { + word |= 1 << (word_size - 1 - j); + } + } + j += 1; + } + } + + if (word & mask) == mask { + out.append_bits(word & mask, word_size); + i -= 1; + } else if (word & mask) == 0 { + out.append_bits(word | 1, word_size); + i -= 1; + } else { + out.append_bits(word, word_size); + } + } + i += word_size; + } + } + + return out; + } + + fn total_bits_in_layer( layers: i32, compact: bool) -> i32 { + return (( if compact { 88 } else { 112 }) + 16 * layers) * layers; + } +} + +// BinaryShiftToken.java +struct BinaryShiftToken { + super: Token; + + let binary_shift_start: i32; + + let binary_shift_byte_count: i32; +} + +impl Token for BinaryShiftToken { + pub fn append_to(&self, bit_array: &BitArray, text: &Vec) { + let bsbc: i32 = self.binary_shift_byte_count; + { + let mut i: i32 = 0; + while i < bsbc { + { + if i == 0 || (i == 31 && bsbc <= 62) { + // We need a header before the first character, and before + // character 31 when the total byte code is <= 62 + // BINARY_SHIFT + bit_array.append_bits(31, 5); + if bsbc > 62 { + bit_array.append_bits(bsbc - 31, 16); + } else if i == 0 { + // 1 <= binaryShiftByteCode <= 62 + bit_array.append_bits(&Math::min(bsbc, 31), 5); + } else { + // 32 <= binaryShiftCount <= 62 and i == 31 + bit_array.append_bits(bsbc - 31, 5); + } + } + bit_array.append_bits(text[self.binary_shift_start + i], 8); + } + i += 1; + } + } + + } + + pub fn to_string(&self) -> String { + return format!("<{}::{}>", self.binary_shift_start, (self.binary_shift_start + self.binary_shift_byte_count - 1)); + } +} + +impl BinaryShiftToken { + + fn new( previous: &Token, binary_shift_start: i32, binary_shift_byte_count: i32) -> BinaryShiftToken { + super(previous); + let .binaryShiftStart = binary_shift_start; + let .binaryShiftByteCount = binary_shift_byte_count; + } + + +} + +// HighLevelEncoder.java +/** + * This produces nearly optimal encodings of text into the first-level of + * encoding used by Aztec code. + * + * It uses a dynamic algorithm. For each prefix of the string, it determines + * a set of encodings that could lead to this prefix. We repeatedly add a + * character and generate a new set of optimal encodings until we have read + * through the entire input. + * + * @author Frank Yellin + * @author Rustam Abdullaev + */ + +const MODE_NAMES: vec![Vec; 5] = vec!["UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT", ] +; + +// 5 bits + const MODE_UPPER: i32 = 0; + +// 5 bits + const MODE_LOWER: i32 = 1; + +// 4 bits + const MODE_DIGIT: i32 = 2; + +// 5 bits + const MODE_MIXED: i32 = 3; + +// 5 bits + const MODE_PUNCT: i32 = 4; + +// The Latch Table shows, for each pair of Modes, the optimal method for +// getting from one mode to another. In the worst possible case, this can +// be up to 14 bits. In the best possible case, we are already there! +// The high half-word of each entry gives the number of bits. +// The low half-word of each entry are the actual bits necessary to change + const LATCH_TABLE: vec![vec![Vec>; 5]; 5] = vec![vec![0, // UPPER -> LOWER +(5 << 16) + 28, // UPPER -> DIGIT +(5 << 16) + 30, // UPPER -> MIXED +(5 << 16) + 29, // UPPER -> MIXED -> PUNCT +(10 << 16) + (29 << 5) + 30, ] +, vec![// LOWER -> DIGIT -> UPPER +(9 << 16) + (30 << 4) + 14, 0, // LOWER -> DIGIT +(5 << 16) + 30, // LOWER -> MIXED +(5 << 16) + 29, // LOWER -> MIXED -> PUNCT +(10 << 16) + (29 << 5) + 30, ] +, vec![// DIGIT -> UPPER +(4 << 16) + 14, // DIGIT -> UPPER -> LOWER +(9 << 16) + (14 << 5) + 28, 0, // DIGIT -> UPPER -> MIXED +(9 << 16) + (14 << 5) + 29, (14 << 16) + (14 << 10) + (29 << 5) + 30, ] +, vec![// MIXED -> UPPER +(5 << 16) + 29, // MIXED -> LOWER +(5 << 16) + 28, // MIXED -> UPPER -> DIGIT +(10 << 16) + (29 << 5) + 30, 0, // MIXED -> PUNCT +(5 << 16) + 30, ] +, vec![// PUNCT -> UPPER +(5 << 16) + 31, // PUNCT -> UPPER -> LOWER +(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> DIGIT +(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> MIXED +(10 << 16) + (31 << 5) + 29, 0, ] +, ] +; + +// A reverse mapping from [mode][char] to the encoding for that character +// in that mode. An entry of 0 indicates no mapping exists. + const CHAR_MAP: [[i32; 256]; 5] = [[0; 256]; 5]; + +// A map showing the available shift codes. (The shifts to BINARY are not +// shown +// mode shift codes, per table + const SHIFT_TABLE: [[i32; 6]; 6] = [[0; 6]; 6]; +pub struct HighLevelEncoder { + + let text: Vec; + + let mut charset: Charset; +} + +impl HighLevelEncoder { + + static { + CHAR_MAP[MODE_UPPER][' '] = 1; + { + let mut c: i32 = 'A'; + while c <= 'Z' { + { + CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2; + } + c += 1; + } + } + + CHAR_MAP[MODE_LOWER][' '] = 1; + { + let mut c: i32 = 'a'; + while c <= 'z' { + { + CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2; + } + c += 1; + } + } + + CHAR_MAP[MODE_DIGIT][' '] = 1; + { + let mut c: i32 = '0'; + while c <= '9' { + { + CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2; + } + c += 1; + } + } + + CHAR_MAP[MODE_DIGIT][','] = 12; + CHAR_MAP[MODE_DIGIT]['.'] = 13; + let mixed_table: vec![Vec; 28] = vec!['\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n', '\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^', '_', '`', '|', '~', '\177', ] + ; + { + let mut i: i32 = 0; + while i < mixed_table.len() { + { + CHAR_MAP[MODE_MIXED][mixed_table[i]] = i; + } + i += 1; + } + } + + let punct_table: vec![Vec; 31] = vec!['\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', ] + ; + { + let mut i: i32 = 0; + while i < punct_table.len() { + { + if punct_table[i] > 0 { + CHAR_MAP[MODE_PUNCT][punct_table[i]] = i; + } + } + i += 1; + } + } + + } + + static { + for let table: Vec in SHIFT_TABLE { + Arrays::fill(&table, -1); + } + SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0; + SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0; + SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28; + SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0; + SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0; + SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15; + } + + pub fn new( text: &Vec) -> HighLevelEncoder { + let .text = text; + let .charset = null; + } + + pub fn new( text: &Vec, charset: &Charset) -> HighLevelEncoder { + let .text = text; + let .charset = charset; + } + + /** + * @return text represented by this encoder encoded as a {@link BitArray} + */ + pub fn encode(&self) -> BitArray { + let initial_state: State = State::INITIAL_STATE; + if self.charset != null { + let eci: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i(&self.charset); + if null == eci { + throw IllegalArgumentException::new(format!("No ECI code for character set {}", self.charset)); + } + initial_state = initial_state.append_f_l_gn(&eci.get_value()); + } + let mut states: Collection = Collections::singleton_list(initial_state); + { + let mut index: i32 = 0; + while index < self.text.len() { + { + let pair_code: i32; + let next_char: i32 = if index + 1 < self.text.len() { self.text[index + 1] } else { 0 }; + match self.text[index] { + '\r' => + { + pair_code = if next_char == '\n' { 2 } else { 0 }; + break; + } + '.' => + { + pair_code = if next_char == ' ' { 3 } else { 0 }; + break; + } + ',' => + { + pair_code = if next_char == ' ' { 4 } else { 0 }; + break; + } + ':' => + { + pair_code = if next_char == ' ' { 5 } else { 0 }; + break; + } + _ => + { + pair_code = 0; + } + } + if pair_code > 0 { + // We have one of the four special PUNCT pairs. Treat them specially. + // Get a new set of states for the two new characters. + states = ::update_state_list_for_pair(&states, index, pair_code); + index += 1; + } else { + // Get a new set of states for the new character. + states = self.update_state_list_for_char(&states, index); + } + } + index += 1; + } + } + + // We are left with a set of states. Find the shortest one. + let min_state: State = Collections::min(&states, Comparator::new() { + + pub fn compare(&self, a: &State, b: &State) -> i32 { + return a.get_bit_count() - b.get_bit_count(); + } + }); + // Convert it to a bit array, and return. + return min_state.to_bit_array(&self.text); + } + + // We update a set of states for a new character by updating each state + // for the new character, merging the results, and then removing the + // non-optimal states. + fn update_state_list_for_char(&self, states: &Iterable, index: i32) -> Collection { + let result: Collection = LinkedList<>::new(); + for let state: State in states { + self.update_state_for_char(state, index, &result); + } + return ::simplify_states(&result); + } + + // Return a set of states that represent the possible ways of updating this + // state for the next character. The resulting set of states are added to + // the "result" list. + fn update_state_for_char(&self, state: &State, index: i32, result: &Collection) { + let ch: char = (self.text[index] & 0xFF) as char; + let char_in_current_table: bool = CHAR_MAP[state.get_mode()][ch] > 0; + let state_no_binary: State = null; + { + let mut mode: i32 = 0; + while mode <= MODE_PUNCT { + { + let char_in_mode: i32 = CHAR_MAP[mode][ch]; + if char_in_mode > 0 { + if state_no_binary == null { + // Only create stateNoBinary the first time it's required. + state_no_binary = state.end_binary_shift(index); + } + // Try generating the character by latching to its mode + if !char_in_current_table || mode == state.get_mode() || mode == MODE_DIGIT { + // If the character is in the current table, we don't want to latch to + // any other mode except possibly digit (which uses only 4 bits). Any + // other latch would be equally successful *after* this character, and + // so wouldn't save any bits. + let latch_state: State = state_no_binary.latch_and_append(mode, char_in_mode); + result.add(latch_state); + } + // Try generating the character by switching to its mode. + if !char_in_current_table && SHIFT_TABLE[state.get_mode()][mode] >= 0 { + // It never makes sense to temporarily shift to another mode if the + // character exists in the current mode. That can never save bits. + let shift_state: State = state_no_binary.shift_and_append(mode, char_in_mode); + result.add(shift_state); + } + } + } + mode += 1; + } + } + + if state.get_binary_shift_byte_count() > 0 || CHAR_MAP[state.get_mode()][ch] == 0 { + // It's never worthwhile to go into binary shift mode if you're not already + // in binary shift mode, and the character exists in your current mode. + // That can never save bits over just outputting the char in the current mode. + let binary_state: State = state.add_binary_shift_char(index); + result.add(binary_state); + } + } + + fn update_state_list_for_pair( states: &Iterable, index: i32, pair_code: i32) -> Collection { + let result: Collection = LinkedList<>::new(); + for let state: State in states { + ::update_state_for_pair(state, index, pair_code, &result); + } + return ::simplify_states(&result); + } + + fn update_state_for_pair( state: &State, index: i32, pair_code: i32, result: &Collection) { + let state_no_binary: State = state.end_binary_shift(index); + // Possibility 1. Latch to MODE_PUNCT, and then append this code + result.add(&state_no_binary.latch_and_append(MODE_PUNCT, pair_code)); + if state.get_mode() != MODE_PUNCT { + // Possibility 2. Shift to MODE_PUNCT, and then append this code. + // Every state except MODE_PUNCT (handled above) can shift + result.add(&state_no_binary.shift_and_append(MODE_PUNCT, pair_code)); + } + if pair_code == 3 || pair_code == 4 { + // both characters are in DIGITS. Sometimes better to just add two digits + let digit_state: State = state_no_binary.latch_and_append(MODE_DIGIT, // period or comma in DIGIT + 16 - pair_code).latch_and_append(MODE_DIGIT, // space in DIGIT + 1); + result.add(digit_state); + } + if state.get_binary_shift_byte_count() > 0 { + // It only makes sense to do the characters as binary if we're already + // in binary mode. + let binary_state: State = state.add_binary_shift_char(index).add_binary_shift_char(index + 1); + result.add(binary_state); + } + } + + fn simplify_states( states: &Iterable) -> Collection { + let result: Deque = LinkedList<>::new(); + for let new_state: State in states { + let mut add: bool = true; + { + let iterator: Iterator = result.iterator(); + while iterator.has_next(){ + let old_state: State = iterator.next(); + if old_state.is_better_than_or_equal_to(new_state) { + add = false; + break; + } + if new_state.is_better_than_or_equal_to(old_state) { + iterator.remove(); + } + } + } + + if add { + result.add_first(new_state); + } + } + return result; + } +} + +// SimpleToken.java +struct SimpleToken { + super: Token; + + // For normal words, indicates value and bitCount + let value: i16; + + let bit_count: i16; +} + +impl Token for SimpleToken { + fn append_to(&self, bit_array: &BitArray, text: &Vec) { + bit_array.append_bits(self.value, self.bit_count); + } + + pub fn to_string(&self) -> String { + let mut value: i32 = self.value & ((1 << self.bit_count) - 1); + value |= 1 << self.bit_count; + return '<' + Integer::to_binary_string(value | (1 << self.bit_count))::substring(1) + '>'; + } +} + +impl SimpleToken { + + fn new( previous: &Token, value: i32, bit_count: i32) -> SimpleToken { + super(previous); + let .value = value as i16; + let .bitCount = bit_count as i16; + } + +} + +// State.java + +/** + * State represents all information about a sequence necessary to generate the current output. + * Note that a state is immutable. + */ + +const INITIAL_STATE: State = State::new(Token::EMPTY, HighLevelEncoder::MODE_UPPER, 0, 0); +struct State { + + // The current mode of the encoding (or the mode to which we'll return if + // we're in Binary Shift mode. + let mode: i32; + + // The list of tokens that we output. If we are in Binary Shift mode, this + // token list does *not* yet included the token for those bytes + let token: Token; + + // If non-zero, the number of most recent bytes that should be output + // in Binary Shift mode. + let binary_shift_byte_count: i32; + + // The total number of bits generated (including Binary Shift). + let bit_count: i32; + + let binary_shift_cost: i32; +} + +impl State { + + fn new( token: &Token, mode: i32, binary_bytes: i32, bit_count: i32) -> State { + let .token = token; + let .mode = mode; + let .binaryShiftByteCount = binary_bytes; + let .bitCount = bit_count; + let .binaryShiftCost = ::calculate_binary_shift_cost(binary_bytes); + } + + fn get_mode(&self) -> i32 { + return self.mode; + } + + fn get_token(&self) -> Token { + return self.token; + } + + fn get_binary_shift_byte_count(&self) -> i32 { + return self.binary_shift_byte_count; + } + + fn get_bit_count(&self) -> i32 { + return self.bit_count; + } + + fn append_f_l_gn(&self, eci: i32) -> State { + // 0: FLG(n) + let result: State = self.shift_and_append(HighLevelEncoder::MODE_PUNCT, 0); + let mut token: Token = result.token; + let bits_added: i32 = 3; + if eci < 0 { + // 0: FNC1 + token = token.add(0, 3); + } else if eci > 999999 { + throw IllegalArgumentException::new("ECI code must be between 0 and 999999"); + } else { + let eci_digits: Vec = Integer::to_string(eci)::get_bytes(StandardCharsets::ISO_8859_1); + // 1-6: number of ECI digits + token = token.add(eci_digits.len(), 3); + for let eci_digit: i8 in eci_digits { + token = token.add(eci_digit - '0' + 2, 4); + } + bits_added += eci_digits.len() * 4; + } + return State::new(token, self.mode, 0, self.bit_count + bits_added); + } + + // Create a new state representing this state with a latch to a (not + // necessary different) mode, and then a code. + fn latch_and_append(&self, mode: i32, value: i32) -> State { + let bit_count: i32 = self.bitCount; + let mut token: Token = self.token; + if mode != self.mode { + let latch: i32 = HighLevelEncoder::LATCH_TABLE[self.mode][mode]; + token = token.add(latch & 0xFFFF, latch >> 16); + bit_count += latch >> 16; + } + let latch_mode_bit_count: i32 = if mode == HighLevelEncoder::MODE_DIGIT { 4 } else { 5 }; + token = token.add(value, latch_mode_bit_count); + return State::new(token, mode, 0, bit_count + latch_mode_bit_count); + } + + // Create a new state representing this state, with a temporary shift + // to a different mode to output a single value. + fn shift_and_append(&self, mode: i32, value: i32) -> State { + let mut token: Token = self.token; + let this_mode_bit_count: i32 = if self.mode == HighLevelEncoder::MODE_DIGIT { 4 } else { 5 }; + // Shifts exist only to UPPER and PUNCT, both with tokens size 5. + token = token.add(HighLevelEncoder::SHIFT_TABLE[self.mode][mode], this_mode_bit_count); + token = token.add(value, 5); + return State::new(token, self.mode, 0, self.bitCount + this_mode_bit_count + 5); + } + + // Create a new state representing this state, but an additional character + // output in Binary Shift mode. + fn add_binary_shift_char(&self, index: i32) -> State { + let mut token: Token = self.token; + let mut mode: i32 = self.mode; + let bit_count: i32 = self.bitCount; + if self.mode == HighLevelEncoder::MODE_PUNCT || self.mode == HighLevelEncoder::MODE_DIGIT { + let latch: i32 = HighLevelEncoder::LATCH_TABLE[mode][HighLevelEncoder::MODE_UPPER]; + token = token.add(latch & 0xFFFF, latch >> 16); + bit_count += latch >> 16; + mode = HighLevelEncoder::MODE_UPPER; + } + let delta_bit_count: i32 = if (self.binary_shift_byte_count == 0 || self.binary_shift_byte_count == 31) { 18 } else { if (self.binary_shift_byte_count == 62) { 9 } else { 8 } }; + let mut result: State = State::new(token, mode, self.binary_shift_byte_count + 1, bit_count + delta_bit_count); + if result.binaryShiftByteCount == 2047 + 31 { + // The string is as long as it's allowed to be. We should end it. + result = result.end_binary_shift(index + 1); + } + return result; + } + + // Create the state identical to this one, but we are no longer in + // Binary Shift mode. + fn end_binary_shift(&self, index: i32) -> State { + if self.binary_shift_byte_count == 0 { + return self; + } + let mut token: Token = self.token; + token = token.add_binary_shift(index - self.binary_shift_byte_count, self.binary_shift_byte_count); + return State::new(token, self.mode, 0, self.bitCount); + } + + // Returns true if "this" state is better (or equal) to be in than "that" + // state under all possible circumstances. + fn is_better_than_or_equal_to(&self, other: &State) -> bool { + let new_mode_bit_count: i32 = self.bitCount + (HighLevelEncoder::LATCH_TABLE[self.mode][other.mode] >> 16); + if self.binaryShiftByteCount < other.binaryShiftByteCount { + // add additional B/S encoding cost of other, if any + new_mode_bit_count += other.binaryShiftCost - self.binaryShiftCost; + } else if self.binaryShiftByteCount > other.binaryShiftByteCount && other.binaryShiftByteCount > 0 { + // maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it) + new_mode_bit_count += 10; + } + return new_mode_bit_count <= other.bitCount; + } + + fn to_bit_array(&self, text: &Vec) -> BitArray { + let symbols: List = ArrayList<>::new(); + { + let mut token: Token = self.end_binary_shift(text.len()).token; + while token != null { + { + symbols.add(token); + } + token = token.get_previous(); + } + } + + let bit_array: BitArray = BitArray::new(); + // Add each token to the result in forward order + { + let mut i: i32 = symbols.size() - 1; + while i >= 0 { + { + symbols.get(i).append_to(bit_array, &text); + } + i -= 1; + } + } + + return bit_array; + } + + pub fn to_string(&self) -> String { + return String::format("%s bits=%d bytes=%d", HighLevelEncoder::MODE_NAMES[self.mode], self.bit_count, self.binary_shift_byte_count); + } + + fn calculate_binary_shift_cost( binary_shift_byte_count: i32) -> i32 { + if binary_shift_byte_count > 62 { + // B/S with extended length + return 21; + } + if binary_shift_byte_count > 31 { + // two B/S + return 20; + } + if binary_shift_byte_count > 0 { + // one B/S + return 10; + } + return 0; + } +}