red lines on datamatrix

This commit is contained in:
Henry Schimke
2022-08-19 17:30:18 -05:00
parent c92f1fb24c
commit b8c45efe7f
5 changed files with 1086 additions and 1058 deletions

View File

@@ -1939,7 +1939,7 @@ impl DecoderResult {
pub fn new( pub fn new(
raw_bytes: &Vec<i8>, raw_bytes: &Vec<i8>,
text: &String, text: &String,
byte_segments: &List<Vec<i8>>, byte_segments: &Vec<Vec<i8>>,
ec_level: &String, ec_level: &String,
sa_sequence: Option<i32>, sa_sequence: Option<i32>,
sa_parity: Option<i32>, sa_parity: Option<i32>,

View File

@@ -1,3 +1,7 @@
pub mod decoder;
pub mod detector;
pub mod encoder;
use crate::{BarcodeFormat,BinaryBitmap,DecodeHintType,ChecksumException,FormatException,NotFoundException,Reader,RXingResult,ResultMetadataType,ResultPoint,EncodeHintType,Writer,Dimension}; use crate::{BarcodeFormat,BinaryBitmap,DecodeHintType,ChecksumException,FormatException,NotFoundException,Reader,RXingResult,ResultMetadataType,ResultPoint,EncodeHintType,Writer,Dimension};
use crate::common::{DecoderResult,BitMatrix,DetectorResult,}; use crate::common::{DecoderResult,BitMatrix,DetectorResult,};
use crate::datamatrix::decoder::{Decoder}; use crate::datamatrix::decoder::{Decoder};
@@ -14,10 +18,9 @@ use crate::qrcode::encoder::ByteMatrix;
*/ */
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0]; const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
#[derive(Reader)]
pub struct DataMatrixReader { pub struct DataMatrixReader {
let decoder: Decoder = Decoder::new(); decoder: Decoder
} }
impl Reader for DataMatrixReader{ impl Reader for DataMatrixReader{
@@ -29,11 +32,7 @@ impl Reader for DataMatrixReader{
* @throws FormatException if a Data Matrix code cannot be decoded * @throws FormatException if a Data Matrix code cannot be decoded
* @throws ChecksumException if error correction fails * @throws ChecksumException if error correction fails
*/ */
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> { fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, _>) -> Result<Result, NotFoundException, ChecksumException, FormatException> {
return Ok(self.decode(image, null));
}
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
let decoder_result: DecoderResult; let decoder_result: DecoderResult;
let mut points: Vec<ResultPoint>; let mut points: Vec<ResultPoint>;
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) { if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
@@ -58,14 +57,18 @@ pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) ->
return Ok(result); return Ok(result);
} }
pub fn reset(&self) { fn reset(&self) {
// do nothing // do nothing
} }
} }
impl DataMatrixReader { impl DataMatrixReader {
pub fn new() -> Self {
Self{
decoder: Decoder::new(),
}
}
/** /**
* This method detects a code in a "pure" image -- that is, pure monochrome image * This method detects a code in a "pure" image -- that is, pure monochrome image
@@ -73,11 +76,11 @@ impl DataMatrixReader {
* around it. This is a specialized method that works exceptionally fast in this special * around it. This is a specialized method that works exceptionally fast in this special
* case. * case.
*/ */
fn extract_pure_bits( image: &BitMatrix) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> { fn extract_pure_bits( image: &BitMatrix) -> Result<BitMatrix, NotFoundException> {
let left_top_black: Vec<i32> = image.get_top_left_on_bit(); let left_top_black: Vec<i32> = image.get_top_left_on_bit();
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit(); let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
if left_top_black == null || right_bottom_black == null { if left_top_black == null || right_bottom_black == null {
throw NotFoundException::get_not_found_instance(); return Err( NotFoundException::get_not_found_instance());
} }
let module_size: i32 = self.module_size(&left_top_black, image); let module_size: i32 = self.module_size(&left_top_black, image);
let mut top: i32 = left_top_black[1]; let mut top: i32 = left_top_black[1];
@@ -87,7 +90,7 @@ impl DataMatrixReader {
let matrix_width: i32 = (right - left + 1) / module_size; let matrix_width: i32 = (right - left + 1) / module_size;
let matrix_height: i32 = (bottom - top + 1) / module_size; let matrix_height: i32 = (bottom - top + 1) / module_size;
if matrix_width <= 0 || matrix_height <= 0 { if matrix_width <= 0 || matrix_height <= 0 {
throw NotFoundException::get_not_found_instance(); return Err( NotFoundException::get_not_found_instance());
} }
// Push in the "border" by half the module width so that we start // Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a // sampling in the middle of the module. Just in case the image is a
@@ -122,7 +125,7 @@ impl DataMatrixReader {
return Ok(bits); return Ok(bits);
} }
fn module_size( left_top_black: &Vec<i32>, image: &BitMatrix) -> /* throws NotFoundException */Result<i32, Rc<Exception>> { fn module_size( left_top_black: &Vec<i32>, image: &BitMatrix) -> Result<i32, NotFoundException> {
let width: i32 = image.get_width(); let width: i32 = image.get_width();
let mut x: i32 = left_top_black[0]; let mut x: i32 = left_top_black[0];
let y: i32 = left_top_black[1]; let y: i32 = left_top_black[1];
@@ -130,11 +133,11 @@ impl DataMatrixReader {
x += 1; x += 1;
} }
if x == width { if x == width {
throw NotFoundException::get_not_found_instance(); return Err( NotFoundException::get_not_found_instance());
} }
let module_size: i32 = x - left_top_black[0]; let module_size: i32 = x - left_top_black[0];
if module_size == 0 { if module_size == 0 {
throw NotFoundException::get_not_found_instance(); return Err( NotFoundException::get_not_found_instance());
} }
return Ok(module_size); return Ok(module_size);
} }
@@ -150,24 +153,20 @@ impl DataMatrixReader {
* @author dswitkin@google.com (Daniel Switkin) * @author dswitkin@google.com (Daniel Switkin)
* @author Guillaume Le Biller Added to zxing lib. * @author Guillaume Le Biller Added to zxing lib.
*/ */
#[derive(Writer)]
pub struct DataMatrixWriter { pub struct DataMatrixWriter {
} }
impl Writer for DataMatrixWriter{ impl Writer for DataMatrixWriter{
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> BitMatrix {
return self.encode(&contents, format, width, height, null);
}
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, ?>) -> BitMatrix { fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, _>) -> BitMatrix {
if contents.is_empty() { if contents.is_empty() {
throw IllegalArgumentException::new("Found empty contents"); return Err( IllegalArgumentException::new("Found empty contents"));
} }
if format != BarcodeFormat::DATA_MATRIX { if format != BarcodeFormat::DATA_MATRIX {
throw IllegalArgumentException::new(format!("Can only encode DATA_MATRIX, but got {}", format)); return Err( IllegalArgumentException::new(format!("Can only encode DATA_MATRIX, but got {}", format)));
} }
if width < 0 || height < 0 { if width < 0 || height < 0 {
throw IllegalArgumentException::new(format!("Requested dimensions can't be negative: {}x{}", width, height)); return Err( IllegalArgumentException::new(format!("Requested dimensions can't be negative: {}x{}", width, height)));
} }
// Try to get force shape & min / max size // Try to get force shape & min / max size
let mut shape: SymbolShapeHint = SymbolShapeHint::FORCE_NONE; let mut shape: SymbolShapeHint = SymbolShapeHint::FORCE_NONE;
@@ -197,14 +196,14 @@ impl Writer for DataMatrixWriter{
if has_encoding_hint { if has_encoding_hint {
charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string()); charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
} }
encoded = MinimalEncoder::encode_high_level(&contents, &charset, if has_g_s1_format_hint { 0x1D } else { -1 }, shape); encoded = MinimalEncoder::encode_high_level(&contents, &charset, if has_g_s1_format_hint { 0x1D } else { -1 }, &shape);
} else { } else {
let has_force_c40_hint: bool = hints != null && hints.contains_key(EncodeHintType::FORCE_C40) && Boolean::parse_boolean(&hints.get(EncodeHintType::FORCE_C40).to_string()); let has_force_c40_hint: bool = hints != null && hints.contains_key(EncodeHintType::FORCE_C40) && Boolean::parse_boolean(&hints.get(EncodeHintType::FORCE_C40).to_string());
encoded = HighLevelEncoder::encode_high_level(&contents, shape, min_size, max_size, has_force_c40_hint); encoded = HighLevelEncoder::encode_high_level(&contents, shape, min_size, max_size, has_force_c40_hint);
} }
let symbol_info: SymbolInfo = SymbolInfo::lookup(&encoded.length(), shape, min_size, max_size, true); let symbol_info: SymbolInfo = SymbolInfo::lookup(&encoded.length(), shape, min_size, max_size, true);
//2. step: ECC generation //2. step: ECC generation
let codewords: String = ErrorCorrection::encode_e_c_c200(&encoded, symbol_info); let codewords: String = ErrorCorrection::encode_e_c_c200(&encoded, &symbol_info);
//3. step: Module placement in Matrix //3. step: Module placement in Matrix
let placement: DefaultPlacement = DefaultPlacement::new(&codewords, &symbol_info.get_symbol_data_width(), &symbol_info.get_symbol_data_height()); let placement: DefaultPlacement = DefaultPlacement::new(&codewords, &symbol_info.get_symbol_data_width(), &symbol_info.get_symbol_data_height());
placement.place(); placement.place();
@@ -329,7 +328,8 @@ impl DataMatrixWriter {
{ {
// Write the contents of this row of the bytematrix // Write the contents of this row of the bytematrix
{ {
let input_x: i32 = 0, let output_x: i32 = left_padding; let input_x: i32 = 0;
let output_x: i32 = left_padding;
while input_x < matrix_width { while input_x < matrix_width {
{ {
if matrix.get(input_x, input_y) == 1 { if matrix.get(input_x, input_y) == 1 {

View File

@@ -9,11 +9,11 @@ use crate::common::reedsolomon::{GenericGF,ReedSolomonDecoder,ReedSolomonExcepti
*/ */
struct BitMatrixParser { struct BitMatrixParser {
let mapping_bit_matrix: BitMatrix; mapping_bit_matrix: BitMatrix,
let read_mapping_matrix: BitMatrix; read_mapping_matrix: BitMatrix,
let mut version: Version; version: Version
} }
impl BitMatrixParser { impl BitMatrixParser {
@@ -22,14 +22,17 @@ impl BitMatrixParser {
* @param bitMatrix {@link BitMatrix} to parse * @param bitMatrix {@link BitMatrix} to parse
* @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2 * @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2
*/ */
fn new( bit_matrix: &BitMatrix) -> BitMatrixParser throws FormatException { fn new( bit_matrix: &BitMatrix) -> Result<Self, FormatException> {
let dimension: i32 = bit_matrix.get_height(); let dimension: i32 = bit_matrix.get_height();
if dimension < 8 || dimension > 144 || (dimension & 0x01) != 0 { if dimension < 8 || dimension > 144 || (dimension & 0x01) != 0 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
version = ::read_version(bit_matrix); let new_bmp : Self;
let .mappingBitMatrix = self.extract_data_region(bit_matrix); new_bmp.version = ::read_version(bit_matrix);
let .readMappingMatrix = BitMatrix::new(&let .mappingBitMatrix.get_width(), &let .mappingBitMatrix.get_height()); new_bmp .mappingBitMatrix = self.extract_data_region(bit_matrix);
new_bmp .readMappingMatrix = BitMatrix::new(&new_bmp.mappingBitMatrix.get_width(), &new_bmp.mappingBitMatrix.get_height());
Ok(new_bmp)
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {
@@ -61,7 +64,7 @@ impl BitMatrixParser {
* @return bytes encoded within the Data Matrix Code * @return bytes encoded within the Data Matrix Code
* @throws FormatException if the exact number of bytes expected is not read * @throws FormatException if the exact number of bytes expected is not read
*/ */
fn read_codewords(&self) -> /* throws FormatException */Result<Vec<i8>, Rc<Exception>> { fn read_codewords(&self) -> Result<Vec<i8>, FormatException> {
let mut result: [i8; self.version.get_total_codewords()] = [0; self.version.get_total_codewords()]; let mut result: [i8; self.version.get_total_codewords()] = [0; self.version.get_total_codewords()];
let result_offset: i32 = 0; let result_offset: i32 = 0;
let mut row: i32 = 4; let mut row: i32 = 4;
@@ -76,22 +79,22 @@ impl BitMatrixParser {
loop { { loop { {
// Check the four corner cases // Check the four corner cases
if (row == num_rows) && (column == 0) && !corner1_read { if (row == num_rows) && (column == 0) && !corner1_read {
result[result_offset += 1 !!!check!!! post increment] = self.read_corner1(num_rows, num_columns) as i8; result[result_offset += 1 ] = self.read_corner1(num_rows, num_columns) as i8;
row -= 2; row -= 2;
column += 2; column += 2;
corner1_read = true; corner1_read = true;
} else if (row == num_rows - 2) && (column == 0) && ((num_columns & 0x03) != 0) && !corner2_read { } else if (row == num_rows - 2) && (column == 0) && ((num_columns & 0x03) != 0) && !corner2_read {
result[result_offset += 1 !!!check!!! post increment] = self.read_corner2(num_rows, num_columns) as i8; result[result_offset += 1 ] = self.read_corner2(num_rows, num_columns) as i8;
row -= 2; row -= 2;
column += 2; column += 2;
corner2_read = true; corner2_read = true;
} else if (row == num_rows + 4) && (column == 2) && ((num_columns & 0x07) == 0) && !corner3_read { } else if (row == num_rows + 4) && (column == 2) && ((num_columns & 0x07) == 0) && !corner3_read {
result[result_offset += 1 !!!check!!! post increment] = self.read_corner3(num_rows, num_columns) as i8; result[result_offset += 1 ] = self.read_corner3(num_rows, num_columns) as i8;
row -= 2; row -= 2;
column += 2; column += 2;
corner3_read = true; corner3_read = true;
} else if (row == num_rows - 2) && (column == 0) && ((num_columns & 0x07) == 4) && !corner4_read { } else if (row == num_rows - 2) && (column == 0) && ((num_columns & 0x07) == 4) && !corner4_read {
result[result_offset += 1 !!!check!!! post increment] = self.read_corner4(num_rows, num_columns) as i8; result[result_offset += 1 ] = self.read_corner4(num_rows, num_columns) as i8;
row -= 2; row -= 2;
column += 2; column += 2;
corner4_read = true; corner4_read = true;
@@ -99,27 +102,27 @@ impl BitMatrixParser {
// Sweep upward diagonally to the right // Sweep upward diagonally to the right
loop { { loop { {
if (row < num_rows) && (column >= 0) && !self.read_mapping_matrix.get(column, row) { if (row < num_rows) && (column >= 0) && !self.read_mapping_matrix.get(column, row) {
result[result_offset += 1 !!!check!!! post increment] = self.read_utah(row, column, num_rows, num_columns) as i8; result[result_offset += 1 ] = self.read_utah(row, column, num_rows, num_columns) as i8;
} }
row -= 2; row -= 2;
column += 2; column += 2;
}if !((row >= 0) && (column < num_columns)) break;} }if !((row >= 0) && (column < num_columns)) {break;}}
row += 1; row += 1;
column += 3; column += 3;
// Sweep downward diagonally to the left // Sweep downward diagonally to the left
loop { { loop { {
if (row >= 0) && (column < num_columns) && !self.read_mapping_matrix.get(column, row) { if (row >= 0) && (column < num_columns) && !self.read_mapping_matrix.get(column, row) {
result[result_offset += 1 !!!check!!! post increment] = self.read_utah(row, column, num_rows, num_columns) as i8; result[result_offset += 1 ] = self.read_utah(row, column, num_rows, num_columns) as i8;
} }
row += 2; row += 2;
column -= 2; column -= 2;
}if !((row < num_rows) && (column >= 0)) break;} }if !((row < num_rows) && (column >= 0)) {break;}}
row += 3; row += 3;
column += 1; column += 1;
} }
}if !((row < num_rows) || (column < num_columns)) break;} }if !((row < num_rows) || (column < num_columns)) {break;}}
if result_offset != self.version.get_total_codewords() { if result_offset != self.version.get_total_codewords() {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
return Ok(result); return Ok(result);
} }
@@ -388,7 +391,7 @@ impl BitMatrixParser {
let symbol_size_rows: i32 = self.version.get_symbol_size_rows(); let symbol_size_rows: i32 = self.version.get_symbol_size_rows();
let symbol_size_columns: i32 = self.version.get_symbol_size_columns(); let symbol_size_columns: i32 = self.version.get_symbol_size_columns();
if bit_matrix.get_height() != symbol_size_rows { if bit_matrix.get_height() != symbol_size_rows {
throw IllegalArgumentException::new("Dimension of bitMatrix must match the version size"); return Err( IllegalArgumentException::new("Dimension of bitMatrix must match the version size"));
} }
let data_region_size_rows: i32 = self.version.get_data_region_size_rows(); let data_region_size_rows: i32 = self.version.get_data_region_size_rows();
let data_region_size_columns: i32 = self.version.get_data_region_size_columns(); let data_region_size_columns: i32 = self.version.get_data_region_size_columns();
@@ -457,17 +460,18 @@ impl BitMatrixParser {
*/ */
struct DataBlock { struct DataBlock {
let num_data_codewords: i32; num_data_codewords: i32,
let mut codewords: Vec<i8>; codewords: Vec<i8>
} }
impl DataBlock { impl DataBlock {
fn new( num_data_codewords: i32, codewords: &Vec<i8>) -> DataBlock { fn new( num_data_codewords: i32, codewords: &Vec<i8>) -> Self {
let .numDataCodewords = num_data_codewords; Self {
let .codewords = codewords; num_data_codewords,
} codewords: codewords,
}}
/** /**
* <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them. * <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.
@@ -481,24 +485,24 @@ impl DataBlock {
*/ */
fn get_data_blocks( raw_codewords: &Vec<i8>, version: &Version) -> Vec<DataBlock> { fn get_data_blocks( raw_codewords: &Vec<i8>, version: &Version) -> Vec<DataBlock> {
// Figure out the number and size of data blocks used by this version // Figure out the number and size of data blocks used by this version
let ec_blocks: Version.ECBlocks = version.get_e_c_blocks(); let ec_blocks: Version::ECBlocks = version.get_e_c_blocks();
// First count the total number of data blocks // First count the total number of data blocks
let total_blocks: i32 = 0; let total_blocks: i32 = 0;
let ec_block_array: Vec<Version.ECB> = ec_blocks.get_e_c_blocks(); let ec_block_array: Vec<Version::ECB> = ec_blocks.get_e_c_blocks();
for let ec_block: Version.ECB in ec_block_array { for ec_block in ec_block_array {
total_blocks += ec_block.get_count(); total_blocks += ec_block.get_count();
} }
// Now establish DataBlocks of the appropriate size and number of data codewords // Now establish DataBlocks of the appropriate size and number of data codewords
let mut result: [Option<DataBlock>; total_blocks] = [None; total_blocks]; let mut result: [Option<DataBlock>; total_blocks] = [None; total_blocks];
let num_result_blocks: i32 = 0; let num_result_blocks: i32 = 0;
for let ec_block: Version.ECB in ec_block_array { for ec_block in ec_block_array {
{ {
let mut i: i32 = 0; let mut i: i32 = 0;
while i < ec_block.get_count() { while i < ec_block.get_count() {
{ {
let num_data_codewords: i32 = ec_block.get_data_codewords(); let num_data_codewords: i32 = ec_block.get_data_codewords();
let num_block_codewords: i32 = ec_blocks.get_e_c_codewords() + num_data_codewords; let num_block_codewords: i32 = ec_blocks.get_e_c_codewords() + num_data_codewords;
result[num_result_blocks += 1 !!!check!!! post increment] = DataBlock::new(num_data_codewords, : [i8; num_block_codewords] = [0; num_block_codewords]); result[num_result_blocks += 1 ] = DataBlock::new(num_data_codewords, [0; num_block_codewords]);
} }
i += 1; i += 1;
} }
@@ -523,7 +527,7 @@ impl DataBlock {
let mut j: i32 = 0; let mut j: i32 = 0;
while j < num_result_blocks { while j < num_result_blocks {
{ {
result[j].codewords[i] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment]; result[j].codewords[i] = raw_codewords[raw_codewords_offset += 1 ];
} }
j += 1; j += 1;
} }
@@ -541,7 +545,7 @@ impl DataBlock {
let mut j: i32 = 0; let mut j: i32 = 0;
while j < num_longer_blocks { while j < num_longer_blocks {
{ {
result[j].codewords[longer_blocks_num_data_codewords - 1] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment]; result[j].codewords[longer_blocks_num_data_codewords - 1] = raw_codewords[raw_codewords_offset += 1 ];
} }
j += 1; j += 1;
} }
@@ -559,7 +563,7 @@ impl DataBlock {
{ {
let j_offset: i32 = if special_version { (j + 8) % num_result_blocks } else { j }; let j_offset: i32 = if special_version { (j + 8) % num_result_blocks } else { j };
let i_offset: i32 = if special_version && j_offset > 7 { i - 1 } else { i }; let i_offset: i32 = if special_version && j_offset > 7 { i - 1 } else { i };
result[j_offset].codewords[i_offset] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment]; result[j_offset].codewords[i_offset] = raw_codewords[raw_codewords_offset += 1 ];
} }
j += 1; j += 1;
} }
@@ -571,7 +575,7 @@ impl DataBlock {
} }
if raw_codewords_offset != raw_codewords.len() { if raw_codewords_offset != raw_codewords.len() {
throw IllegalArgumentException::new(); return Err( IllegalArgumentException::new());
} }
return result; return result;
} }
@@ -615,10 +619,6 @@ impl DataBlock {
const TEXT_SHIFT3_SET_CHARS: vec![Vec<char>; 32] = vec!['`', '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', '{', '|', '}', '~', 127 as char, ] const TEXT_SHIFT3_SET_CHARS: vec![Vec<char>; 32] = vec!['`', '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', '{', '|', '}', '~', 127 as char, ]
; ;
struct DecodedBitStreamParser {
}
impl DecodedBitStreamParser {
enum Mode { enum Mode {
@@ -626,17 +626,24 @@ impl DataBlock {
PAD_ENCODE(), ASCII_ENCODE(), C40_ENCODE(), TEXT_ENCODE(), ANSIX12_ENCODE(), EDIFACT_ENCODE(), BASE256_ENCODE(), ECI_ENCODE() PAD_ENCODE(), ASCII_ENCODE(), C40_ENCODE(), TEXT_ENCODE(), ANSIX12_ENCODE(), EDIFACT_ENCODE(), BASE256_ENCODE(), ECI_ENCODE()
} }
struct DecodedBitStreamParser {
}
impl DecodedBitStreamParser {
fn new() -> DecodedBitStreamParser { fn new() -> DecodedBitStreamParser {
} }
fn decode( bytes: &Vec<i8>) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> { fn decode( bytes: &Vec<i8>) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
let bits: BitSource = BitSource::new(&bytes); let bits: BitSource = BitSource::new(&bytes);
let result: ECIStringBuilder = ECIStringBuilder::new(100); let result: ECIStringBuilder = ECIStringBuilder::new();
let result_trailer: StringBuilder = StringBuilder::new(0); let result_trailer: StringBuilder = StringBuilder::new(0);
let byte_segments: List<Vec<i8>> = ArrayList<>::new(1); let byte_segments: List<Vec<i8>> = Vec::new();
let mut mode: Mode = Mode::ASCII_ENCODE; let mut mode: Mode = Mode::ASCII_ENCODE;
// Could look directly at 'bytes', if we're sure of not having to account for multi byte values // Could look directly at 'bytes', if we're sure of not having to account for multi byte values
let fnc1_positions: Set<Integer> = HashSet<>::new(); let fnc1_positions: Set<Integer> = HashSet::new();
let symbology_modifier: i32; let symbology_modifier: i32;
let is_e_c_iencoded: bool = false; let is_e_c_iencoded: bool = false;
loop { { loop { {
@@ -678,12 +685,12 @@ impl DataBlock {
} }
_ => _ =>
{ {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
} }
mode = Mode::ASCII_ENCODE; mode = Mode::ASCII_ENCODE;
} }
}if !(mode != Mode::PAD_ENCODE && bits.available() > 0) break;} }if !(mode != Mode::PAD_ENCODE && bits.available() > 0) {break;}}
if result_trailer.length() > 0 { if result_trailer.length() > 0 {
result.append_characters(&result_trailer); result.append_characters(&result_trailer);
} }
@@ -704,8 +711,11 @@ impl DataBlock {
} else { } else {
symbology_modifier = 1; symbology_modifier = 1;
} }
} }
return Ok(DecoderResult::new(&bytes, &result.to_string(), if byte_segments.is_empty() { null } else { byte_segments }, null, symbology_modifier)); return Ok(DecoderResult::new(&bytes, &result.to_string(), &byte_segments , null, Some(symbology_modifier), None, None));
} }
/** /**
@@ -716,7 +726,7 @@ impl DataBlock {
loop { { loop { {
let one_byte: i32 = bits.read_bits(8); let one_byte: i32 = bits.read_bits(8);
if one_byte == 0 { if one_byte == 0 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} else if one_byte <= 128 { } else if one_byte <= 128 {
// ASCII data (ASCII value + 1) // ASCII data (ASCII value + 1)
if upper_shift { if upper_shift {
@@ -775,15 +785,15 @@ impl DataBlock {
// 05 Macro // 05 Macro
236 => 236 =>
{ {
result.append("[)>\u001E05\u001D"); result.append("[)>\u{001E05}\u{001D}");
result_trailer.insert(0, "\u001E\u0004"); result_trailer.insert(0, "\u{001E}\u{0004}");
break; break;
} }
// 06 Macro // 06 Macro
237 => 237 =>
{ {
result.append("[)>\u001E06\u001D"); result.append("[)>\u{001E06}\u{001D}");
resultTrailer.insert(0, "\u001E\u0004"); resultTrailer.insert(0, "\u{001E}\u{0004}");
break; break;
} }
// Latch to ANSI X12 encodation // Latch to ANSI X12 encodation
@@ -810,20 +820,20 @@ impl DataBlock {
{ {
// but work around encoders that end with 254, latch back to ASCII // but work around encoders that end with 254, latch back to ASCII
if one_byte != 254 || bits.available() != 0 { if one_byte != 254 || bits.available() != 0 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
break; break;
} }
} }
} }
}if !(bits.available() > 0) break;} }if !(bits.available() > 0) {break;}}
return Ok(Mode::ASCII_ENCODE); return Ok(Mode::ASCII_ENCODE);
} }
/** /**
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
*/ */
fn decode_c40_segment( bits: &BitSource, result: &ECIStringBuilder, fnc1positions: &Set<Integer>) -> /* throws FormatException */Result<Void, Rc<Exception>> { fn decode_c40_segment( bits: &BitSource, result: &ECIStringBuilder, fnc1positions: &Set<Integer>) -> Result<(), FormatException> {
// Three C40 values are encoded in a 16-bit value as // Three C40 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1 // (1600 * C1) + (40 * C2) + C3 + 1
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
@@ -860,7 +870,7 @@ impl DataBlock {
result.append(c40char); result.append(c40char);
} }
} else { } else {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
break; break;
} }
@@ -903,7 +913,7 @@ impl DataBlock {
} }
_ => _ =>
{ {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
} }
} }
@@ -923,7 +933,7 @@ impl DataBlock {
} }
_ => _ =>
{ {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
} }
} }
@@ -931,7 +941,8 @@ impl DataBlock {
} }
} }
}if !(bits.available() > 0) break;} }if !(bits.available() > 0) {break;}}
Ok(())
} }
/** /**
@@ -974,7 +985,7 @@ impl DataBlock {
result.append(text_char); result.append(text_char);
} }
} else { } else {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
break; break;
} }
@@ -1018,7 +1029,7 @@ impl DataBlock {
} }
_ => _ =>
{ {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
} }
} }
@@ -1037,13 +1048,13 @@ impl DataBlock {
} }
shift = 0; shift = 0;
} else { } else {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
break; break;
} }
_ => _ =>
{ {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
} }
} }
@@ -1051,7 +1062,8 @@ impl DataBlock {
} }
} }
}if !(bits.available() > 0) break;} }if !(bits.available() > 0) {break;}}
Ok(())
} }
/** /**
@@ -1111,7 +1123,7 @@ impl DataBlock {
// A - Z // A - Z
result.append((c_value + 51) as char); result.append((c_value + 51) as char);
} else { } else {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
break; break;
} }
@@ -1121,7 +1133,8 @@ impl DataBlock {
} }
} }
}if !(bits.available() > 0) break;} }if !(bits.available() > 0) {break;}}
Ok(())
} }
fn parse_two_bytes( first_byte: i32, second_byte: i32, result: &Vec<i32>) { fn parse_two_bytes( first_byte: i32, second_byte: i32, result: &Vec<i32>) {
@@ -1169,17 +1182,17 @@ impl DataBlock {
} }
} }
}if !(bits.available() > 0) break;} }if !(bits.available() > 0) {break;}}
} }
/** /**
* See ISO 16022:2006, 5.2.9 and Annex B, B.2 * See ISO 16022:2006, 5.2.9 and Annex B, B.2
*/ */
fn decode_base256_segment( bits: &BitSource, result: &ECIStringBuilder, byte_segments: &Collection<Vec<i8>>) -> /* throws FormatException */Result<Void, Rc<Exception>> { fn decode_base256_segment( bits: &BitSource, result: &ECIStringBuilder, byte_segments: &Collection<Vec<i8>>) -> Result<(), FormatException> {
// Figure out how long the Base 256 Segment is. // Figure out how long the Base 256 Segment is.
// position is 1-indexed // position is 1-indexed
let codeword_position: i32 = 1 + bits.get_byte_offset(); let codeword_position: i32 = 1 + bits.get_byte_offset();
let d1: i32 = ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 !!!check!!! post increment); let d1: i32 = ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 );
let mut count: i32; let mut count: i32;
if d1 == 0 { if d1 == 0 {
// Read the remainder of the symbol // Read the remainder of the symbol
@@ -1187,11 +1200,11 @@ impl DataBlock {
} else if d1 < 250 { } else if d1 < 250 {
count = d1; count = d1;
} else { } else {
count = 250 * (d1 - 249) + ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 !!!check!!! post increment); count = 250 * (d1 - 249) + ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 );
} }
// We're seeing NegativeArraySizeException errors from users. // We're seeing NegativeArraySizeException errors from users.
if count < 0 { if count < 0 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
let mut bytes: [i8; count] = [0; count]; let mut bytes: [i8; count] = [0; count];
{ {
@@ -1200,29 +1213,37 @@ impl DataBlock {
{ {
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2
if bits.available() < 8 { if bits.available() < 8 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
bytes[i] = ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 !!!check!!! post increment) as i8; bytes[i] = ::unrandomize255_state(&bits.read_bits(8), codeword_position += 1 ) as i8;
} }
i += 1; i += 1;
} }
} }
byte_segments.add(&bytes); byte_segments.add(&bytes);
result.append(String::new(&bytes, StandardCharsets::ISO_8859_1)); {
use encoding::{Encoding,DecoderTrap};
use encoding::all::ISO_8859_1;
result.append(ISO_8859_1.decode(&bytes, DecoderTrap::Strict).unwrap_or("".to_owned()))
// result.append(String::new(&bytes, StandardCharsets::ISO_8859_1));
}
Ok(())
} }
/** /**
* See ISO 16022:2007, 5.4.1 * See ISO 16022:2007, 5.4.1
*/ */
fn decode_e_c_i_segment( bits: &BitSource, result: &ECIStringBuilder) -> /* throws FormatException */Result<Void, Rc<Exception>> { fn decode_e_c_i_segment( bits: &BitSource, result: &ECIStringBuilder) -> Result<(),FormatException> {
if bits.available() < 8 { if bits.available() < 8 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
let c1: i32 = bits.read_bits(8); let c1: i32 = bits.read_bits(8);
if c1 <= 127 { if c1 <= 127 {
result.append_e_c_i(c1 - 1); result.append_e_c_i(c1 - 1);
} }
Ok(())
//currently we only support character set ECIs //currently we only support character set ECIs
/*} else { /*} else {
if (bits.available() < 8) { if (bits.available() < 8) {
@@ -1259,7 +1280,7 @@ impl DataBlock {
*/ */
pub struct Decoder { pub struct Decoder {
let rs_decoder: ReedSolomonDecoder; rs_decoder: ReedSolomonDecoder
} }
impl Decoder { impl Decoder {
@@ -1297,10 +1318,10 @@ impl Decoder {
// Read codewords // Read codewords
let codewords: Vec<i8> = parser.read_codewords(); let codewords: Vec<i8> = parser.read_codewords();
// Separate into data blocks // Separate into data blocks
let data_blocks: Vec<DataBlock> = DataBlock::get_data_blocks(&codewords, version); let data_blocks: Vec<DataBlock> = DataBlock::get_data_blocks(&codewords, &version);
// Count total number of data bytes // Count total number of data bytes
let total_bytes: i32 = 0; let total_bytes: i32 = 0;
for let db: DataBlock in data_blocks { for db in data_blocks {
total_bytes += db.get_num_data_codewords(); total_bytes += db.get_num_data_codewords();
} }
let result_bytes: [i8; total_bytes] = [0; total_bytes]; let result_bytes: [i8; total_bytes] = [0; total_bytes];
@@ -1342,7 +1363,7 @@ impl Decoder {
* @param numDataCodewords number of codewords that are data bytes * @param numDataCodewords number of codewords that are data bytes
* @throws ChecksumException if error correction fails * @throws ChecksumException if error correction fails
*/ */
fn correct_errors(&self, codeword_bytes: &Vec<i8>, num_data_codewords: i32) -> /* throws ChecksumException */Result<Void, Rc<Exception>> { fn correct_errors(&self, codeword_bytes: &Vec<i8>, num_data_codewords: i32) -> Result<(), ChecksumException> {
let num_codewords: i32 = codeword_bytes.len(); let num_codewords: i32 = codeword_bytes.len();
// First read into an array of ints // First read into an array of ints
let codewords_ints: [i32; num_codewords] = [0; num_codewords]; let codewords_ints: [i32; num_codewords] = [0; num_codewords];
@@ -1356,18 +1377,9 @@ impl Decoder {
} }
} }
let tryResult1 = 0;
'try1: loop {
{
self.rs_decoder.decode(&codewords_ints, codeword_bytes.len() - num_data_codewords); self.rs_decoder.decode(&codewords_ints, codeword_bytes.len() - num_data_codewords);
}
break 'try1
}
match tryResult1 {
catch ( ignored: &ReedSolomonException) {
throw ChecksumException::get_checksum_instance();
} 0 => break
}
// We don't care about errors in the error-correction codewords // We don't care about errors in the error-correction codewords
{ {
@@ -1379,6 +1391,7 @@ impl Decoder {
i += 1; i += 1;
} }
} }
Ok(())
} }
} }
@@ -1395,38 +1408,41 @@ impl Decoder {
const VERSIONS: Vec<Version> = ::build_versions(); const VERSIONS: Vec<Version> = ::build_versions();
pub struct Version { pub struct Version {
let version_number: i32; version_number: i32,
let symbol_size_rows: i32; symbol_size_rows: i32,
let symbol_size_columns: i32; symbol_size_columns: i32,
let data_region_size_rows: i32; data_region_size_rows: i32,
let data_region_size_columns: i32; data_region_size_columns: i32,
let ec_blocks: ECBlocks; ec_blocks: ECBlocks,
let total_codewords: i32; total_codewords: i32
} }
impl Version { impl Version {
fn new( version_number: i32, symbol_size_rows: i32, symbol_size_columns: i32, data_region_size_rows: i32, data_region_size_columns: i32, ec_blocks: &ECBlocks) -> Version { fn new( version_number: i32, symbol_size_rows: i32, symbol_size_columns: i32, data_region_size_rows: i32, data_region_size_columns: i32, ec_blocks: &ECBlocks) -> Self {
let .versionNumber = version_number; let new_v : Self;
let .symbolSizeRows = symbol_size_rows; new_v .versionNumber = version_number;
let .symbolSizeColumns = symbol_size_columns; new_v .symbolSizeRows = symbol_size_rows;
let .dataRegionSizeRows = data_region_size_rows; new_v .symbolSizeColumns = symbol_size_columns;
let .dataRegionSizeColumns = data_region_size_columns; new_v .dataRegionSizeRows = data_region_size_rows;
let .ecBlocks = ec_blocks; new_v .dataRegionSizeColumns = data_region_size_columns;
new_v .ecBlocks = ec_blocks;
// Calculate the total number of codewords // Calculate the total number of codewords
let mut total: i32 = 0; let mut total: i32 = 0;
let ec_codewords: i32 = ec_blocks.get_e_c_codewords(); let ec_codewords: i32 = ec_blocks.get_e_c_codewords();
let ecb_array: Vec<ECB> = ec_blocks.get_e_c_blocks(); let ecb_array: Vec<ECB> = ec_blocks.get_e_c_blocks();
for let ec_block: ECB in ecb_array { for ec_block in ecb_array {
total += ec_block.get_count() * (ec_block.get_data_codewords() + ec_codewords); total += ec_block.get_count() * (ec_block.get_data_codewords() + ec_codewords);
} }
let .totalCodewords = total; new_v .totalCodewords = total;
new_v
} }
pub fn get_version_number(&self) -> i32 { pub fn get_version_number(&self) -> i32 {
@@ -1467,14 +1483,29 @@ impl Version {
*/ */
pub fn get_version_for_dimensions( num_rows: i32, num_columns: i32) -> /* throws FormatException */Result<Version, Rc<Exception>> { pub fn get_version_for_dimensions( num_rows: i32, num_columns: i32) -> /* throws FormatException */Result<Version, Rc<Exception>> {
if (num_rows & 0x01) != 0 || (num_columns & 0x01) != 0 { if (num_rows & 0x01) != 0 || (num_columns & 0x01) != 0 {
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
} }
for let version: Version in VERSIONS { for version in VERSIONS {
if version.symbolSizeRows == num_rows && version.symbolSizeColumns == num_columns { if version.symbolSizeRows == num_rows && version.symbolSizeColumns == num_columns {
return Ok(version); return Ok(version);
} }
} }
throw FormatException::get_format_instance(); return Err( FormatException::get_format_instance());
}
pub fn to_string(&self) -> String {
return String::value_of(self.version_number);
}
/**
* See ISO 16022:2006 5.5.1 Table 7
*/
fn build_versions() -> Vec<Version> {
return vec![Version::new(1, 10, 10, 8, 8, &ECBlocks::new_simple(5, &ECB::new(1, 3))), Version::new(2, 12, 12, 10, 10, &ECBlocks::new_simple(7, &ECB::new(1, 5))), Version::new(3, 14, 14, 12, 12, &ECBlocks::new_simple(10, &ECB::new(1, 8))), Version::new(4, 16, 16, 14, 14, &ECBlocks::new_simple(12, &ECB::new(1, 12))), Version::new(5, 18, 18, 16, 16,& ECBlocks::new_simple(14, &ECB::new(1, 18))), Version::new(6, 20, 20, 18, 18, &ECBlocks::new_simple(18, &ECB::new(1, 22))), Version::new(7, 22, 22, 20, 20, &ECBlocks::new_simple(20, &ECB::new(1, 30))), Version::new(8, 24, 24, 22, 22,& ECBlocks::new_simple(24, &ECB::new(1, 36))), Version::new(9, 26, 26, 24, 24,& ECBlocks::new_simple(28, &ECB::new(1, 44))), Version::new(10, 32, 32, 14, 14,& ECBlocks::new_simple(36, &ECB::new(1, 62))), Version::new(11, 36, 36, 16, 16, &ECBlocks::new_simple(42,& ECB::new(1, 86))), Version::new(12, 40, 40, 18, 18, &ECBlocks::new_simple(48, &ECB::new(1, 114))), Version::new(13, 44, 44, 20, 20,& ECBlocks::new_simple(56,& ECB::new(1, 144))), Version::new(14, 48, 48, 22, 22,& ECBlocks::new_simple(68,& ECB::new(1, 174))), Version::new(15, 52, 52, 24, 24,& ECBlocks::new_simple(42, &ECB::new(2, 102))), Version::new(16, 64, 64, 14, 14,& ECBlocks::new_simple(56, &ECB::new(2, 140))), Version::new(17, 72, 72, 16, 16, &ECBlocks::new_simple(36, &ECB::new(4, 92))), Version::new(18, 80, 80, 18, 18,& ECBlocks::new_simple(48, &ECB::new(4, 114))), Version::new(19, 88, 88, 20, 20,& ECBlocks::new_simple(56, &ECB::new(4, 144))), Version::new(20, 96, 96, 22, 22, &ECBlocks::new_simple(68, &ECB::new(4, 174))), Version::new(21, 104, 104, 24, 24, &ECBlocks::new_simple(56, &ECB::new(6, 136))), Version::new(22, 120, 120, 18, 18, &ECBlocks::new_simple(68, &ECB::new(6, 175))), Version::new(23, 132, 132, 20, 20, &ECBlocks::new_simple(62, &ECB::new(8, 163))), Version::new(24, 144, 144, 22, 22, &ECBlocks::new(62, &ECB::new(8, 156), &ECB::new(2, 155))), Version::new(25, 8, 18, 6, 16, &ECBlocks::new_simple(7, &ECB::new(1, 5))), Version::new(26, 8, 32, 6, 14,& ECBlocks::new_simple(11, &ECB::new(1, 10))), Version::new(27, 12, 26, 10, 24,& ECBlocks::new_simple(14, &ECB::new(1, 16))), Version::new(28, 12, 36, 10, 16,& ECBlocks::new_simple(18, &ECB::new(1, 22))), Version::new(29, 16, 36, 14, 16, &ECBlocks::new_simple(24,& ECB::new(1, 32))), Version::new(30, 16, 48, 14, 22, &ECBlocks::new_simple(28, &ECB::new(1, 49))), // ISO 21471:2020 (DMRE) 5.5.1 Table 7
Version::new(31, 8, 48, 6, 22,& ECBlocks::new_simple(15, &ECB::new(1, 18))), Version::new(32, 8, 64, 6, 14,& ECBlocks::new_simple(18, &ECB::new(1, 24))), Version::new(33, 8, 80, 6, 18, &ECBlocks::new_simple(22, &ECB::new(1, 32))), Version::new(34, 8, 96, 6, 22, &ECBlocks::new_simple(28, &ECB::new(1, 38))), Version::new(35, 8, 120, 6, 18, &ECBlocks::new_simple(32, &ECB::new(1, 49))), Version::new(36, 8, 144, 6, 22, &ECBlocks::new_simple(36, &ECB::new(1, 63))), Version::new(37, 12, 64, 10, 14, &ECBlocks::new_simple(27, &ECB::new(1, 43))), Version::new(38, 12, 88, 10, 20, &ECBlocks::new_simple(36, &ECB::new(1, 64))), Version::new(39, 16, 64, 14, 14,& ECBlocks::new_simple(36, &ECB::new(1, 62))), Version::new(40, 20, 36, 18, 16,& ECBlocks::new_simple(28, &ECB::new(1, 44))), Version::new(41, 20, 44, 18, 20,& ECBlocks::new_simple(34, &ECB::new(1, 56))), Version::new(42, 20, 64, 18, 14,& ECBlocks::new_simple(42,& ECB::new(1, 84))), Version::new(43, 22, 48, 20, 22, &ECBlocks::new_simple(38,& ECB::new(1, 72))), Version::new(44, 24, 48, 22, 22, &ECBlocks::new_simple(41, &ECB::new(1, 80))), Version::new(45, 24, 64, 22, 14, &ECBlocks::new_simple(46, &ECB::new(1, 108))), Version::new(46, 26, 40, 24, 18, &ECBlocks::new_simple(38, &ECB::new(1, 70))), Version::new(47, 26, 48, 24, 22, &ECBlocks::new_simple(42, &ECB::new(1, 90))), Version::new(48, 26, 64, 24, 14, &ECBlocks::new_simple(50, &ECB::new(1, 118))), ]
;
}
} }
/** /**
@@ -1485,23 +1516,26 @@ impl Version {
*/ */
struct ECBlocks { struct ECBlocks {
let ec_codewords: i32; ec_codewords: i32,
let ec_blocks: Vec<ECB>; ec_blocks: Vec<ECB>,
} }
impl ECBlocks { impl ECBlocks {
fn new( ec_codewords: i32, ec_blocks: &ECB) -> ECBlocks { fn new_simple( ec_codewords: i32, ec_blocks: &ECB) -> Self {
let .ecCodewords = ec_codewords; Self{
let .ecBlocks = : vec![ECB; 1] = vec![ec_blocks, ] ec_codewords: ec_codewords,
; ec_blocks: vec![ec_blocks, ]
}
} }
fn new( ec_codewords: i32, ec_blocks1: &ECB, ec_blocks2: &ECB) -> ECBlocks { fn new( ec_codewords: i32, ec_blocks1: &ECB, ec_blocks2: &ECB) -> ECBlocks {
let .ecCodewords = ec_codewords; Self{
let .ecBlocks = : vec![ECB; 2] = vec![ec_blocks1, ec_blocks2, ] ec_codewords: ec_codewords,
; ec_blocks: vec![ec_blocks1, ec_blocks2, ]
}
} }
fn get_e_c_codewords(&self) -> i32 { fn get_e_c_codewords(&self) -> i32 {
@@ -1521,16 +1555,19 @@ impl Version {
*/ */
struct ECB { struct ECB {
let count: i32; count: i32,
let data_codewords: i32; data_codewords: i32
} }
impl ECB { impl ECB {
fn new( count: i32, data_codewords: i32) -> ECB { fn new( count: i32, data_codewords: i32) -> Self {
let .count = count; Self {
let .dataCodewords = data_codewords;
count,
data_codewords
}
} }
fn get_count(&self) -> i32 { fn get_count(&self) -> i32 {
@@ -1541,19 +1578,3 @@ impl Version {
return self.data_codewords; return self.data_codewords;
} }
} }
pub fn to_string(&self) -> String {
return String::value_of(self.version_number);
}
/**
* See ISO 16022:2006 5.5.1 Table 7
*/
fn build_versions() -> Vec<Version> {
return : vec![Version; 48] = vec![Version::new(1, 10, 10, 8, 8, ECBlocks::new(5, ECB::new(1, 3))), Version::new(2, 12, 12, 10, 10, ECBlocks::new(7, ECB::new(1, 5))), Version::new(3, 14, 14, 12, 12, ECBlocks::new(10, ECB::new(1, 8))), Version::new(4, 16, 16, 14, 14, ECBlocks::new(12, ECB::new(1, 12))), Version::new(5, 18, 18, 16, 16, ECBlocks::new(14, ECB::new(1, 18))), Version::new(6, 20, 20, 18, 18, ECBlocks::new(18, ECB::new(1, 22))), Version::new(7, 22, 22, 20, 20, ECBlocks::new(20, ECB::new(1, 30))), Version::new(8, 24, 24, 22, 22, ECBlocks::new(24, ECB::new(1, 36))), Version::new(9, 26, 26, 24, 24, ECBlocks::new(28, ECB::new(1, 44))), Version::new(10, 32, 32, 14, 14, ECBlocks::new(36, ECB::new(1, 62))), Version::new(11, 36, 36, 16, 16, ECBlocks::new(42, ECB::new(1, 86))), Version::new(12, 40, 40, 18, 18, ECBlocks::new(48, ECB::new(1, 114))), Version::new(13, 44, 44, 20, 20, ECBlocks::new(56, ECB::new(1, 144))), Version::new(14, 48, 48, 22, 22, ECBlocks::new(68, ECB::new(1, 174))), Version::new(15, 52, 52, 24, 24, ECBlocks::new(42, ECB::new(2, 102))), Version::new(16, 64, 64, 14, 14, ECBlocks::new(56, ECB::new(2, 140))), Version::new(17, 72, 72, 16, 16, ECBlocks::new(36, ECB::new(4, 92))), Version::new(18, 80, 80, 18, 18, ECBlocks::new(48, ECB::new(4, 114))), Version::new(19, 88, 88, 20, 20, ECBlocks::new(56, ECB::new(4, 144))), Version::new(20, 96, 96, 22, 22, ECBlocks::new(68, ECB::new(4, 174))), Version::new(21, 104, 104, 24, 24, ECBlocks::new(56, ECB::new(6, 136))), Version::new(22, 120, 120, 18, 18, ECBlocks::new(68, ECB::new(6, 175))), Version::new(23, 132, 132, 20, 20, ECBlocks::new(62, ECB::new(8, 163))), Version::new(24, 144, 144, 22, 22, ECBlocks::new(62, ECB::new(8, 156), ECB::new(2, 155))), Version::new(25, 8, 18, 6, 16, ECBlocks::new(7, ECB::new(1, 5))), Version::new(26, 8, 32, 6, 14, ECBlocks::new(11, ECB::new(1, 10))), Version::new(27, 12, 26, 10, 24, ECBlocks::new(14, ECB::new(1, 16))), Version::new(28, 12, 36, 10, 16, ECBlocks::new(18, ECB::new(1, 22))), Version::new(29, 16, 36, 14, 16, ECBlocks::new(24, ECB::new(1, 32))), Version::new(30, 16, 48, 14, 22, ECBlocks::new(28, ECB::new(1, 49))), // ISO 21471:2020 (DMRE) 5.5.1 Table 7
Version::new(31, 8, 48, 6, 22, ECBlocks::new(15, ECB::new(1, 18))), Version::new(32, 8, 64, 6, 14, ECBlocks::new(18, ECB::new(1, 24))), Version::new(33, 8, 80, 6, 18, ECBlocks::new(22, ECB::new(1, 32))), Version::new(34, 8, 96, 6, 22, ECBlocks::new(28, ECB::new(1, 38))), Version::new(35, 8, 120, 6, 18, ECBlocks::new(32, ECB::new(1, 49))), Version::new(36, 8, 144, 6, 22, ECBlocks::new(36, ECB::new(1, 63))), Version::new(37, 12, 64, 10, 14, ECBlocks::new(27, ECB::new(1, 43))), Version::new(38, 12, 88, 10, 20, ECBlocks::new(36, ECB::new(1, 64))), Version::new(39, 16, 64, 14, 14, ECBlocks::new(36, ECB::new(1, 62))), Version::new(40, 20, 36, 18, 16, ECBlocks::new(28, ECB::new(1, 44))), Version::new(41, 20, 44, 18, 20, ECBlocks::new(34, ECB::new(1, 56))), Version::new(42, 20, 64, 18, 14, ECBlocks::new(42, ECB::new(1, 84))), Version::new(43, 22, 48, 20, 22, ECBlocks::new(38, ECB::new(1, 72))), Version::new(44, 24, 48, 22, 22, ECBlocks::new(41, ECB::new(1, 80))), Version::new(45, 24, 64, 22, 14, ECBlocks::new(46, ECB::new(1, 108))), Version::new(46, 26, 40, 24, 18, ECBlocks::new(38, ECB::new(1, 70))), Version::new(47, 26, 48, 24, 22, ECBlocks::new(42, ECB::new(1, 90))), Version::new(48, 26, 64, 24, 14, ECBlocks::new(50, ECB::new(1, 118))), ]
;
}
}

View File

@@ -11,16 +11,19 @@ use crate::common::detector::WhiteRectangleDetector;
*/ */
pub struct Detector { pub struct Detector {
let image: BitMatrix; image: BitMatrix,
let rectangle_detector: WhiteRectangleDetector; rectangle_detector: WhiteRectangleDetector
} }
impl Detector { impl Detector {
pub fn new( image: &BitMatrix) -> Detector throws NotFoundException { pub fn new( image: &BitMatrix) -> Result<Self, NotFoundException> {
let .image = image; let d : Self;
rectangle_detector = WhiteRectangleDetector::new(image); d .image = image;
d.rectangle_detector = WhiteRectangleDetector::new(image, None, None, None);
Ok(d)
} }
/** /**
@@ -29,21 +32,21 @@ impl Detector {
* @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code * @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code
* @throws NotFoundException if no Data Matrix Code can be found * @throws NotFoundException if no Data Matrix Code can be found
*/ */
pub fn detect(&self) -> /* throws NotFoundException */Result<DetectorResult, Rc<Exception>> { pub fn detect(&self) -> Result<DetectorResult, NotFoundException> {
let corner_points: Vec<ResultPoint> = self.rectangle_detector.detect(); let corner_points: Vec<ResultPoint> = self.rectangle_detector.detect();
let mut points: Vec<ResultPoint> = self.detect_solid1(corner_points); let mut points: Vec<ResultPoint> = self.detect_solid1(&corner_points);
points = self.detect_solid2(points); points = self.detect_solid2(points?);
points[3] = self.correct_top_right(points); points[3] = self.correct_top_right(points?);
if points[3] == null { if points[3] == null {
throw NotFoundException::get_not_found_instance(); return Err( NotFoundException::get_not_found_instance());
} }
points = self.shift_to_module_center(points); points = self.shift_to_module_center(points?);
let top_left: ResultPoint = points[0]; let top_left: ResultPoint = points[0];
let bottom_left: ResultPoint = points[1]; let bottom_left: ResultPoint = points[1];
let bottom_right: ResultPoint = points[2]; let bottom_right: ResultPoint = points[2];
let top_right: ResultPoint = points[3]; let top_right: ResultPoint = points[3];
let dimension_top: i32 = self.transitions_between(top_left, top_right) + 1; let dimension_top: i32 = self.transitions_between(&top_left, &top_right) + 1;
let dimension_right: i32 = self.transitions_between(bottom_right, top_right) + 1; let dimension_right: i32 = self.transitions_between(&bottom_right, &top_right) + 1;
if (dimension_top & 0x01) == 1 { if (dimension_top & 0x01) == 1 {
dimension_top += 1; dimension_top += 1;
} }
@@ -55,7 +58,7 @@ impl Detector {
dimension_top = dimension_right = Math::max(dimension_top, dimension_right); dimension_top = dimension_right = Math::max(dimension_top, dimension_right);
} }
let bits: BitMatrix = ::sample_grid(self.image, top_left, bottom_left, bottom_right, top_right, dimension_top, dimension_right); let bits: BitMatrix = ::sample_grid(self.image, top_left, bottom_left, bottom_right, top_right, dimension_top, dimension_right);
return Ok(DetectorResult::new(bits, : vec![ResultPoint; 4] = vec![top_left, bottom_left, bottom_right, top_right, ] return Ok(DetectorResult::new(bits, vec![top_left, bottom_left, bottom_right, top_right, ]
)); ));
} }
@@ -91,10 +94,10 @@ impl Detector {
let point_b: ResultPoint = corner_points[1]; let point_b: ResultPoint = corner_points[1];
let point_c: ResultPoint = corner_points[3]; let point_c: ResultPoint = corner_points[3];
let point_d: ResultPoint = corner_points[2]; let point_d: ResultPoint = corner_points[2];
let tr_a_b: i32 = self.transitions_between(point_a, point_b); let tr_a_b: i32 = self.transitions_between(&point_a, &point_b);
let tr_b_c: i32 = self.transitions_between(point_b, point_c); let tr_b_c: i32 = self.transitions_between(&point_b, &point_c);
let tr_c_d: i32 = self.transitions_between(point_c, point_d); let tr_c_d: i32 = self.transitions_between(&point_c, &point_d);
let tr_d_a: i32 = self.transitions_between(point_d, point_a); let tr_d_a: i32 = self.transitions_between(&point_d, &point_a);
// 0..3 // 0..3
// : : // : :
// 1--2 // 1--2
@@ -137,11 +140,11 @@ impl Detector {
let point_d: ResultPoint = points[3]; let point_d: ResultPoint = points[3];
// Transition detection on the edge is not stable. // Transition detection on the edge is not stable.
// To safely detect, shift the points to the module center. // To safely detect, shift the points to the module center.
let tr: i32 = self.transitions_between(point_a, point_d); let tr: i32 = self.transitions_between(&point_a, &point_d);
let point_bs: ResultPoint = ::shift_point(point_b, point_c, (tr + 1) * 4); let point_bs: ResultPoint = ::shift_point(point_b, point_c, (tr + 1) * 4);
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr + 1) * 4); let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr + 1) * 4);
let tr_b_a: i32 = self.transitions_between(point_bs, point_a); let tr_b_a: i32 = self.transitions_between(&point_bs, &point_a);
let tr_c_d: i32 = self.transitions_between(point_cs, point_d); let tr_c_d: i32 = self.transitions_between(&point_cs, &point_d);
// 1--2 // 1--2
if tr_b_a < tr_c_d { if tr_b_a < tr_c_d {
// solid sides: A-B-C // solid sides: A-B-C
@@ -171,25 +174,25 @@ impl Detector {
let point_c: ResultPoint = points[2]; let point_c: ResultPoint = points[2];
let point_d: ResultPoint = points[3]; let point_d: ResultPoint = points[3];
// shift points for safe transition detection. // shift points for safe transition detection.
let tr_top: i32 = self.transitions_between(point_a, point_d); let tr_top: i32 = self.transitions_between(&point_a, &point_d);
let tr_right: i32 = self.transitions_between(point_b, point_d); let tr_right: i32 = self.transitions_between(&point_b, &point_d);
let point_as: ResultPoint = ::shift_point(point_a, point_b, (tr_right + 1) * 4); let point_as: ResultPoint = ::shift_point(point_a, point_b, (tr_right + 1) * 4);
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr_top + 1) * 4); let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr_top + 1) * 4);
tr_top = self.transitions_between(point_as, point_d); tr_top = self.transitions_between(&point_as, &point_d);
tr_right = self.transitions_between(point_cs, point_d); tr_right = self.transitions_between(&point_cs, &point_d);
let candidate1: ResultPoint = ResultPoint::new(point_d.get_x() + (point_c.get_x() - point_b.get_x()) / (tr_top + 1), point_d.get_y() + (point_c.get_y() - point_b.get_y()) / (tr_top + 1)); let candidate1: ResultPoint = ResultPoint::new(point_d.get_x() + (point_c.get_x() - point_b.get_x()) / (tr_top + 1), point_d.get_y() + (point_c.get_y() - point_b.get_y()) / (tr_top + 1));
let candidate2: ResultPoint = ResultPoint::new(point_d.get_x() + (point_a.get_x() - point_b.get_x()) / (tr_right + 1), point_d.get_y() + (point_a.get_y() - point_b.get_y()) / (tr_right + 1)); let candidate2: ResultPoint = ResultPoint::new(point_d.get_x() + (point_a.get_x() - point_b.get_x()) / (tr_right + 1), point_d.get_y() + (point_a.get_y() - point_b.get_y()) / (tr_right + 1));
if !self.is_valid(candidate1) { if !self.is_valid(&candidate1) {
if self.is_valid(candidate2) { if self.is_valid(&candidate2) {
return candidate2; return candidate2;
} }
return null; return null;
} }
if !self.is_valid(candidate2) { if !self.is_valid(&candidate2) {
return candidate1; return candidate1;
} }
let sumc1: i32 = self.transitions_between(point_as, candidate1) + self.transitions_between(point_cs, candidate1); let sumc1: i32 = self.transitions_between(&point_as, &candidate1) + self.transitions_between(&point_cs, &candidate1);
let sumc2: i32 = self.transitions_between(point_as, candidate2) + self.transitions_between(point_cs, candidate2); let sumc2: i32 = self.transitions_between(&point_as, &candidate2) + self.transitions_between(&point_cs, &candidate2);
if sumc1 > sumc2 { if sumc1 > sumc2 {
return candidate1; return candidate1;
} else { } else {
@@ -209,14 +212,14 @@ impl Detector {
let point_c: ResultPoint = points[2]; let point_c: ResultPoint = points[2];
let point_d: ResultPoint = points[3]; let point_d: ResultPoint = points[3];
// calculate pseudo dimensions // calculate pseudo dimensions
let dim_h: i32 = self.transitions_between(point_a, point_d) + 1; let dim_h: i32 = self.transitions_between(&point_a, &point_d) + 1;
let dim_v: i32 = self.transitions_between(point_c, point_d) + 1; let dim_v: i32 = self.transitions_between(&point_c, &point_d) + 1;
// shift points for safe dimension detection // shift points for safe dimension detection
let point_as: ResultPoint = ::shift_point(point_a, point_b, dim_v * 4); let point_as: ResultPoint = ::shift_point(point_a, point_b, dim_v * 4);
let point_cs: ResultPoint = ::shift_point(point_c, point_b, dim_h * 4); let point_cs: ResultPoint = ::shift_point(point_c, point_b, dim_h * 4);
// calculate more precise dimensions // calculate more precise dimensions
dim_h = self.transitions_between(point_as, point_d) + 1; dim_h = self.transitions_between(&point_as, &point_d) + 1;
dim_v = self.transitions_between(point_cs, point_d) + 1; dim_v = self.transitions_between(&point_cs, &point_d) + 1;
if (dim_h & 0x01) == 1 { if (dim_h & 0x01) == 1 {
dim_h += 1; dim_h += 1;
} }
@@ -242,7 +245,7 @@ impl Detector {
point_cs = ::shift_point(point_cs, point_b, dim_h * 4); point_cs = ::shift_point(point_cs, point_b, dim_h * 4);
point_ds = ::shift_point(point_d, point_c, dim_v * 4); point_ds = ::shift_point(point_d, point_c, dim_v * 4);
point_ds = ::shift_point(point_ds, point_a, dim_h * 4); point_ds = ::shift_point(point_ds, point_a, dim_h * 4);
return : vec![ResultPoint; 4] = vec![point_as, point_bs, point_cs, point_ds, ] return vec![point_as, point_bs, point_cs, point_ds, ]
; ;
} }
@@ -252,7 +255,7 @@ impl Detector {
fn sample_grid( image: &BitMatrix, top_left: &ResultPoint, bottom_left: &ResultPoint, bottom_right: &ResultPoint, top_right: &ResultPoint, dimension_x: i32, dimension_y: i32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> { fn sample_grid( image: &BitMatrix, top_left: &ResultPoint, bottom_left: &ResultPoint, bottom_right: &ResultPoint, top_right: &ResultPoint, dimension_x: i32, dimension_y: i32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
let sampler: GridSampler = GridSampler::get_instance(); let sampler: GridSampler = GridSampler::get_instance();
return Ok(sampler.sample_grid(image, dimension_x, dimension_y, 0.5f, 0.5f, dimension_x - 0.5f, 0.5f, dimension_x - 0.5f, dimension_y - 0.5f, 0.5f, dimension_y - 0.5f, &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())); return Ok(sampler.sample_grid(image, dimension_x, dimension_y, 0.5f32, 0.5f32, dimension_x - 0.5f32, 0.5f32, dimension_x - 0.5f32, dimension_y - 0.5f32, 0.5f32, dimension_y - 0.5f32, &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()));
} }
/** /**
@@ -281,7 +284,8 @@ impl Detector {
let mut transitions: i32 = 0; let mut transitions: i32 = 0;
let in_black: bool = self.image.get( if steep { from_y } else { from_x }, if steep { from_x } else { from_y }); let in_black: bool = self.image.get( if steep { from_y } else { from_x }, if steep { from_x } else { from_y });
{ {
let mut x: i32 = from_x, let mut y: i32 = from_y; let mut x: i32 = from_x;
let mut y: i32 = from_y;
while x != to_x { while x != to_x {
{ {
let is_black: bool = self.image.get( if steep { y } else { x }, if steep { x } else { y }); let is_black: bool = self.image.get( if steep { y } else { x }, if steep { x } else { y });

File diff suppressed because it is too large Load Diff