removed for rebuild

This commit is contained in:
Henry Schimke
2022-08-20 11:55:57 -05:00
parent 35196da8aa
commit f3898179fa
2788 changed files with 0 additions and 98925 deletions
-285
View File
@@ -1,285 +0,0 @@
pub mod decoder;
pub mod detector;
pub mod encoder;
use crate::aztec::decoder::Decoder;
use crate::aztec::detector::Detector;
use crate::common::{BitMatrix, DecoderResult, DetectorResult};
use crate::{
BarcodeFormat, BinaryBitmap, DecodeHintType, FormatException, NotFoundException, Reader,
Result, ResultMetadataType, ResultPoint, ResultPointCallback,
};
use crate::{
BarcodeFormat, EncodeHintType, Reader, ReaderException, ResultPoint, Writer, WriterException,
};
use crate::aztec::encoder::{AztecCode, Encoder};
// AztecDetectorResult.java
/**
* <p>Extends {@link DetectorResult} with more information specific to the Aztec format,
* like the number of layers and whether it's compact.</p>
*
* @author Sean Owen
*/
pub struct AztecDetectorResult {
//super: DetectorResult;
compact: bool,
nb_datablocks: i32,
nb_layers: i32,
bits: BitMatrix,
points: Vec<ResultPoint>,
}
impl DetectorResult for AztecDetectorResult {
fn get_bits(&self) -> BitMatrix {
return self.bits;
}
fn get_points(&self) -> Vec<ResultPoint> {
return self.points;
}
}
impl AztecDetectorResult {
pub fn new(
bits: &BitMatrix,
points: &Vec<ResultPoint>,
compact: bool,
nb_datablocks: i32,
nb_layers: i32,
) -> Self {
Self {
compact: compact,
nb_datablocks: nd_datablocks,
nb_layers: nb_layers,
bits: bits,
points: points,
}
}
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
/**
* 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
*/
/*fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, FormatException */Result<Result, Rc<Exception>> {
return Ok(self.decode(image, null));
}*/
fn decode(
&self,
image: &BinaryBitmap,
hints: &Map<DecodeHintType, _>,
) -> Result<Result, ReaderException> {
let not_found_exception: NotFoundException = null;
let format_exception: FormatException = null;
let detector: Detector = Detector::new(&image.get_black_matrix());
let mut points: Vec<ResultPoint> = null;
let decoder_result: DecoderResult = null;
let detector_result: AztecDetectorResult = detector.detect(Some(false))?;
points = detector_result.get_points()?;
decoder_result = Decoder::new().decode(detector_result);
/*
let tryResult1 = 0;
'try1: loop {
{
let detector_result: AztecDetectorResult = detector.detect(Some(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 point 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<Vec<i8>> = decoder_result.get_byte_segments();
if byte_segments != null {
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
}
let ec_level: String = decoder_result.get_e_c_level();
if ec_level != null {
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
}
result.put_metadata(
ResultMetadataType::SYMBOLOGY_IDENTIFIER,
format!("]z{}", decoder_result.get_symbology_modifier()),
);
return Ok(result);
}
fn reset(&self) {
// do nothing
}
}
// AztecWriter.java
/**
* Renders an Aztec code as a {@link BitMatrix}.
*/
pub struct AztecWriter {}
impl Writer for AztecWriter {
fn encode(
&self,
contents: &String,
format: &BarcodeFormat,
width: i32,
height: i32,
hints: Option<&HashMap<EncodeHintType, _>>,
) -> 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 {
return Err( 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);
}*/
}
impl AztecWriter {
fn render_result(code: &AztecCode, width: i32, height: i32) -> BitMatrix {
let input: BitMatrix = code.get_matrix();
if input == null {
return Err(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;
}
}
-548
View File
@@ -1,548 +0,0 @@
use crate::aztec::AztecDetectorResult;
use crate::common::reedsolomon::{GenericGF, ReedSolomonDecoder, ReedSolomonException};
use crate::common::{BitMatrix, CharacterSetECI, DecoderResult};
use create::FormatException;
/**
* <p>The main class which implements Aztec Code decoding -- as opposed to locating and extracting
* the Aztec Code from an image.</p>
*
* @author David Olivier
*/
const UPPER_TABLE: vec![Vec<String>; 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<String>; 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<String>; 32] = vec![
"CTRL_PS", " ", "\u{0001}", "\u{0002}", "\u{0003}", "\u{0004}", "\u{0005}", "\u{0006}",
"\u{0007}", "\u{000b}", "\t", "\n", "\u{000d}", "\u{000f}", "\r", "\u{0021}", "\u{0022}",
"\u{0023}", "\u{0024}", "\u{0025}", "@", "\\", "^", "_", "`", "|", "~", "\u{00b1}", "CTRL_LL",
"CTRL_UL", "CTRL_PL", "CTRL_BS",
];
const PUNCT_TABLE: vec![Vec<String>; 32] = vec![
"FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*",
"+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL",
];
const DIGIT_TABLE: vec![Vec<String>; 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 {
ddata: AztecDetectorResult,
}
enum Table {
UPPER(),
LOWER(),
MIXED(),
DIGIT(),
PUNCT(),
BINARY(),
}
impl Decoder {
pub fn decode(
&self,
detector_result: &AztecDetectorResult,
) -> Result<DecoderResult, FormatException> {
self.ddata = detector_result;
let matrix: BitMatrix = detector_result.get_bits();
let rawbits: Vec<bool> = self.extract_bits(&matrix);
let corrected_bits: CorrectedBitsResult = self.correct_bits(&rawbits);
let raw_bytes: Vec<i8> = ::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),
None,
None,
None,
);
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<bool>) -> Result<String, Rc<Exception>> {
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<bool>) -> Result<String, Rc<Exception>> {
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;
result.append(&decoded_bytes.to_string(&encoding.name()));
decoded_bytes.reset();
match n {
0 => {
// translate FNC1 as ASCII 29
result.append(29 as char);
break;
}
7 => {
// FLG(7) is reserved and illegal
return Err(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) > 0 {
let next_digit: i32 = ::read_code(&corrected_bits, index, 4);
index += 4;
if next_digit < 2 || next_digit > 11 {
// Not a decimal digit
return Err(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 {
return Err(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<i8> = 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;
}
}
}
result.append(&decoded_bytes.to_string(&encoding.name()));
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.
return Err(IllegalStateException::new("Bad table"));
}
}
}
/**
* <p>Performs RS error correction on an array of bits.</p>
*
* @return the corrected array
* @throws FormatException if the input contains too many errors
*/
fn correct_bits(&self, rawbits: &Vec<bool>) -> Result<CorrectedBitsResult, FormatException> {
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 {
return Err(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;
let rs_decoder: ReedSolomonDecoder = ReedSolomonDecoder::new(gf)?;
rs_decoder.decode(&data_words, num_codewords - num_data_codewords);
// 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 {
return Err(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] = (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<bool> {
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 <low, low> (not including alignment lines)
let low: i32 = i * 2;
// The bottom-right most point of this layer is <high, high> (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<bool>, 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<bool>, 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<bool>) -> Vec<i8> {
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;
}
}
struct CorrectedBitsResult {
correct_bits: Vec<bool>,
ec_level: i32,
}
impl CorrectedBitsResult {
fn new(correct_bits: &Vec<bool>, ec_level: i32) -> Self {
Self {
correct_bits: correct_bits,
ec_level: ec_level,
}
}
}
-670
View File
@@ -1,670 +0,0 @@
use crate::aztec::AztecDetectorResult;
use crate::common::detector::{MathUtils, WhiteRectangleDetector};
use crate::common::reedsolomon::{GenericGF, ReedSolomonDecoder, ReedSolomonException};
use crate::common::{BitMatrix, GridSampler};
use crate::{NotFoundException, ResultPoint};
/**
* 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<i32>; 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 {
image: BitMatrix,
compact: bool,
nb_layers: i32,
nb_data_blocks: i32,
nb_center_layers: i32,
shift: i32,
}
impl Detector {
pub fn new(image: &BitMatrix) -> Self {
let new_d: Self;
new_d.image = image;
new_d
}
/**
* 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: Option<bool>,
) -> Result<AztecDetectorResult, NotFoundException> {
// 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<ResultPoint> = self.get_bulls_eye_corners(&p_center);
if is_mirror.unwrap_or(false) {
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<ResultPoint> = 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<ResultPoint>,
) -> Result<(), NotFoundException> {
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])
{
return Err(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<i32>; 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;
}
Ok(())
}
fn get_rotation(sides: &Vec<i32>, length: i32) -> Result<i32, NotFoundException> {
// 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 side 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;
}
}
return Err(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,
) -> Result<i32, Rc<Exception>> {
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(&parameter_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) -> Result<Vec<ResultPoint>, Rc<Exception>> {
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 {
return Err(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.5f32, pina.get_y() - 0.5f32);
let pinbx: ResultPoint = ResultPoint::new(pinb.get_x() + 0.5f32, pinb.get_y() + 0.5f32);
let pincx: ResultPoint = ResultPoint::new(pinc.get_x() - 0.5f32, pinc.get_y() + 0.5f32);
let pindx: ResultPoint = ResultPoint::new(pind.get_x() - 0.5f32, pind.get_y() - 0.5f32);
// just outside the bull's eye.
return Ok(::expand_square(
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;
let corner_points_detector = WhiteRectangleDetector::new(&self.image, None, None, None);
if corner_points_detector.is_ok() {
let corner_points: Vec<ResultPoint> = corner_points_detector.detect();
point_a = corner_points[0];
point_b = corner_points[1];
point_c = corner_points[2];
point_d = corner_points[3];
} else {
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();
}
//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.0f32,
);
let mut cy: i32 = MathUtils::round(
(point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f32,
);
// in order to compute a more accurate center.
let tryResult1 = 0;
let corner_points_wrd =
WhiteRectangleDetector::new(&self.image, Some(15), Some(cx), Some(cy));
if corner_points_wrd.is_ok() {
let corner_points: Vec<ResultPoint> = corner_points_wrd.detect();
point_a = corner_points[0];
point_b = corner_points[1];
point_c = corner_points[2];
point_d = corner_points[3];
} else {
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();
}
// 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.0f32,
);
cy = MathUtils::round(
(point_a.get_y() + point_d.get_y() + point_b.get_y() + point_c.get_y()) / 4.0f32,
);
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<ResultPoint>) -> Vec<ResultPoint> {
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,
) -> Result<BitMatrix, Rc<Exception>> {
let sampler: GridSampler = GridSampler::get_instance();
let dimension: i32 = self.get_dimension();
let low: f32 = dimension / 2.0f32 - self.nb_center_layers;
let high: f32 = dimension / 2.0f32 + 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.0f32 {
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.1f32 && err_ratio < 0.9f32 {
return 0;
}
return if (err_ratio <= 0.1f32) == 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<ResultPoint>,
old_side: i32,
new_side: i32,
) -> Vec<ResultPoint> {
let ratio: f32 = new_side / (2.0f32 * 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.0f32;
let mut centery: f32 = (corner_points[0].get_y() + corner_points[2].get_y()) / 2.0f32;
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.0f32;
centery = (corner_points[1].get_y() + corner_points[3].get_y()) / 2.0f32;
let result1: ResultPoint = ResultPoint::new(centerx + ratio * dx, centery + ratio * dy);
let result3: ResultPoint = ResultPoint::new(centerx - ratio * dx, centery - ratio * dy);
return vec![result0, result1, result2, result3];
}
fn is_valid_coords(&self, x: i32, y: i32) -> bool {
return x >= 0 && x < self.image.get_width() && y >= 0 && y < self.image.get_height();
}
fn is_valid_rp(&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 {
x: i32,
y: i32,
}
impl Point {
fn to_result_point(&self) -> ResultPoint {
return ResultPoint::new(self.x, self.y);
}
fn new(x: i32, y: i32) -> Self {
Self { x: x, 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);
}
}
-1387
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -1 +0,0 @@
pub mod result;
-3525
View File
File diff suppressed because it is too large Load Diff
-3750
View File
File diff suppressed because it is too large Load Diff
-708
View File
@@ -1,708 +0,0 @@
use crate::common::{BitMatrix, BitMatrix};
use crate::{NotFoundException, ResultPoint};
// MathUtils.java
/**
* General math-related and numeric utility functions.
*/
pub struct MathUtils {}
impl MathUtils {
fn new() -> Self {
Self {}
}
/**
* Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its
* argument to the nearest int, where x.5 rounds up to x+1. Semantics of this shortcut
* differ slightly from {@link Math#round(float)} in that half rounds down for negative
* values. -2.5 rounds to -3, not -2. For purposes here it makes no difference.
*
* @param d real value to round
* @return nearest {@code int}
*/
pub fn round(d: f32) -> i32 {
return (d + (if d < 0.0f32 { -0.5f32 } else { 0.5f32 })) as i32;
}
/**
* @param aX point A x coordinate
* @param aY point A y coordinate
* @param bX point B x coordinate
* @param bY point B y coordinate
* @return Euclidean distance between points A and B
*/
pub fn distance(a_x: f32, a_y: f32, b_x: f32, b_y: f32) -> f32 {
let x_diff: f64 = a_x - b_x;
let y_diff: f64 = a_y - b_y;
return Math::sqrt(x_diff * x_diff + y_diff * y_diff) as f32;
}
/**
* @param aX point A x coordinate
* @param aY point A y coordinate
* @param bX point B x coordinate
* @param bY point B y coordinate
* @return Euclidean distance between points A and B
*/
pub fn distance(a_x: i32, a_y: i32, b_x: i32, b_y: i32) -> f32 {
let x_diff: f64 = a_x - b_x;
let y_diff: f64 = a_y - b_y;
return Math::sqrt(x_diff * x_diff + y_diff * y_diff) as f32;
}
/**
* @param array values to sum
* @return sum of values in array
*/
pub fn sum(array: &Vec<i32>) -> i32 {
let mut count: i32 = 0;
for a in array {
count += a;
}
return count;
}
}
// MonochromeRectangleDetector.java
/**
* <p>A somewhat generic detector that looks for a barcode-like rectangular region within an image.
* It looks within a mostly white region of an image for a region of black and white, but mostly
* black. It returns the four corners of the region, as best it can determine.</p>
*
* @author Sean Owen
* @deprecated without replacement since 3.3.0
*/
const MAX_MODULES: i32 = 32;
#[deprecated]
pub struct MonochromeRectangleDetector {
image: BitMatrix,
}
impl MonochromeRectangleDetector {
pub fn new(image: &BitMatrix) -> Self {
Self { image }
}
/**
* <p>Detects a rectangular region of black and white -- mostly black -- with a region of mostly
* white, in an image.</p>
*
* @return {@link ResultPoint}[] describing the corners of the rectangular region. The first and
* last points are opposed on the diagonal, as are the second and third. The first point will be
* the topmost point and the last, the bottommost. The second point will be leftmost and the
* third, the rightmost
* @throws NotFoundException if no Data Matrix Code can be found
*/
pub fn detect(&self) -> Result<Vec<ResultPoint>, Rc<Exception>> {
let height: i32 = self.image.get_height();
let width: i32 = self.image.get_width();
let half_height: i32 = height / 2;
let half_width: i32 = width / 2;
let delta_y: i32 = Math::max(1, height / (MAX_MODULES * 8));
let delta_x: i32 = Math::max(1, width / (MAX_MODULES * 8));
let mut top: i32 = 0;
let mut bottom: i32 = height;
let mut left: i32 = 0;
let mut right: i32 = width;
let point_a: ResultPoint = self.find_corner_from_center(
half_width,
0,
left,
right,
half_height,
-delta_y,
top,
bottom,
half_width / 2,
);
top = point_a.get_y() as i32 - 1;
let point_b: ResultPoint = self.find_corner_from_center(
half_width,
-delta_x,
left,
right,
half_height,
0,
top,
bottom,
half_height / 2,
);
left = point_b.get_x() as i32 - 1;
let point_c: ResultPoint = self.find_corner_from_center(
half_width,
delta_x,
left,
right,
half_height,
0,
top,
bottom,
half_height / 2,
);
right = point_c.get_x() as i32 + 1;
let point_d: ResultPoint = self.find_corner_from_center(
half_width,
0,
left,
right,
half_height,
delta_y,
top,
bottom,
half_width / 2,
);
bottom = point_d.get_y() as i32 + 1;
// Go try to find point A again with better information -- might have been off at first.
point_a = self.find_corner_from_center(
half_width,
0,
left,
right,
half_height,
-delta_y,
top,
bottom,
half_width / 4,
);
return Ok(vec![point_a, point_b, point_c, point_d]);
}
/**
* Attempts to locate a corner of the barcode by scanning up, down, left or right from a center
* point which should be within the barcode.
*
* @param centerX center's x component (horizontal)
* @param deltaX same as deltaY but change in x per step instead
* @param left minimum value of x
* @param right maximum value of x
* @param centerY center's y component (vertical)
* @param deltaY change in y per step. If scanning up this is negative; down, positive;
* left or right, 0
* @param top minimum value of y to search through (meaningless when di == 0)
* @param bottom maximum value of y
* @param maxWhiteRun maximum run of white pixels that can still be considered to be within
* the barcode
* @return a {@link ResultPoint} encapsulating the corner that was found
* @throws NotFoundException if such a point cannot be found
*/
fn find_corner_from_center(
&self,
center_x: i32,
delta_x: i32,
left: i32,
right: i32,
center_y: i32,
delta_y: i32,
top: i32,
bottom: i32,
max_white_run: i32,
) -> Result<ResultPoint, NotFoundException> {
let last_range: Vec<i32> = null;
{
let mut y: i32 = center_y;
let mut x: i32 = center_x;
while y < bottom && y >= top && x < right && x >= left {
{
let mut range: Vec<i32>;
if delta_x == 0 {
// horizontal slices, up and down
range = self.black_white_range(y, max_white_run, left, right, true);
} else {
// vertical slices, left and right
range = self.black_white_range(x, max_white_run, top, bottom, false);
}
if range == null {
if last_range == null {
return Err(NotFoundException::get_not_found_instance());
}
// lastRange was found
if delta_x == 0 {
let last_y: i32 = y - delta_y;
if last_range[0] < center_x {
if last_range[1] > center_x {
// straddle, choose one or the other based on direction
return Ok(ResultPoint::new(
last_range[if delta_y > 0 { 0 } else { 1 }],
last_y,
));
}
return Ok(ResultPoint::new(last_range[0], last_y));
} else {
return Ok(ResultPoint::new(last_range[1], last_y));
}
} else {
let last_x: i32 = x - delta_x;
if last_range[0] < center_y {
if last_range[1] > center_y {
return Ok(ResultPoint::new(
last_x,
last_range[if delta_x < 0 { 0 } else { 1 }],
));
}
return Ok(ResultPoint::new(last_x, last_range[0]));
} else {
return Ok(ResultPoint::new(last_x, last_range[1]));
}
}
}
last_range = range;
}
y += delta_y;
x += delta_x;
}
}
return Err(NotFoundException::get_not_found_instance());
}
/**
* Computes the start and end of a region of pixels, either horizontally or vertically, that could
* be part of a Data Matrix barcode.
*
* @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location)
* where we are scanning. If scanning vertically it's the column, the fixed horizontal location
* @param maxWhiteRun largest run of white pixels that can still be considered part of the
* barcode region
* @param minDim minimum pixel location, horizontally or vertically, to consider
* @param maxDim maximum pixel location, horizontally or vertically, to consider
* @param horizontal if true, we're scanning left-right, instead of up-down
* @return int[] with start and end of found range, or null if no such range is found
* (e.g. only white was found)
*/
fn black_white_range(
&self,
fixed_dimension: i32,
max_white_run: i32,
min_dim: i32,
max_dim: i32,
horizontal: bool,
) -> Option<Vec<i32>> {
let center: i32 = (min_dim + max_dim) / 2;
// Scan left/up first
let mut start: i32 = center;
while start >= min_dim {
if if horizontal {
self.image.get(start, fixed_dimension)
} else {
self.image.get(fixed_dimension, start)
} {
start -= 1;
} else {
let white_run_start: i32 = start;
loop {
{
start -= 1;
}
if !(start >= min_dim
&& !(if horizontal {
self.image.get(start, fixed_dimension)
} else {
self.image.get(fixed_dimension, start)
}))
{
break;
}
}
let white_run_size: i32 = white_run_start - start;
if start < min_dim || white_run_size > max_white_run {
start = white_run_start;
break;
}
}
}
start += 1;
// Then try right/down
let mut end: i32 = center;
while end < max_dim {
if if horizontal {
self.image.get(end, fixed_dimension)
} else {
self.image.get(fixed_dimension, end)
} {
end += 1;
} else {
let white_run_start: i32 = end;
loop {
{
end += 1;
}
if !(end < max_dim
&& !(if horizontal {
self.image.get(end, fixed_dimension)
} else {
self.image.get(fixed_dimension, end)
}))
{
break;
}
}
let white_run_size: i32 = end - white_run_start;
if end >= max_dim || white_run_size > max_white_run {
end = white_run_start;
break;
}
}
}
end -= 1;
return if end > start {
Some(vec![start, end])
} else {
null
};
}
}
// WhiteRectangleDetector.java
/**
* <p>
* Detects a candidate barcode-like rectangular region within an image. It
* starts around the center of the image, increases the size of the candidate
* region until it finds a white rectangular region. By keeping track of the
* last black points it encountered, it determines the corners of the barcode.
* </p>
*
* @author David Olivier
*/
const INIT_SIZE: i32 = 10;
const CORR: i32 = 1;
pub struct WhiteRectangleDetector {
image: BitMatrix,
height: i32,
width: i32,
left_init: i32,
right_init: i32,
down_init: i32,
up_init: i32,
}
impl WhiteRectangleDetector {
/**
* @param image barcode image to find a rectangle in
* @param initSize initial size of search area around center
* @param x x position of search center
* @param y y position of search center
* @throws NotFoundException if image is too small to accommodate {@code initSize}
*/
pub fn new(
image: &BitMatrix,
init_size: Option<i32>,
x_in: Option<i32>,
y_in: Option<i32>,
) -> Result<Self, NotFoundException> {
let mut new_wrd: Self;
let x = x_in.unwrap_or(image.get_width() / 2);
let y = y_in.unwrap_or(image.get_height() / 2);
new_wrd.image = image;
new_wrd.height = image.get_height();
new_wrd.width = image.get_width();
let halfsize: i32 = init_size.unwrap_or(INIT_SIZE) / 2;
new_wrd.left_init = x - halfsize;
new_wrd.right_init = x + halfsize;
new_wrd.up_init = y - halfsize;
new_wrd.down_init = y + halfsize;
if up_init < 0 || left_init < 0 || down_init >= height || right_init >= width {
return Err(NotFoundException::get_not_found_instance());
}
Ok(new_wrd)
}
/**
* <p>
* Detects a candidate barcode-like rectangular region within an image. It
* starts around the center of the image, increases the size of the candidate
* region until it finds a white rectangular region.
* </p>
*
* @return {@link ResultPoint}[] describing the corners of the rectangular
* region. The first and last points are opposed on the diagonal, as
* are the second and third. The first point will be the topmost
* point and the last, the bottommost. The second point will be
* leftmost and the third, the rightmost
* @throws NotFoundException if no Data Matrix Code can be found
*/
pub fn detect(&self) -> Result<Vec<ResultPoint>, NotFoundException> {
let mut left: i32 = self.left_init;
let mut right: i32 = self.right_init;
let mut up: i32 = self.up_init;
let mut down: i32 = self.down_init;
let size_exceeded: bool = false;
let a_black_point_found_on_border: bool = true;
let at_least_one_black_point_found_on_right: bool = false;
let at_least_one_black_point_found_on_bottom: bool = false;
let at_least_one_black_point_found_on_left: bool = false;
let at_least_one_black_point_found_on_top: bool = false;
while a_black_point_found_on_border {
a_black_point_found_on_border = false;
// .....
// . |
// .....
let right_border_not_white: bool = true;
while (right_border_not_white || !at_least_one_black_point_found_on_right)
&& right < self.width
{
right_border_not_white = self.contains_black_point(up, down, right, false);
if right_border_not_white {
right += 1;
a_black_point_found_on_border = true;
at_least_one_black_point_found_on_right = true;
} else if !at_least_one_black_point_found_on_right {
right += 1;
}
}
if right >= self.width {
size_exceeded = true;
break;
}
// .....
// . .
// .___.
let bottom_border_not_white: bool = true;
while (bottom_border_not_white || !at_least_one_black_point_found_on_bottom)
&& down < self.height
{
bottom_border_not_white = self.contains_black_point(left, right, down, true);
if bottom_border_not_white {
down += 1;
a_black_point_found_on_border = true;
at_least_one_black_point_found_on_bottom = true;
} else if !at_least_one_black_point_found_on_bottom {
down += 1;
}
}
if down >= self.height {
size_exceeded = true;
break;
}
// .....
// | .
// .....
let left_border_not_white: bool = true;
while (left_border_not_white || !at_least_one_black_point_found_on_left) && left >= 0 {
left_border_not_white = self.contains_black_point(up, down, left, false);
if left_border_not_white {
left -= 1;
a_black_point_found_on_border = true;
at_least_one_black_point_found_on_left = true;
} else if !at_least_one_black_point_found_on_left {
left -= 1;
}
}
if left < 0 {
size_exceeded = true;
break;
}
// .___.
// . .
// .....
let top_border_not_white: bool = true;
while (top_border_not_white || !at_least_one_black_point_found_on_top) && up >= 0 {
top_border_not_white = self.contains_black_point(left, right, up, true);
if top_border_not_white {
up -= 1;
a_black_point_found_on_border = true;
at_least_one_black_point_found_on_top = true;
} else if !at_least_one_black_point_found_on_top {
up -= 1;
}
}
if up < 0 {
size_exceeded = true;
break;
}
}
if !size_exceeded {
let max_size: i32 = right - left;
let mut z: ResultPoint = null;
{
let mut i: i32 = 1;
while z == null && i < max_size {
{
z = self.get_black_point_on_segment(left, down - i, left + i, down);
}
i += 1;
}
}
if z == null {
return Err(NotFoundException::get_not_found_instance());
}
let mut t: ResultPoint = null;
//go down right
{
let mut i: i32 = 1;
while t == null && i < max_size {
{
t = self.get_black_point_on_segment(left, up + i, left + i, up);
}
i += 1;
}
}
if t == null {
return Err(NotFoundException::get_not_found_instance());
}
let mut x: ResultPoint = null;
//go down left
{
let mut i: i32 = 1;
while x == null && i < max_size {
{
x = self.get_black_point_on_segment(right, up + i, right - i, up);
}
i += 1;
}
}
if x == null {
return Err(NotFoundException::get_not_found_instance());
}
let mut y: ResultPoint = null;
//go up left
{
let mut i: i32 = 1;
while y == null && i < max_size {
{
y = self.get_black_point_on_segment(right, down - i, right - i, down);
}
i += 1;
}
}
if y == null {
return Err(NotFoundException::get_not_found_instance());
}
return Ok(self.center_edges(&y, &z, &x, &t));
} else {
return Err(NotFoundException::get_not_found_instance());
}
}
fn get_black_point_on_segment(
&self,
a_x: f32,
a_y: f32,
b_x: f32,
b_y: f32,
) -> Option<ResultPoint> {
let dist: i32 = MathUtils::round(&MathUtils::distance(a_x, a_y, b_x, b_y));
let x_step: f32 = (b_x - a_x) / dist;
let y_step: f32 = (b_y - a_y) / dist;
{
let mut i: i32 = 0;
while i < dist {
{
let x: i32 = MathUtils::round(a_x + i * x_step);
let y: i32 = MathUtils::round(a_y + i * y_step);
if self.image.get(x, y) {
return Some(ResultPoint::new(x, y));
}
}
i += 1;
}
}
return null;
}
/**
* recenters the points of a constant distance towards the center
*
* @param y bottom most point
* @param z left most point
* @param x right most point
* @param t top most point
* @return {@link ResultPoint}[] describing the corners of the rectangular
* region. The first and last points are opposed on the diagonal, as
* are the second and third. The first point will be the topmost
* point and the last, the bottommost. The second point will be
* leftmost and the third, the rightmost
*/
fn center_edges(
&self,
y: &ResultPoint,
z: &ResultPoint,
x: &ResultPoint,
t: &ResultPoint,
) -> Vec<ResultPoint> {
//
// t t
// z x
// x OR z
// y y
//
let yi: f32 = y.get_x();
let yj: f32 = y.get_y();
let zi: f32 = z.get_x();
let zj: f32 = z.get_y();
let xi: f32 = x.get_x();
let xj: f32 = x.get_y();
let ti: f32 = t.get_x();
let tj: f32 = t.get_y();
if yi < self.width / 2.0f32 {
return vec![
ResultPoint::new(ti - CORR, tj + CORR),
ResultPoint::new(zi + CORR, zj + CORR),
ResultPoint::new(xi - CORR, xj - CORR),
ResultPoint::new(yi + CORR, yj - CORR),
];
} else {
return vec![
ResultPoint::new(ti + CORR, tj + CORR),
ResultPoint::new(zi + CORR, zj - CORR),
ResultPoint::new(xi - CORR, xj + CORR),
ResultPoint::new(yi - CORR, yj - CORR),
];
}
}
/**
* Determines whether a segment contains a black point
*
* @param a min value of the scanned coordinate
* @param b max value of the scanned coordinate
* @param fixed value of fixed coordinate
* @param horizontal set to true if scan must be horizontal, false if vertical
* @return true if a black point has been found, else false.
*/
fn contains_black_point(&self, a: i32, b: i32, fixed: i32, horizontal: bool) -> bool {
if horizontal {
{
let mut x: i32 = a;
while x <= b {
{
if self.image.get(x, fixed) {
return true;
}
}
x += 1;
}
}
} else {
{
let mut y: i32 = a;
while y <= b {
{
if self.image.get(fixed, y) {
return true;
}
}
y += 1;
}
}
}
return false;
}
}
-849
View File
@@ -1,849 +0,0 @@
// GenericGFPoly.java
/**
* <p>Represents a polynomial whose coefficients are elements of a GF.
* Instances of this class are immutable.</p>
*
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
* port of his C++ Reed-Solomon implementation.</p>
*
* @author Sean Owen
*/
struct GenericGFPoly {
field: GenericGF,
coefficients: Vec<i32>,
}
impl GenericGFPoly {
/**
* @param field the {@link GenericGF} instance representing the field to use
* to perform computations
* @param coefficients coefficients as ints representing elements of GF(size), arranged
* from most significant (highest-power term) coefficient to least significant
* @throws IllegalArgumentException if argument is null or empty,
* or if leading coefficient is 0 and this is not a
* constant polynomial (that is, it is not the monomial "0")
*/
fn new(field: &GenericGF, coefficients: &Vec<i32>) -> Result<Self, IllegalArgumentException> {
let mut new_poly: GenericGFPoly;
if coefficients.len() == 0 {
return Err(IllegalArgumentException::new());
}
new_poly.field = field;
let coefficients_length: i32 = coefficients.len();
if coefficients_length > 1 && coefficients[0] == 0 {
// Leading term must be non-zero for anything except the constant polynomial "0"
let first_non_zero: i32 = 1;
while first_non_zero < coefficients_length && coefficients[first_non_zero] == 0 {
first_non_zero += 1;
}
if first_non_zero == coefficients_length {
new_poly.coefficients = vec![0];
} else {
new_poly.coefficients = coefficients;
//System::arraycopy(&coefficients, first_non_zero, let .coefficients, 0, let .coefficients.len());
}
} else {
new_poly.coefficients = coefficients;
}
Ok(new_poly)
}
fn get_coefficients(&self) -> Vec<i32> {
return self.coefficients;
}
/**
* @return degree of this polynomial
*/
fn get_degree(&self) -> i32 {
return self.coefficients.len() - 1;
}
/**
* @return true iff this polynomial is the monomial "0"
*/
fn is_zero(&self) -> bool {
return self.coefficients[0] == 0;
}
/**
* @return coefficient of x^degree term in this polynomial
*/
fn get_coefficient(&self, degree: i32) -> i32 {
return self.coefficients[self.coefficients.len() - 1 - degree];
}
/**
* @return evaluation of this polynomial at a given point
*/
fn evaluate_at(&self, a: i32) -> i32 {
if a == 0 {
// Just return the x^0 coefficient
return self.get_coefficient(0);
}
if a == 1 {
// Just the sum of the coefficients
let mut result: i32 = 0;
for coefficient in self.coefficients {
result = GenericGF::add_or_subtract(result, coefficient);
}
return result;
}
let mut result: i32 = self.coefficients[0];
let size: i32 = self.coefficients.len();
{
let mut i: i32 = 1;
while i < size {
{
result = GenericGF::add_or_subtract(
&self.field.multiply(a, result),
self.coefficients[i],
);
}
i += 1;
}
}
return result;
}
fn add_or_subtract(
&self,
other: &GenericGFPoly,
) -> Result<GenericGFPoly, IllegalArgumentException> {
if !self.field.equals(other.field) {
return Err(IllegalArgumentException::new(
"GenericGFPolys do not have same GenericGF field",
));
}
if self.is_zero() {
return other;
}
if other.is_zero() {
return self;
}
let smaller_coefficients: Vec<i32> = self.coefficients;
let larger_coefficients: Vec<i32> = other.coefficients;
if smaller_coefficients.len() > larger_coefficients.len() {
let temp: Vec<i32> = smaller_coefficients;
smaller_coefficients = larger_coefficients;
larger_coefficients = temp;
}
let sum_diff: [i32; larger_coefficients.len()] = [0; larger_coefficients.len()];
let length_diff: i32 = larger_coefficients.len() - smaller_coefficients.len();
// Copy high-order terms only found in higher-degree polynomial's coefficients
System::arraycopy(&larger_coefficients, 0, &sum_diff, 0, length_diff);
{
let mut i: i32 = length_diff;
while i < larger_coefficients.len() {
{
sum_diff[i] = GenericGF::add_or_subtract(
smaller_coefficients[i - length_diff],
larger_coefficients[i],
);
}
i += 1;
}
}
return GenericGFPoly::new(&self.field, &sum_diff);
}
fn multiply(&self, other: &GenericGFPoly) -> Result<GenericGFPoly, IllegalArgumentException> {
if !self.field.equals(other.field) {
return Err(IllegalArgumentException::new(
"GenericGFPolys do not have same GenericGF field",
));
}
if self.is_zero() || other.is_zero() {
return Ok(self.field.get_zero());
}
let a_coefficients: Vec<i32> = self.coefficients;
let a_length: i32 = a_coefficients.len();
let b_coefficients: Vec<i32> = other.coefficients;
let b_length: i32 = b_coefficients.len();
let mut product: [i32; a_length + b_length - 1] = [0; a_length + b_length - 1];
{
let mut i: i32 = 0;
while i < a_length {
{
let a_coeff: i32 = a_coefficients[i];
{
let mut j: i32 = 0;
while j < b_length {
{
product[i + j] = GenericGF::add_or_subtract(
product[i + j],
&self.field.multiply(a_coeff, b_coefficients[j]),
);
}
j += 1;
}
}
}
i += 1;
}
}
return GenericGFPoly::new(&self.field, &product);
}
fn multiply(&self, scalar: i32) -> GenericGFPoly {
if scalar == 0 {
return self.field.get_zero();
}
if scalar == 1 {
return self;
}
let size: i32 = self.coefficients.len();
let mut product: [i32; size] = [0; size];
{
let mut i: i32 = 0;
while i < size {
{
product[i] = self.field.multiply(self.coefficients[i], scalar);
}
i += 1;
}
}
return GenericGFPoly::new(&self.field, &product);
}
fn multiply_by_monomial(
&self,
degree: i32,
coefficient: i32,
) -> Result<GenericGFPoly, IllegalArgumentException> {
if degree < 0 {
return Err(IllegalArgumentException::new());
}
if coefficient == 0 {
return Ok(self.field.get_zero());
}
let size: i32 = self.coefficients.len();
let mut product: [i32; size + degree] = [0; size + degree];
{
let mut i: i32 = 0;
while i < size {
{
product[i] = self.field.multiply(self.coefficients[i], coefficient);
}
i += 1;
}
}
return GenericGFPoly::new(&self.field, &product);
}
fn divide(
&self,
other: &GenericGFPoly,
) -> Result<Vec<GenericGFPoly>, IllegalArgumentException> {
if !self.field.equals(other.field) {
return Err(IllegalArgumentException::new(
"GenericGFPolys do not have same GenericGF field",
));
}
if other.is_zero() {
return Err(IllegalArgumentException::new("Divide by 0"));
}
let mut quotient: GenericGFPoly = self.field.get_zero();
let mut remainder: GenericGFPoly = self;
let denominator_leading_term: i32 = other.get_coefficient(&other.get_degree());
let inverse_denominator_leading_term: i32 = self.field.inverse(denominator_leading_term);
while remainder.get_degree() >= other.get_degree() && !remainder.is_zero() {
let degree_difference: i32 = remainder.get_degree() - other.get_degree();
let scale: i32 = self.field.multiply(
&remainder.get_coefficient(&remainder.get_degree()),
inverse_denominator_leading_term,
);
let term: GenericGFPoly = other.multiply_by_monomial(degree_difference, scale);
let iteration_quotient: GenericGFPoly =
self.field.build_monomial(degree_difference, scale);
quotient = quotient.add_or_subtract(&iteration_quotient);
remainder = remainder.add_or_subtract(&term);
}
return Ok(vec![quotient, remainder]);
}
pub fn to_string(&self) -> String {
if self.is_zero() {
return "0".to_owned();
}
let result: StringBuilder = StringBuilder::new(8 * self.get_degree());
{
let mut degree: i32 = self.get_degree();
while degree >= 0 {
{
let mut coefficient: i32 = self.get_coefficient(degree);
if coefficient != 0 {
if coefficient < 0 {
if degree == self.get_degree() {
result.append("-");
} else {
result.append(" - ");
}
coefficient = -coefficient;
} else {
if result.length() > 0 {
result.append(" + ");
}
}
if degree == 0 || coefficient != 1 {
let alpha_power: i32 = self.field.log(coefficient);
if alpha_power == 0 {
result.append('1');
} else if alpha_power == 1 {
result.append('a');
} else {
result.append("a^");
result.append(alpha_power);
}
}
if degree != 0 {
if degree == 1 {
result.append('x');
} else {
result.append("x^");
result.append(degree);
}
}
}
}
degree -= 1;
}
}
return result.to_string();
}
}
// GenericGF.java
/**
* <p>This class contains utility methods for performing mathematical operations over
* the Galois Fields. Operations use a given primitive polynomial in calculations.</p>
*
* <p>Throughout this package, elements of the GF are represented as an {@code int}
* for convenience and speed (but at the cost of memory).
* </p>
*
* @author Sean Owen
* @author David Olivier
*/
// x^12 + x^6 + x^5 + x^3 + 1
const AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1);
// x^10 + x^3 + 1
const AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1);
// x^6 + x + 1
const AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1);
// x^4 + x + 1
const AZTEC_PARAM: GenericGF = GenericGF::new(0x13, 16, 1);
// x^8 + x^4 + x^3 + x^2 + 1
const QR_CODE_FIELD_256: GenericGF = GenericGF::new(0x011D, 256, 0);
// x^8 + x^5 + x^3 + x^2 + 1
const DATA_MATRIX_FIELD_256: GenericGF = GenericGF::new(0x012D, 256, 1);
const AZTEC_DATA_8: GenericGF = DATA_MATRIX_FIELD_256;
const MAXICODE_FIELD_64: GenericGF = AZTEC_DATA_6;
pub struct GenericGF {
exp_table: Vec<i32>,
log_table: Vec<i32>,
zero: GenericGFPoly,
one: GenericGFPoly,
size: i32,
primitive: i32,
generator_base: i32,
}
impl GenericGF {
/**
* Create a representation of GF(size) using the given primitive polynomial.
*
* @param primitive irreducible polynomial whose coefficients are represented by
* the bits of an int, where the least-significant bit represents the constant
* coefficient
* @param size the size of the field
* @param b the factor b in the generator polynomial can be 0- or 1-based
* (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))).
* In most cases it should be 1, but for QR code it is 0.
*/
pub fn new(primitive: i32, size: i32, b: i32) -> Self {
let mut new_generic_gf: GenericGF;
new_generic_gf.primitive = primitive;
new_generic_gf.size = size;
new_generic_gf.generatorBase = b;
exp_table = [0; size];
log_table = [0; size];
let mut x: i32 = 1;
{
let mut i: i32 = 0;
while i < size {
{
exp_table[i] = x;
// we're assuming the generator alpha is 2
x *= 2;
if x >= size {
x ^= primitive;
x &= size - 1;
}
}
i += 1;
}
}
{
let mut i: i32 = 0;
while i < size - 1 {
{
log_table[exp_table[i]] = i;
}
i += 1;
}
}
// logTable[0] == 0 but this should never be used
new_generic_gf.zero = GenericGFPoly::new(0, &vec![0]);
new_generic_gf.one = GenericGFPoly::new(0, &vec![1]);
new_generic_gf
}
fn get_zero(&self) -> GenericGFPoly {
return self.zero;
}
fn get_one(&self) -> GenericGFPoly {
return self.one;
}
/**
* @return the monomial representing coefficient * x^degree
*/
fn build_monomial(
&self,
degree: i32,
coefficient: i32,
) -> Result<GenericGFPoly, IllegalArgumentException> {
if degree < 0 {
return Err(IllegalArgumentException::new());
}
if coefficient == 0 {
return Ok(self.zero);
}
let mut coefficients: [i32; degree + 1] = [0; degree + 1];
coefficients[0] = coefficient;
return GenericGFPoly::new(self, &coefficients);
}
/**
* Implements both addition and subtraction -- they are the same in GF(size).
*
* @return sum/difference of a and b
*/
fn add_or_subtract(a: i32, b: i32) -> i32 {
return a ^ b;
}
/**
* @return 2 to the power of a in GF(size)
*/
fn exp(&self, a: i32) -> i32 {
return self.exp_table[a];
}
/**
* @return base 2 log of a in GF(size)
*/
fn log(&self, a: i32) -> Result<i32, IllegalArgumentException> {
if a == 0 {
return Err(IllegalArgumentException::new());
}
return self.log_table[a];
}
/**
* @return multiplicative inverse of a
*/
fn inverse(&self, a: i32) -> Result<i32, ArithmeticException> {
if a == 0 {
return Err(ArithmeticException::new());
}
return self.exp_table[self.size - self.log_table[a] - 1];
}
/**
* @return product of a and b in GF(size)
*/
fn multiply(&self, a: i32, b: i32) -> i32 {
if a == 0 || b == 0 {
return 0;
}
return self.exp_table[(self.log_table[a] + self.log_table[b]) % (self.size - 1)];
}
pub fn get_size(&self) -> i32 {
return self.size;
}
pub fn get_generator_base(&self) -> i32 {
return self.generator_base;
}
pub fn to_string(&self) -> String {
return format!(
"GF(0x{},{})",
Integer::to_hex_string(self.primitive),
self.size
);
}
}
// ReedSolomonDecoder.java
/**
* <p>Implements Reed-Solomon decoding, as the name implies.</p>
*
* <p>The algorithm will not be explained here, but the following references were helpful
* in creating this implementation:</p>
*
* <ul>
* <li>Bruce Maggs.
* <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
* "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
* <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
* "Chapter 5. Generalized Reed-Solomon Codes"</a>
* (see discussion of Euclidean algorithm)</li>
* </ul>
*
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
* port of his C++ Reed-Solomon implementation.</p>
*
* @author Sean Owen
* @author William Rucklidge
* @author sanfordsquires
*/
pub struct ReedSolomonDecoder {
field: GenericGF,
}
impl ReedSolomonDecoder {
pub fn new(field: &GenericGF) -> Self {
Self { field }
}
/**
* <p>Decodes given set of received codewords, which include both data and error-correction
* codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
* in the input.</p>
*
* @param received data and error-correction codewords
* @param twoS number of error-correction codewords available
* @throws ReedSolomonException if decoding fails for any reason
*/
pub fn decode(&self, received: &Vec<i32>, two_s: i32) -> Result<(), ReedSolomonException> {
let poly: GenericGFPoly = GenericGFPoly::new(&self.field, &received);
let syndrome_coefficients: [i32; two_s] = [0; two_s];
let no_error: bool = true;
{
let mut i: i32 = 0;
while i < two_s {
{
let eval: i32 =
poly.evaluate_at(&self.field.exp(i + self.field.get_generator_base()));
syndrome_coefficients[syndrome_coefficients.len() - 1 - i] = eval;
if eval != 0 {
no_error = false;
}
}
i += 1;
}
}
if no_error {
return;
}
let syndrome: GenericGFPoly = GenericGFPoly::new(&self.field, &syndrome_coefficients);
let sigma_omega: Vec<GenericGFPoly> =
self.run_euclidean_algorithm(&self.field.build_monomial(two_s, 1), &syndrome, two_s);
let sigma: GenericGFPoly = sigma_omega[0];
let omega: GenericGFPoly = sigma_omega[1];
let error_locations: Vec<i32> = self.find_error_locations(&sigma);
let error_magnitudes: Vec<i32> = self.find_error_magnitudes(&omega, &error_locations);
{
let mut i: i32 = 0;
while i < error_locations.len() {
{
let mut position: i32 = received.len() - 1 - self.field.log(error_locations[i]);
if position < 0 {
return Err(ReedSolomonException::new("Bad error location"));
}
received[position] =
GenericGF::add_or_subtract(received[position], error_magnitudes[i]);
}
i += 1;
}
}
Ok(())
}
fn run_euclidean_algorithm(
&self,
a: &GenericGFPoly,
b: &GenericGFPoly,
R: i32,
) -> Result<Vec<GenericGFPoly>, ReedSolomonException + IllegalStateException> {
// Assume a's degree is >= b's
if a.get_degree() < b.get_degree() {
let temp: GenericGFPoly = a;
a = b;
b = &temp;
}
let r_last: GenericGFPoly = a;
let mut r: GenericGFPoly = b;
let t_last: GenericGFPoly = self.field.get_zero();
let mut t: GenericGFPoly = self.field.get_one();
// Run Euclidean algorithm until r's degree is less than R/2
while 2 * r.get_degree() >= R {
let r_last_last: GenericGFPoly = r_last;
let t_last_last: GenericGFPoly = t_last;
r_last = r;
t_last = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if r_last.is_zero() {
// Oops, Euclidean algorithm already terminated?
return Err(ReedSolomonException::new("r_{i-1} was zero"));
}
r = r_last_last;
let mut q: GenericGFPoly = self.field.get_zero();
let denominator_leading_term: i32 = r_last.get_coefficient(&r_last.get_degree());
let dlt_inverse: i32 = self.field.inverse(denominator_leading_term);
while r.get_degree() >= r_last.get_degree() && !r.is_zero() {
let degree_diff: i32 = r.get_degree() - r_last.get_degree();
let scale: i32 = self
.field
.multiply(&r.get_coefficient(&r.get_degree()), dlt_inverse);
q = q.add_or_subtract(&self.field.build_monomial(degree_diff, scale));
r = r.add_or_subtract(&r_last.multiply_by_monomial(degree_diff, scale));
}
t = q.multiply(&t_last).add_or_subtract(t_last_last);
if r.get_degree() >= r_last.get_degree() {
return Err(IllegalStateException::new(format!(
"Division algorithm failed to reduce polynomial? r: {}, rLast: {}",
r, r_last
)));
}
}
let sigma_tilde_at_zero: i32 = t.get_coefficient(0);
if sigma_tilde_at_zero == 0 {
return Err(ReedSolomonException::new("sigmaTilde(0) was zero"));
}
let inverse: i32 = self.field.inverse(sigma_tilde_at_zero);
let sigma: GenericGFPoly = t.multiply(inverse);
let omega: GenericGFPoly = r.multiply(inverse);
return Ok(vec![sigma, omega]);
}
fn find_error_locations(
&self,
error_locator: &GenericGFPoly,
) -> Result<Vec<i32>, ReedSolomonException> {
// This is a direct application of Chien's search
let num_errors: i32 = error_locator.get_degree();
if num_errors == 1 {
// shortcut
return Ok(vec![error_locator.get_coefficient(1)]);
}
let mut result: [i32; num_errors] = [0; num_errors];
let mut e: i32 = 0;
{
let mut i: i32 = 1;
while i < self.field.get_size() && e < num_errors {
{
if error_locator.evaluate_at(i) == 0 {
result[e] = self.field.inverse(i);
e += 1;
}
}
i += 1;
}
}
if e != num_errors {
return Err(ReedSolomonException::new(
"Error locator degree does not match number of roots",
));
}
return Ok(result);
}
fn find_error_magnitudes(
&self,
error_evaluator: &GenericGFPoly,
error_locations: &Vec<i32>,
) -> Vec<i32> {
// This is directly applying Forney's Formula
let s: i32 = error_locations.len();
let mut result: [i32; s] = [0; s];
{
let mut i: i32 = 0;
while i < s {
{
let xi_inverse: i32 = self.field.inverse(error_locations[i]);
let mut denominator: i32 = 1;
{
let mut j: i32 = 0;
while j < s {
{
if i != j {
//denominator = field.multiply(denominator,
// GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
// Below is a funny-looking workaround from Steven Parkes
let term: i32 =
self.field.multiply(error_locations[j], xi_inverse);
let term_plus1: i32 = if (term & 0x1) == 0 {
term | 1
} else {
term & 1
};
denominator = self.field.multiply(denominator, term_plus1);
}
}
j += 1;
}
}
result[i] = self.field.multiply(
&error_evaluator.evaluate_at(xi_inverse),
&self.field.inverse(denominator),
);
if self.field.get_generator_base() != 0 {
result[i] = self.field.multiply(result[i], xi_inverse);
}
}
i += 1;
}
}
return result;
}
}
// ReedSolomonEncoder.java
/**
* <p>Implements Reed-Solomon encoding, as the name implies.</p>
*
* @author Sean Owen
* @author William Rucklidge
*/
pub struct ReedSolomonEncoder {
field: GenericGF,
cached_generators: Vector<GenericGFPoly>,
}
impl ReedSolomonEncoder {
pub fn new(field: &GenericGF) -> Self {
let mut new_rse;
new_rse.field = field;
new_rse.cachedGenerators = Vector::new();
cached_generators.add(GenericGFPoly::new(field, &vec![1]));
new_rse
}
fn build_generator(&self, degree: i32) -> GenericGFPoly {
if degree >= self.cached_generators.size() {
let last_generator: GenericGFPoly = self
.cached_generators
.get(self.cached_generators.size() - 1);
{
let mut d: i32 = self.cached_generators.size();
while d <= degree {
{
let next_generator: GenericGFPoly =
last_generator.multiply(GenericGFPoly::new(
&self.field,
&vec![1, self.field.exp(d - 1 + self.field.get_generator_base())],
));
self.cached_generators.add(next_generator);
last_generator = next_generator;
}
d += 1;
}
}
}
return self.cached_generators.get(degree);
}
pub fn encode(
&self,
to_encode: &Vec<i32>,
ec_bytes: i32,
) -> Result<(), IllegalArgumentException> {
if ec_bytes == 0 {
return Err(IllegalArgumentException::new("No error correction bytes"));
}
let data_bytes: i32 = to_encode.len() - ec_bytes;
if data_bytes <= 0 {
return Err(IllegalArgumentException::new("No data bytes provided"));
}
let generator: GenericGFPoly = self.build_generator(ec_bytes);
let info_coefficients: [i32; data_bytes] = [0; data_bytes];
System::arraycopy(&to_encode, 0, &info_coefficients, 0, data_bytes);
let mut info: GenericGFPoly = GenericGFPoly::new(&self.field, &info_coefficients);
info = info.multiply_by_monomial(ec_bytes, 1);
let remainder: GenericGFPoly = info.divide(&generator)[1];
let coefficients: Vec<i32> = remainder.get_coefficients();
let num_zero_coefficients: i32 = ec_bytes - coefficients.len();
{
let mut i: i32 = 0;
while i < num_zero_coefficients {
{
to_encode[data_bytes + i] = 0;
}
i += 1;
}
}
System::arraycopy(
&coefficients,
0,
&to_encode,
data_bytes + num_zero_coefficients,
coefficients.len(),
);
Ok(())
}
}
// ReedSolomonException.java
/**
* <p>Thrown when an exception occurs during Reed-Solomon decoding, such as when
* there are too many errors to correct.</p>
*
* @author Sean Owen
*/
pub struct ReedSolomonException {
message: String,
}
impl ReedSolomonException {
pub fn new(message: &String) -> Self {
ReedSolomonException { message }
}
}
-406
View File
@@ -1,406 +0,0 @@
pub mod decoder;
pub mod detector;
pub mod encoder;
use crate::common::{BitMatrix, DecoderResult, DetectorResult};
use crate::datamatrix::decoder::Decoder;
use crate::datamatrix::detector::Detector;
use crate::datamatrix::encoder::{
DefaultPlacement, ErrorCorrection, HighLevelEncoder, MinimalEncoder, SymbolInfo,
SymbolShapeHint,
};
use crate::qrcode::encoder::ByteMatrix;
use crate::{
BarcodeFormat, BinaryBitmap, ChecksumException, DecodeHintType, Dimension, EncodeHintType,
FormatException, NotFoundException, RXingResult, Reader, ResultMetadataType, ResultPoint,
Writer,
};
// DataMatrixReader.java
/**
* This implementation can detect and decode Data Matrix codes in an image.
*
* @author bbrown@google.com (Brian Brown)
*/
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
pub struct DataMatrixReader {
decoder: Decoder,
}
impl Reader for DataMatrixReader {
/**
* 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
* @throws ChecksumException if error correction fails
*/
fn decode(
&self,
image: &BinaryBitmap,
hints: &Map<DecodeHintType, _>,
) -> Result<Result, NotFoundException, ChecksumException, FormatException> {
let decoder_result: DecoderResult;
let mut points: Vec<ResultPoint>;
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
decoder_result = self.decoder.decode(bits);
points = NO_POINTS;
} else {
let detector_result: DetectorResult = Detector::new(&image.get_black_matrix()).detect();
decoder_result = self.decoder.decode(&detector_result.get_bits());
points = detector_result.get_points();
}
let result: Result = Result::new(
&decoder_result.get_text(),
&decoder_result.get_raw_bytes(),
points,
BarcodeFormat::DATA_MATRIX,
);
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
if byte_segments != null {
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
}
let ec_level: String = decoder_result.get_e_c_level();
if ec_level != null {
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
}
result.put_metadata(
ResultMetadataType::SYMBOLOGY_IDENTIFIER,
format!("]d{}", decoder_result.get_symbology_modifier()),
);
return Ok(result);
}
fn reset(&self) {
// do nothing
}
}
impl DataMatrixReader {
pub fn new() -> Self {
Self {
decoder: Decoder::new(),
}
}
/**
* This method detects a code in a "pure" image -- that is, pure monochrome image
* which contains only an unrotated, unskewed, image of a code, with some white border
* around it. This is a specialized method that works exceptionally fast in this special
* case.
*/
fn extract_pure_bits(image: &BitMatrix) -> Result<BitMatrix, NotFoundException> {
let left_top_black: Vec<i32> = image.get_top_left_on_bit();
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
if left_top_black == null || right_bottom_black == null {
return Err(NotFoundException::get_not_found_instance());
}
let module_size: i32 = self.module_size(&left_top_black, image);
let mut top: i32 = left_top_black[1];
let bottom: i32 = right_bottom_black[1];
let mut left: i32 = left_top_black[0];
let right: i32 = right_bottom_black[0];
let matrix_width: i32 = (right - left + 1) / module_size;
let matrix_height: i32 = (bottom - top + 1) / module_size;
if matrix_width <= 0 || matrix_height <= 0 {
return Err(NotFoundException::get_not_found_instance());
}
// Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a
// little off, this will help recover.
let nudge: i32 = module_size / 2;
top += nudge;
left += nudge;
// Now just read off the bits
let bits: BitMatrix = BitMatrix::new(matrix_width, matrix_height);
{
let mut y: i32 = 0;
while y < matrix_height {
{
let i_offset: i32 = top + y * module_size;
{
let mut x: i32 = 0;
while x < matrix_width {
{
if image.get(left + x * module_size, i_offset) {
bits.set(x, y);
}
}
x += 1;
}
}
}
y += 1;
}
}
return Ok(bits);
}
fn module_size(left_top_black: &Vec<i32>, image: &BitMatrix) -> Result<i32, NotFoundException> {
let width: i32 = image.get_width();
let mut x: i32 = left_top_black[0];
let y: i32 = left_top_black[1];
while x < width && image.get(x, y) {
x += 1;
}
if x == width {
return Err(NotFoundException::get_not_found_instance());
}
let module_size: i32 = x - left_top_black[0];
if module_size == 0 {
return Err(NotFoundException::get_not_found_instance());
}
return Ok(module_size);
}
}
// DataMatrixWriter.java
/**
* This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
*
* @author dswitkin@google.com (Daniel Switkin)
* @author Guillaume Le Biller Added to zxing lib.
*/
pub struct DataMatrixWriter {}
impl Writer for DataMatrixWriter {
fn encode(
&self,
contents: &String,
format: &BarcodeFormat,
width: i32,
height: i32,
hints: &Map<EncodeHintType, _>,
) -> BitMatrix {
if contents.is_empty() {
return Err(IllegalArgumentException::new("Found empty contents"));
}
if format != BarcodeFormat::DATA_MATRIX {
return Err(IllegalArgumentException::new(format!(
"Can only encode DATA_MATRIX, but got {}",
format
)));
}
if width < 0 || height < 0 {
return Err(IllegalArgumentException::new(format!(
"Requested dimensions can't be negative: {}x{}",
width, height
)));
}
// Try to get force shape & min / max size
let mut shape: SymbolShapeHint = SymbolShapeHint::FORCE_NONE;
let min_size: Dimension = null;
let max_size: Dimension = null;
if hints != null {
let requested_shape: SymbolShapeHint =
hints.get(EncodeHintType::DATA_MATRIX_SHAPE) as SymbolShapeHint;
if requested_shape != null {
shape = requested_shape;
}
let requested_min_size: Dimension = hints.get(EncodeHintType::MIN_SIZE) as Dimension;
if requested_min_size != null {
min_size = requested_min_size;
}
let requested_max_size: Dimension = hints.get(EncodeHintType::MAX_SIZE) as Dimension;
if requested_max_size != null {
max_size = requested_max_size;
}
}
//1. step: Data encodation
let mut encoded: String;
let has_compaction_hint: bool = hints != null
&& hints.contains_key(EncodeHintType::DATA_MATRIX_COMPACT)
&& Boolean::parse_boolean(&hints.get(EncodeHintType::DATA_MATRIX_COMPACT).to_string());
if has_compaction_hint {
let has_g_s1_format_hint: bool = hints.contains_key(EncodeHintType::GS1_FORMAT)
&& Boolean::parse_boolean(&hints.get(EncodeHintType::GS1_FORMAT).to_string());
let mut charset: Charset = null;
let has_encoding_hint: bool = hints.contains_key(EncodeHintType::CHARACTER_SET);
if has_encoding_hint {
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,
);
} 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());
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);
//2. step: ECC generation
let codewords: String = ErrorCorrection::encode_e_c_c200(&encoded, &symbol_info);
//3. step: Module placement in Matrix
let placement: DefaultPlacement = DefaultPlacement::new(
&codewords,
&symbol_info.get_symbol_data_width(),
&symbol_info.get_symbol_data_height(),
);
placement.place();
//4. step: low-level encoding
return ::encode_low_level(placement, symbol_info, width, height);
}
}
impl DataMatrixWriter {
/**
* Encode the given symbol info to a bit matrix.
*
* @param placement The DataMatrix placement.
* @param symbolInfo The symbol info to encode.
* @return The bit matrix generated.
*/
fn encode_low_level(
placement: &DefaultPlacement,
symbol_info: &SymbolInfo,
width: i32,
height: i32,
) -> BitMatrix {
let symbol_width: i32 = symbol_info.get_symbol_data_width();
let symbol_height: i32 = symbol_info.get_symbol_data_height();
let matrix: ByteMatrix = ByteMatrix::new(
&symbol_info.get_symbol_width(),
&symbol_info.get_symbol_height(),
);
let matrix_y: i32 = 0;
{
let mut y: i32 = 0;
while y < symbol_height {
{
// Fill the top edge with alternate 0 / 1
let matrix_x: i32;
if (y % symbol_info.matrixHeight) == 0 {
matrix_x = 0;
{
let mut x: i32 = 0;
while x < symbol_info.get_symbol_width() {
{
matrix.set(matrix_x, matrix_y, (x % 2) == 0);
matrix_x += 1;
}
x += 1;
}
}
matrix_y += 1;
}
matrix_x = 0;
{
let mut x: i32 = 0;
while x < symbol_width {
{
// Fill the right edge with full 1
if (x % symbol_info.matrixWidth) == 0 {
matrix.set(matrix_x, matrix_y, true);
matrix_x += 1;
}
matrix.set(matrix_x, matrix_y, &placement.get_bit(x, y));
matrix_x += 1;
// Fill the right edge with alternate 0 / 1
if (x % symbol_info.matrixWidth) == symbol_info.matrixWidth - 1 {
matrix.set(matrix_x, matrix_y, (y % 2) == 0);
matrix_x += 1;
}
}
x += 1;
}
}
matrix_y += 1;
// Fill the bottom edge with full 1
if (y % symbol_info.matrixHeight) == symbol_info.matrixHeight - 1 {
matrix_x = 0;
{
let mut x: i32 = 0;
while x < symbol_info.get_symbol_width() {
{
matrix.set(matrix_x, matrix_y, true);
matrix_x += 1;
}
x += 1;
}
}
matrix_y += 1;
}
}
y += 1;
}
}
return ::convert_byte_matrix_to_bit_matrix(matrix, width, height);
}
/**
* Convert the ByteMatrix to BitMatrix.
*
* @param reqHeight The requested height of the image (in pixels) with the Datamatrix code
* @param reqWidth The requested width of the image (in pixels) with the Datamatrix code
* @param matrix The input matrix.
* @return The output matrix.
*/
fn convert_byte_matrix_to_bit_matrix(
matrix: &ByteMatrix,
req_width: i32,
req_height: i32,
) -> BitMatrix {
let matrix_width: i32 = matrix.get_width();
let matrix_height: i32 = matrix.get_height();
let output_width: i32 = Math::max(req_width, matrix_width);
let output_height: i32 = Math::max(req_height, matrix_height);
let multiple: i32 = Math::min(output_width / matrix_width, output_height / matrix_height);
let left_padding: i32 = (output_width - (matrix_width * multiple)) / 2;
let top_padding: i32 = (output_height - (matrix_height * multiple)) / 2;
let mut output: BitMatrix;
// remove padding if requested width and height are too small
if req_height < matrix_height || req_width < matrix_width {
left_padding = 0;
top_padding = 0;
output = BitMatrix::new(matrix_width, matrix_height);
} else {
output = BitMatrix::new(req_width, req_height);
}
output.clear();
{
let input_y: i32 = 0;
let output_y: i32 = top_padding;
while input_y < matrix_height {
{
// Write the contents of this row of the bytematrix
{
let input_x: i32 = 0;
let output_x: i32 = left_padding;
while input_x < matrix_width {
{
if matrix.get(input_x, input_y) == 1 {
output.set_region(output_x, output_y, multiple, multiple);
}
}
input_x += 1;
output_x += multiple;
}
}
}
input_y += 1;
output_y += multiple;
}
}
return output;
}
}
File diff suppressed because it is too large Load Diff
-363
View File
@@ -1,363 +0,0 @@
use crate::common::detector::WhiteRectangleDetector;
use crate::common::{BitMatrix, DetectorResult, GridSampler};
use crate::{NotFoundException, ResultPoint};
// Detector.java
/**
* <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code
* is rotated or skewed, or partially obscured.</p>
*
* @author Sean Owen
*/
pub struct Detector {
image: BitMatrix,
rectangle_detector: WhiteRectangleDetector,
}
impl Detector {
pub fn new(image: &BitMatrix) -> Result<Self, NotFoundException> {
let d: Self;
d.image = image;
d.rectangle_detector = WhiteRectangleDetector::new(image, None, None, None);
Ok(d)
}
/**
* <p>Detects a Data Matrix Code in an image.</p>
*
* @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code
* @throws NotFoundException if no Data Matrix Code can be found
*/
pub fn detect(&self) -> Result<DetectorResult, NotFoundException> {
let corner_points: Vec<ResultPoint> = self.rectangle_detector.detect();
let mut points: Vec<ResultPoint> = self.detect_solid1(&corner_points);
points = self.detect_solid2(points?);
points[3] = self.correct_top_right(points?);
if points[3] == null {
return Err(NotFoundException::get_not_found_instance());
}
points = self.shift_to_module_center(points?);
let top_left: ResultPoint = points[0];
let bottom_left: ResultPoint = points[1];
let bottom_right: ResultPoint = points[2];
let top_right: ResultPoint = points[3];
let dimension_top: i32 = self.transitions_between(&top_left, &top_right) + 1;
let dimension_right: i32 = self.transitions_between(&bottom_right, &top_right) + 1;
if (dimension_top & 0x01) == 1 {
dimension_top += 1;
}
if (dimension_right & 0x01) == 1 {
dimension_right += 1;
}
if 4 * dimension_top < 6 * dimension_right && 4 * dimension_right < 6 * dimension_top {
// The matrix is square
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,
);
return Ok(DetectorResult::new(
bits,
vec![top_left, bottom_left, bottom_right, top_right],
));
}
fn shift_point(point: &ResultPoint, to: &ResultPoint, div: i32) -> ResultPoint {
let x: f32 = (to.get_x() - point.get_x()) / (div + 1);
let y: f32 = (to.get_y() - point.get_y()) / (div + 1);
return ResultPoint::new(point.get_x() + x, point.get_y() + y);
}
fn move_away(point: &ResultPoint, from_x: f32, from_y: f32) -> ResultPoint {
let mut x: f32 = point.get_x();
let mut y: f32 = point.get_y();
if x < from_x {
x -= 1.0;
} else {
x += 1.0;
}
if y < from_y {
y -= 1.0;
} else {
y += 1.0;
}
return ResultPoint::new(x, y);
}
/**
* Detect a solid side which has minimum transition.
*/
fn detect_solid1(&self, corner_points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
// 0 2
// 1 3
let point_a: ResultPoint = corner_points[0];
let point_b: ResultPoint = corner_points[1];
let point_c: ResultPoint = corner_points[3];
let point_d: ResultPoint = corner_points[2];
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_c_d: i32 = self.transitions_between(&point_c, &point_d);
let tr_d_a: i32 = self.transitions_between(&point_d, &point_a);
// 0..3
// : :
// 1--2
let mut min: i32 = tr_a_b;
let mut points: vec![Vec<ResultPoint>; 4] = vec![point_d, point_a, point_b, point_c];
if min > tr_b_c {
min = tr_b_c;
points[0] = point_a;
points[1] = point_b;
points[2] = point_c;
points[3] = point_d;
}
if min > tr_c_d {
min = tr_c_d;
points[0] = point_b;
points[1] = point_c;
points[2] = point_d;
points[3] = point_a;
}
if min > tr_d_a {
points[0] = point_c;
points[1] = point_d;
points[2] = point_a;
points[3] = point_b;
}
return points;
}
/**
* Detect a second solid side next to first solid side.
*/
fn detect_solid2(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
// A..D
// : :
// B--C
let point_a: ResultPoint = points[0];
let point_b: ResultPoint = points[1];
let point_c: ResultPoint = points[2];
let point_d: ResultPoint = points[3];
// Transition detection on the edge is not stable.
// To safely detect, shift the points to the module center.
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_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_c_d: i32 = self.transitions_between(&point_cs, &point_d);
// 1--2
if tr_b_a < tr_c_d {
// solid sides: A-B-C
points[0] = point_a;
points[1] = point_b;
points[2] = point_c;
points[3] = point_d;
} else {
// solid sides: B-C-D
points[0] = point_b;
points[1] = point_c;
points[2] = point_d;
points[3] = point_a;
}
return points;
}
/**
* Calculates the corner position of the white top right module.
*/
fn correct_top_right(&self, points: &Vec<ResultPoint>) -> ResultPoint {
// A..D
// | :
// B--C
let point_a: ResultPoint = points[0];
let point_b: ResultPoint = points[1];
let point_c: ResultPoint = points[2];
let point_d: ResultPoint = points[3];
// shift points for safe transition detection.
let tr_top: i32 = self.transitions_between(&point_a, &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_cs: ResultPoint = ::shift_point(point_c, point_b, (tr_top + 1) * 4);
tr_top = self.transitions_between(&point_as, &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 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(&candidate2) {
return candidate2;
}
return null;
}
if !self.is_valid(&candidate2) {
return 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);
if sumc1 > sumc2 {
return candidate1;
} else {
return candidate2;
}
}
/**
* Shift the edge points to the module center.
*/
fn shift_to_module_center(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
// A..D
// | :
// B--C
let point_a: ResultPoint = points[0];
let point_b: ResultPoint = points[1];
let point_c: ResultPoint = points[2];
let point_d: ResultPoint = points[3];
// calculate pseudo dimensions
let dim_h: i32 = self.transitions_between(&point_a, &point_d) + 1;
let dim_v: i32 = self.transitions_between(&point_c, &point_d) + 1;
// shift points for safe dimension detection
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);
// calculate more precise dimensions
dim_h = self.transitions_between(&point_as, &point_d) + 1;
dim_v = self.transitions_between(&point_cs, &point_d) + 1;
if (dim_h & 0x01) == 1 {
dim_h += 1;
}
if (dim_v & 0x01) == 1 {
dim_v += 1;
}
// WhiteRectangleDetector returns points inside of the rectangle.
// I want points on the edges.
let center_x: f32 =
(point_a.get_x() + point_b.get_x() + point_c.get_x() + point_d.get_x()) / 4;
let center_y: f32 =
(point_a.get_y() + point_b.get_y() + point_c.get_y() + point_d.get_y()) / 4;
point_a = ::move_away(point_a, center_x, center_y);
point_b = ::move_away(point_b, center_x, center_y);
point_c = ::move_away(point_c, center_x, center_y);
point_d = ::move_away(point_d, center_x, center_y);
let point_bs: ResultPoint;
let point_ds: ResultPoint;
// shift points to the center of each modules
point_as = ::shift_point(point_a, point_b, dim_v * 4);
point_as = ::shift_point(point_as, point_d, dim_h * 4);
point_bs = ::shift_point(point_b, point_a, dim_v * 4);
point_bs = ::shift_point(point_bs, point_c, dim_h * 4);
point_cs = ::shift_point(point_c, point_d, dim_v * 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_ds, point_a, dim_h * 4);
return vec![point_as, point_bs, point_cs, point_ds];
}
fn is_valid(&self, p: &ResultPoint) -> bool {
return p.get_x() >= 0
&& p.get_x() <= self.image.get_width() - 1
&& p.get_y() > 0
&& p.get_y() <= self.image.get_height() - 1;
}
fn sample_grid(
image: &BitMatrix,
top_left: &ResultPoint,
bottom_left: &ResultPoint,
bottom_right: &ResultPoint,
top_right: &ResultPoint,
dimension_x: i32,
dimension_y: i32,
) -> Result<BitMatrix, Rc<Exception>> {
let sampler: GridSampler = GridSampler::get_instance();
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(),
));
}
/**
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
*/
fn transitions_between(&self, from: &ResultPoint, to: &ResultPoint) -> i32 {
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
let from_x: i32 = from.get_x() as i32;
let from_y: i32 = from.get_y() as i32;
let to_x: i32 = to.get_x() as i32;
let to_y: i32 = Math::min(self.image.get_height() - 1, to.get_y() as i32);
let steep: bool = Math::abs(to_y - from_y) > Math::abs(to_x - from_x);
if steep {
let mut temp: i32 = from_x;
from_x = from_y;
from_y = temp;
temp = to_x;
to_x = to_y;
to_y = temp;
}
let dx: i32 = Math::abs(to_x - from_x);
let dy: i32 = Math::abs(to_y - from_y);
let mut error: i32 = -dx / 2;
let ystep: i32 = if from_y < to_y { 1 } else { -1 };
let xstep: i32 = if from_x < to_x { 1 } else { -1 };
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 mut x: i32 = from_x;
let mut y: i32 = from_y;
while x != to_x {
{
let is_black: bool = self
.image
.get(if steep { y } else { x }, if steep { x } else { y });
if is_black != in_black {
transitions += 1;
in_black = is_black;
}
error += dy;
if error > 0 {
if y == to_y {
break;
}
y += ystep;
error -= dx;
}
}
x += xstep;
}
}
return transitions;
}
}
File diff suppressed because it is too large Load Diff
-102
View File
@@ -1,102 +0,0 @@
pub mod decoder;
use crate::{BarcodeFormat,BinaryBitmap,ChecksumException,DecodeHintType,FormatException,NotFoundException,Reader,XRingResultResultMetadataType,ResultPoint};
use crate::common::{BitMatrix,DecoderResult};
use crate::maxicode::decoder::Decoder;
// MaxiCodeReader.java
/**
* This implementation can detect and decode a MaxiCode in an image.
*/
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
const MATRIX_WIDTH: i32 = 30;
const MATRIX_HEIGHT: i32 = 33;
pub struct MaxiCodeReader {
decoder: Decoder
}
impl Reader for MaxiCodeReader{
/**
* Locates and decodes a MaxiCode in an image.
*
* @return a String representing the content encoded by the MaxiCode
* @throws NotFoundException if a MaxiCode cannot be found
* @throws FormatException if a MaxiCode cannot be decoded
* @throws ChecksumException if error correction fails
*/
fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, _>) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
// Note that MaxiCode reader effectively always assumes PURE_BARCODE mode
// and can't detect it in an image
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
let decoder_result: DecoderResult = self.decoder.decode(&bits, &hints);
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), NO_POINTS, BarcodeFormat::MAXICODE);
let ec_level: String = decoder_result.get_e_c_level();
if ec_level != null {
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
}
return Ok(result);
}
fn reset(&self) {
// do nothing
}
}
impl MaxiCodeReader {
pub fn new() -> Self {
Self { decoder: Decoder::new() }
}
/**
* This method detects a code in a "pure" image -- that is, pure monochrome image
* which contains only an unrotated, unskewed, image of a code, with some white border
* around it. This is a specialized method that works exceptionally fast in this special
* case.
*/
fn extract_pure_bits( image: &BitMatrix) -> Result<BitMatrix,NotFoundException> {
let enclosing_rectangle: Vec<i32> = image.get_enclosing_rectangle();
if enclosing_rectangle == null {
return Err( NotFoundException::get_not_found_instance());
}
let left: i32 = enclosing_rectangle[0];
let top: i32 = enclosing_rectangle[1];
let width: i32 = enclosing_rectangle[2];
let height: i32 = enclosing_rectangle[3];
// Now just read off the bits
let bits: BitMatrix = BitMatrix::new(MATRIX_WIDTH, MATRIX_HEIGHT);
{
let mut y: i32 = 0;
while y < MATRIX_HEIGHT {
{
let iy: i32 = Math::min(top + (y * height + height / 2) / MATRIX_HEIGHT, height - 1);
{
let mut x: i32 = 0;
while x < MATRIX_WIDTH {
{
// srowen: I don't quite understand why the formula below is necessary, but it
// can walk off the image if left + width = the right boundary. So cap it.
let ix: i32 = left + Math::min((x * width + width / 2 + (y & 0x01) * width / 2) / MATRIX_WIDTH, width - 1);
if image.get(ix, iy) {
bits.set(x, y);
}
}
x += 1;
}
}
}
y += 1;
}
}
return Ok(bits);
}
}
-450
View File
@@ -1,450 +0,0 @@
use crate::common::{BitMatrix,DecoderResult};
use crate::{FormatException,ChecksumException,DecodeHintType,FormatException};
use crate::common::reedsolomon::{GenericGF,ReedSolomonDecoder,ReedSolomonException};
// BitMatrixParser.java
/**
* @author mike32767
* @author Manuel Kasten
*/
const BITNR: vec![vec![Vec<Vec<i32>>; 30]; 33] = vec![vec![121, 120, 127, 126, 133, 132, 139, 138, 145, 144, 151, 150, 157, 156, 163, 162, 169, 168, 175, 174, 181, 180, 187, 186, 193, 192, 199, 198, -2, -2, ]
, vec![123, 122, 129, 128, 135, 134, 141, 140, 147, 146, 153, 152, 159, 158, 165, 164, 171, 170, 177, 176, 183, 182, 189, 188, 195, 194, 201, 200, 816, -3, ]
, vec![125, 124, 131, 130, 137, 136, 143, 142, 149, 148, 155, 154, 161, 160, 167, 166, 173, 172, 179, 178, 185, 184, 191, 190, 197, 196, 203, 202, 818, 817, ]
, vec![283, 282, 277, 276, 271, 270, 265, 264, 259, 258, 253, 252, 247, 246, 241, 240, 235, 234, 229, 228, 223, 222, 217, 216, 211, 210, 205, 204, 819, -3, ]
, vec![285, 284, 279, 278, 273, 272, 267, 266, 261, 260, 255, 254, 249, 248, 243, 242, 237, 236, 231, 230, 225, 224, 219, 218, 213, 212, 207, 206, 821, 820, ]
, vec![287, 286, 281, 280, 275, 274, 269, 268, 263, 262, 257, 256, 251, 250, 245, 244, 239, 238, 233, 232, 227, 226, 221, 220, 215, 214, 209, 208, 822, -3, ]
, vec![289, 288, 295, 294, 301, 300, 307, 306, 313, 312, 319, 318, 325, 324, 331, 330, 337, 336, 343, 342, 349, 348, 355, 354, 361, 360, 367, 366, 824, 823, ]
, vec![291, 290, 297, 296, 303, 302, 309, 308, 315, 314, 321, 320, 327, 326, 333, 332, 339, 338, 345, 344, 351, 350, 357, 356, 363, 362, 369, 368, 825, -3, ]
, vec![293, 292, 299, 298, 305, 304, 311, 310, 317, 316, 323, 322, 329, 328, 335, 334, 341, 340, 347, 346, 353, 352, 359, 358, 365, 364, 371, 370, 827, 826, ]
, vec![409, 408, 403, 402, 397, 396, 391, 390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43, 109, 108, 385, 384, 379, 378, 373, 372, 828, -3, ]
, vec![411, 410, 405, 404, 399, 398, 393, 392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45, 111, 110, 387, 386, 381, 380, 375, 374, 830, 829, ]
, vec![413, 412, 407, 406, 401, 400, 395, 394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46, 113, 112, 389, 388, 383, 382, 377, 376, 831, -3, ]
, vec![415, 414, 421, 420, 427, 426, 103, 102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84, 433, 432, 439, 438, 445, 444, 833, 832, ]
, vec![417, 416, 423, 422, 429, 428, 105, 104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86, 435, 434, 441, 440, 447, 446, 834, -3, ]
, vec![419, 418, 425, 424, 431, 430, 107, 106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88, 437, 436, 443, 442, 449, 448, 836, 835, ]
, vec![481, 480, 475, 474, 469, 468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52, 463, 462, 457, 456, 451, 450, 837, -3, ]
, vec![483, 482, 477, 476, 471, 470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1, 465, 464, 459, 458, 453, 452, 839, 838, ]
, vec![485, 484, 479, 478, 473, 472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42, 467, 466, 461, 460, 455, 454, 840, -3, ]
, vec![487, 486, 493, 492, 499, 498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90, 505, 504, 511, 510, 517, 516, 842, 841, ]
, vec![489, 488, 495, 494, 501, 500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92, 507, 506, 513, 512, 519, 518, 843, -3, ]
, vec![491, 490, 497, 496, 503, 502, 101, 100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94, 509, 508, 515, 514, 521, 520, 845, 844, ]
, vec![559, 558, 553, 552, 547, 546, 541, 540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66, 115, 114, 535, 534, 529, 528, 523, 522, 846, -3, ]
, vec![561, 560, 555, 554, 549, 548, 543, 542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68, 117, 116, 537, 536, 531, 530, 525, 524, 848, 847, ]
, vec![563, 562, 557, 556, 551, 550, 545, 544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70, 119, 118, 539, 538, 533, 532, 527, 526, 849, -3, ]
, vec![565, 564, 571, 570, 577, 576, 583, 582, 589, 588, 595, 594, 601, 600, 607, 606, 613, 612, 619, 618, 625, 624, 631, 630, 637, 636, 643, 642, 851, 850, ]
, vec![567, 566, 573, 572, 579, 578, 585, 584, 591, 590, 597, 596, 603, 602, 609, 608, 615, 614, 621, 620, 627, 626, 633, 632, 639, 638, 645, 644, 852, -3, ]
, vec![569, 568, 575, 574, 581, 580, 587, 586, 593, 592, 599, 598, 605, 604, 611, 610, 617, 616, 623, 622, 629, 628, 635, 634, 641, 640, 647, 646, 854, 853, ]
, vec![727, 726, 721, 720, 715, 714, 709, 708, 703, 702, 697, 696, 691, 690, 685, 684, 679, 678, 673, 672, 667, 666, 661, 660, 655, 654, 649, 648, 855, -3, ]
, vec![729, 728, 723, 722, 717, 716, 711, 710, 705, 704, 699, 698, 693, 692, 687, 686, 681, 680, 675, 674, 669, 668, 663, 662, 657, 656, 651, 650, 857, 856, ]
, vec![731, 730, 725, 724, 719, 718, 713, 712, 707, 706, 701, 700, 695, 694, 689, 688, 683, 682, 677, 676, 671, 670, 665, 664, 659, 658, 653, 652, 858, -3, ]
, vec![733, 732, 739, 738, 745, 744, 751, 750, 757, 756, 763, 762, 769, 768, 775, 774, 781, 780, 787, 786, 793, 792, 799, 798, 805, 804, 811, 810, 860, 859, ]
, vec![735, 734, 741, 740, 747, 746, 753, 752, 759, 758, 765, 764, 771, 770, 777, 776, 783, 782, 789, 788, 795, 794, 801, 800, 807, 806, 813, 812, 861, -3, ]
, vec![737, 736, 743, 742, 749, 748, 755, 754, 761, 760, 767, 766, 773, 772, 779, 778, 785, 784, 791, 790, 797, 796, 803, 802, 809, 808, 815, 814, 863, 862, ]
, ]
;
struct BitMatrixParser {
bit_matrix: BitMatrix
}
impl BitMatrixParser {
/**
* @param bitMatrix {@link BitMatrix} to parse
*/
fn new( bit_matrix: &BitMatrix) -> Self {
Self {
bit_matrix
}
}
fn read_codewords(&self) -> Vec<i8> {
let mut result: [i8; 144] = [0; 144];
let height: i32 = self.bit_matrix.get_height();
let width: i32 = self.bit_matrix.get_width();
{
let mut y: i32 = 0;
while y < height {
{
let bitnr_row: Vec<i32> = BITNR[y];
{
let mut x: i32 = 0;
while x < width {
{
let mut bit: i32 = bitnr_row[x];
if bit >= 0 && self.bit_matrix.get(x, y) {
result[bit / 6] |= (1 << (5 - (bit % 6))) as i8;
}
}
x += 1;
}
}
}
y += 1;
}
}
return result;
}
}
// DecodedBitStreamParser.java
/**
* <p>MaxiCodes can encode text or structured information as bits in one of several modes,
* with multiple character sets in one code. This class decodes the bits back into text.</p>
*
* @author mike32767
* @author Manuel Kasten
*/
const SHIFTA: char = '\u{FFF0}';
const SHIFTB: char = '\u{FFF1}';
const SHIFTC: char = '\u{FFF2}';
const SHIFTD: char = '\u{FFF3}';
const SHIFTE: char = '\u{FFF4}';
const TWOSHIFTA: char ='\u{FFF5}';
const THREESHIFTA: char ='\u{FFF6}';
const LATCHA: char = '\u{FFF7}';
const LATCHB: char = '\u{FFF8}';
const LOCK: char = '\u{FFF9}';
const ECI: char ='\u{FFFA}';
const NS: char ='\u{FFFB}';
const PAD: char = '\u{FFFC}';
const FS: char = '\u{001C}';
const GS: char = '\u{001D}';
const RS: char = '\u{001E}';
const COUNTRY_BYTES: vec![Vec<i8>; 10] = vec![53, 54, 43, 44, 45, 46, 47, 48, 37, 38, ]
;
const SERVICE_CLASS_BYTES: vec![Vec<i8>; 10] = vec![55, 56, 57, 58, 59, 60, 49, 50, 51, 52, ]
;
const POSTCODE_2_LENGTH_BYTES: vec![Vec<i8>; 6] = vec![39, 40, 41, 42, 31, 32, ]
;
const POSTCODE_2_BYTES: vec![Vec<i8>; 30] = vec![33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2, ]
;
const POSTCODE_3_BYTES: vec![vec![Vec<Vec<i8>>; 6]; 6] = vec![vec![39, 40, 41, 42, 31, 32, ]
, vec![33, 34, 35, 36, 25, 26, ]
, vec![27, 28, 29, 30, 19, 20, ]
, vec![21, 22, 23, 24, 13, 14, ]
, vec![15, 16, 17, 18, 7, 8, ]
, vec![9, 10, 11, 12, 1, 2, ]
, ]
;
const SETS: vec![Vec<String>; 5] = vec![
format!("\rABCDEFGHIJKLMNOPQRSTUVWXYZ{}{}{}{}{} {}\"#$%&'()*+,-./0123456789:{}{}{}{}{}" , ECI , FS , GS , RS , NS , PAD ,SHIFTB , SHIFTC , SHIFTD , SHIFTE , LATCHB),
format!("`abcdefghijklmnopqrstuvwxyz{}{}{}{}{}\{{}\}{}{}{}{}{}{}{}{}{}", ECI, FS, GS , RS , NS , PAD ,PAD , TWOSHIFTA , THREESHIFTA , PAD ,SHIFTA , SHIFTC , SHIFTD, SHIFTE , LATCHA),
format!("\u{00C0}\u{00C1}\u{00C2}\u{00C3}\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA{}{}{}{}{}\u00DB\u00DC\u00DD\u00DE\u00DF\u00AA\u00AC\u00B1\u00B2\u00B3\u00B5\u00B9\u00BA\u00BC\u00BD\u00BE\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089{} {}{}{}{}",ECI , FS , GS , RS , NS ,LATCHA , LOCK , SHIFTD , SHIFTE , LATCHB),
format!("\u{00E0}\u{00E1}\u{00E2}\u{00E3}\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA{}{}{}{}{}\u00FB\u00FC\u00FD\u00FE\u00FF\u00A1\u00A8\u00AB\u00AF\u00B0\u00B4\u00B7\u00B8\u00BB\u00BF\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094{} {}{}{}{}" ,ECI , FS , GS, RS , NS ,LATCHA , SHIFTC , LOCK , SHIFTE , LATCHB),
format!("\u{0000}\u{0001}\u{0002}\u{0003}\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A{}{}{}\u001B{}{}{}{}\u001F\u009F\u00A0\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A9\u00AD\u00AE\u00B6\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E{} {}{}{}{}" ,ECI , PAD, PAD , NS , FS , GS , RS , LATCHA , SHIFTC , SHIFTD , LOCK , LATCHB)
];
struct DecodedBitStreamParser {
}
impl DecodedBitStreamParser {
fn new() -> DecodedBitStreamParser {
}
fn decode( bytes: &Vec<i8>, mode: i32) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
let result: StringBuilder = StringBuilder::new(144);
match mode {
2 =>
{
}
3 =>
{
let mut postcode: String;
if mode == 2 {
let pc: i32 = ::get_post_code2(&bytes);
let ps2_length: i32 = ::get_post_code2_length(&bytes);
if ps2_length > 10 {
return Err( FormatException::get_format_instance());
}
let df: NumberFormat = DecimalFormat::new(&"0000000000".substring(0, ps2_length));
postcode = df.format(pc);
} else {
postcode = ::get_post_code3(&bytes);
}
let three_digits: NumberFormat = DecimalFormat::new("000");
let country: String = three_digits.format(&::get_country(&bytes));
let service: String = three_digits.format(&::get_service_class(&bytes));
result.append(&::get_message(&bytes, 10, 84));
if result.to_string().starts_with(format!("[)>{}01{}", RS, GS)) {
result.insert(9, format!("{}{}{}{}{}{}", postcode, GS, country, GS, service, GS));
} else {
result.insert(0, format!("{}{}{}{}{}{}", postcode, GS, country, GS, service, GS));
}
}
4 =>
{
result.append(&::get_message(&bytes, 1, 93));
}
5 =>
{
result.append(&::get_message(&bytes, 1, 77));
}
}
return Ok(DecoderResult::new(&bytes, &result.to_string(), null, &String::value_of(mode), None, None, None));
}
fn get_bit( bit: i32, bytes: &Vec<i8>) -> i32 {
bit -= 1;
return if (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 { 0 } else { 1 };
}
fn get_int( bytes: &Vec<i8>, x: &Vec<i8>) -> i32 {
let mut val: i32 = 0;
{
let mut i: i32 = 0;
while i < x.len() {
{
val += ::get_bit(x[i], &bytes) << (x.len() - i - 1);
}
i += 1;
}
}
return val;
}
fn get_country( bytes: &Vec<i8>) -> i32 {
return ::get_int(&bytes, &COUNTRY_BYTES);
}
fn get_service_class( bytes: &Vec<i8>) -> i32 {
return ::get_int(&bytes, &SERVICE_CLASS_BYTES);
}
fn get_post_code2_length( bytes: &Vec<i8>) -> i32 {
return ::get_int(&bytes, &POSTCODE_2_LENGTH_BYTES);
}
fn get_post_code2( bytes: &Vec<i8>) -> i32 {
return ::get_int(&bytes, &POSTCODE_2_BYTES);
}
fn get_post_code3( bytes: &Vec<i8>) -> String {
let sb: StringBuilder = StringBuilder::new(POSTCODE_3_BYTES.len());
for p3bytes in POSTCODE_3_BYTES {
sb.append(&SETS[0].char_at(&::get_int(&bytes, &p3bytes)));
}
return sb.to_string();
}
fn get_message( bytes: &Vec<i8>, start: i32, len: i32) -> String {
let sb: StringBuilder = StringBuilder::new();
let mut shift: i32 = -1;
let mut set: i32 = 0;
let mut lastset: i32 = 0;
{
let mut i: i32 = start;
while i < start + len {
{
let c: char = SETS[set].char_at(bytes[i]);
match c {
LATCHA =>
{
set = 0;
shift = -1;
break;
}
LATCHB =>
{
set = 1;
shift = -1;
break;
}
SHIFTA =>
{
}
SHIFTB =>
{
}
SHIFTC =>
{
}
SHIFTD =>
{
}
SHIFTE =>
{
lastset = set;
set = c - SHIFTA;
shift = 1;
break;
}
TWOSHIFTA =>
{
lastset = set;
set = 0;
shift = 2;
break;
}
THREESHIFTA =>
{
lastset = set;
set = 0;
shift = 3;
break;
}
NS =>
{
let nsval: i32 = (bytes[i += 1] << 24) + (bytes[i += 1] << 18) + (bytes[i += 1] << 12) + (bytes[i += 1] << 6) + bytes[i += 1];
sb.append(&DecimalFormat::new("000000000").format(nsval));
break;
}
LOCK =>
{
shift = -1;
break;
}
_ =>
{
sb.append(c);
}
}
if shift -= 1 == 0 {
set = lastset;
}
}
i += 1;
}
}
while sb.length() > 0 && sb.char_at(sb.length() - 1) == PAD {
sb.set_length(sb.length() - 1);
}
return sb.to_string();
}
}
// Decoder.java
/**
* <p>The main class which implements MaxiCode decoding -- as opposed to locating and extracting
* the MaxiCode from an image.</p>
*
* @author Manuel Kasten
*/
const ALL: i32 = 0;
const EVEN: i32 = 1;
const ODD: i32 = 2;
pub struct Decoder {
rs_decoder: ReedSolomonDecoder
}
impl Decoder {
pub fn new() -> Decoder {
rs_decoder = ReedSolomonDecoder::new(GenericGF::MAXICODE_FIELD_64);
}
pub fn decode_simple(&self, bits: &BitMatrix) -> Result<DecoderResult, ChecksumException+ FormatException> {
return Ok(self.decode(bits, null));
}
pub fn decode(&self, bits: &BitMatrix, hints: &Map<DecodeHintType, _>) -> Result<DecoderResult, ChecksumException+ FormatException> {
let parser: BitMatrixParser = BitMatrixParser::new(bits);
let codewords: Vec<i8> = parser.read_codewords();
self.correct_errors(&codewords, 0, 10, 10, ALL);
let mode: i32 = codewords[0] & 0x0F;
let mut datawords: Vec<i8>;
match mode {
2 =>
{
}
3 =>
{
}
4 =>
{
self.correct_errors(&codewords, 20, 84, 40, EVEN);
self.correct_errors(&codewords, 20, 84, 40, ODD);
datawords = [0; 94];
}
5 =>
{
self.correct_errors(&codewords, 20, 68, 56, EVEN);
self.correct_errors(&codewords, 20, 68, 56, ODD);
datawords = [0; 78];
}
_ =>
{
return Err( FormatException::get_format_instance());
}
}
System::arraycopy(&codewords, 0, &datawords, 0, 10);
System::arraycopy(&codewords, 20, &datawords, 10, datawords.len() - 10);
return Ok(DecodedBitStreamParser::decode(&datawords, mode));
}
fn correct_errors(&self, codeword_bytes: &Vec<i8>, start: i32, data_codewords: i32, ec_codewords: i32, mode: i32) -> Result<(), ChecksumException> {
let codewords: i32 = data_codewords + ec_codewords;
// in EVEN or ODD mode only half the codewords
let mut divisor: i32 = if mode == ALL { 1 } else { 2 };
// First read into an array of ints
let codewords_ints: [i32; codewords / divisor] = [0; codewords / divisor];
{
let mut i: i32 = 0;
while i < codewords {
{
if (mode == ALL) || (i % 2 == (mode - 1)) {
codewords_ints[i / divisor] = codeword_bytes[i + start] & 0xFF;
}
}
i += 1;
}
}
self.rs_decoder.decode(&codewords_ints, ec_codewords / divisor);
// We don't care about errors in the error-correction codewords
{
let mut i: i32 = 0;
while i < data_codewords {
{
if (mode == ALL) || (i % 2 == (mode - 1)) {
codeword_bytes[i + start] = codewords_ints[i / divisor] as i8;
}
}
i += 1;
}
}
Ok(())
}
}
-285
View File
@@ -1,285 +0,0 @@
use crate::{BinaryBitmap,DecodeHintType,NotFoundException,RXingResult,Reader,ReaderException,ResultPoint,ChecksumException,FormatException};
// ByQuadrantReader.java
/**
* This class attempts to decode a barcode from an image, not by scanning the whole image,
* but by scanning subsets of the image. This is important when there may be multiple barcodes in
* an image, and detecting a barcode may find parts of multiple barcode and fail to decode
* (e.g. QR Codes). Instead this scans the four quadrants of the image -- and also the center
* 'quadrant' to cover the case where a barcode is found in the center.
*
* @see GenericMultipleBarcodeReader
*/
pub struct ByQuadrantReader {
let delegate: Reader;
}
impl Reader for ByQuadrantReader {
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
return Ok(self.decode(image, null));
}
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
let width: i32 = image.get_width();
let height: i32 = image.get_height();
let half_width: i32 = width / 2;
let half_height: i32 = height / 2;
let tryResult1 = 0;
'try1: loop {
{
// No need to call makeAbsolute as results will be relative to original top left here
return Ok(self.delegate.decode(&image.crop(0, 0, half_width, half_height), &hints));
}
break 'try1
}
match tryResult1 {
catch ( re: &NotFoundException) {
} 0 => break
}
let tryResult1 = 0;
'try1: loop {
{
let result: Result = self.delegate.decode(&image.crop(half_width, 0, half_width, half_height), &hints);
::make_absolute(&result.get_result_points(), half_width, 0);
return Ok(result);
}
break 'try1
}
match tryResult1 {
catch ( re: &NotFoundException) {
} 0 => break
}
let tryResult1 = 0;
'try1: loop {
{
let result: Result = self.delegate.decode(&image.crop(0, half_height, half_width, half_height), &hints);
::make_absolute(&result.get_result_points(), 0, half_height);
return Ok(result);
}
break 'try1
}
match tryResult1 {
catch ( re: &NotFoundException) {
} 0 => break
}
let tryResult1 = 0;
'try1: loop {
{
let result: Result = self.delegate.decode(&image.crop(half_width, half_height, half_width, half_height), &hints);
::make_absolute(&result.get_result_points(), half_width, half_height);
return Ok(result);
}
break 'try1
}
match tryResult1 {
catch ( re: &NotFoundException) {
} 0 => break
}
let quarter_width: i32 = half_width / 2;
let quarter_height: i32 = half_height / 2;
let center: BinaryBitmap = image.crop(quarter_width, quarter_height, half_width, half_height);
let result: Result = self.delegate.decode(center, &hints);
::make_absolute(&result.get_result_points(), quarter_width, quarter_height);
return Ok(result);
}
pub fn reset(&self) {
self.delegate.reset();
}
}
impl ByQuadrantReader {
pub fn new( delegate: &Reader) -> ByQuadrantReader {
let .delegate = delegate;
}
fn make_absolute( points: &Vec<ResultPoint>, left_offset: i32, top_offset: i32) {
if points != null {
{
let mut i: i32 = 0;
while i < points.len() {
{
let relative: ResultPoint = points[i];
if relative != null {
points[i] = ResultPoint::new(relative.get_x() + left_offset, relative.get_y() + top_offset);
}
}
i += 1;
}
}
}
}
}
// MultipleBarcodeReader.java
/**
* Implementation of this interface attempt to read several barcodes from one image.
*
* @see com.google.zxing.Reader
* @author Sean Owen
*/
pub trait MultipleBarcodeReader {
fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result<Vec<Result>, Rc<Exception>> ;
fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Vec<Result>, Rc<Exception>> ;
}
// GenericMultipleBarcodeReader.java
/**
* <p>Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image.
* After one barcode is found, the areas left, above, right and below the barcode's
* {@link ResultPoint}s are scanned, recursively.</p>
*
* <p>A caller may want to also employ {@link ByQuadrantReader} when attempting to find multiple
* 2D barcodes, like QR Codes, in an image, where the presence of multiple barcodes might prevent
* detecting any one of them.</p>
*
* <p>That is, instead of passing a {@link Reader} a caller might pass
* {@code new ByQuadrantReader(reader)}.</p>
*
* @author Sean Owen
*/
const MIN_DIMENSION_TO_RECUR: i32 = 100;
const MAX_DEPTH: i32 = 4;
const EMPTY_RESULT_ARRAY: [Option<Result>; 0] = [None; 0];
pub struct GenericMultipleBarcodeReader {
let delegate: Reader;
}
impl MultipleBarcodeReader for GenericMultipleBarcodeReader {
pub fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result<Vec<Result>, Rc<Exception>> {
return Ok(self.decode_multiple(image, null));
}
pub fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Vec<Result>, Rc<Exception>> {
let results: List<Result> = ArrayList<>::new();
self.do_decode_multiple(image, &hints, &results, 0, 0, 0);
if results.is_empty() {
throw NotFoundException::get_not_found_instance();
}
return Ok(results.to_array(EMPTY_RESULT_ARRAY));
}
}
impl GenericMultipleBarcodeReader {
pub fn new( delegate: &Reader) -> GenericMultipleBarcodeReader {
let .delegate = delegate;
}
fn do_decode_multiple(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>, results: &List<Result>, x_offset: i32, y_offset: i32, current_depth: i32) {
if current_depth > MAX_DEPTH {
return;
}
let mut result: Result;
let tryResult1 = 0;
'try1: loop {
{
result = self.delegate.decode(image, &hints);
}
break 'try1
}
match tryResult1 {
catch ( ignored: &ReaderException) {
return;
} 0 => break
}
let already_found: bool = false;
for let existing_result: Result in results {
if existing_result.get_text().equals(&result.get_text()) {
already_found = true;
break;
}
}
if !already_found {
results.add(&::translate_result_points(result, x_offset, y_offset));
}
let result_points: Vec<ResultPoint> = result.get_result_points();
if result_points == null || result_points.len() == 0 {
return;
}
let width: i32 = image.get_width();
let height: i32 = image.get_height();
let min_x: f32 = width;
let min_y: f32 = height;
let max_x: f32 = 0.0f;
let max_y: f32 = 0.0f;
for let point: ResultPoint in result_points {
if point == null {
continue;
}
let x: f32 = point.get_x();
let y: f32 = point.get_y();
if x < min_x {
min_x = x;
}
if y < min_y {
min_y = y;
}
if x > max_x {
max_x = x;
}
if y > max_y {
max_y = y;
}
}
// Decode left of barcode
if min_x > MIN_DIMENSION_TO_RECUR {
self.do_decode_multiple(&image.crop(0, 0, min_x as i32, height), &hints, &results, x_offset, y_offset, current_depth + 1);
}
// Decode above barcode
if min_y > MIN_DIMENSION_TO_RECUR {
self.do_decode_multiple(&image.crop(0, 0, width, min_y as i32), &hints, &results, x_offset, y_offset, current_depth + 1);
}
// Decode right of barcode
if max_x < width - MIN_DIMENSION_TO_RECUR {
self.do_decode_multiple(&image.crop(max_x as i32, 0, width - max_x as i32, height), &hints, &results, x_offset + max_x as i32, y_offset, current_depth + 1);
}
// Decode below barcode
if max_y < height - MIN_DIMENSION_TO_RECUR {
self.do_decode_multiple(&image.crop(0, max_y as i32, width, height - max_y as i32), &hints, &results, x_offset, y_offset + max_y as i32, current_depth + 1);
}
}
fn translate_result_points( result: &Result, x_offset: i32, y_offset: i32) -> Result {
let old_result_points: Vec<ResultPoint> = result.get_result_points();
if old_result_points == null {
return result;
}
let new_result_points: [Option<ResultPoint>; old_result_points.len()] = [None; old_result_points.len()];
{
let mut i: i32 = 0;
while i < old_result_points.len() {
{
let old_point: ResultPoint = old_result_points[i];
if old_point != null {
new_result_points[i] = ResultPoint::new(old_point.get_x() + x_offset, old_point.get_y() + y_offset);
}
}
i += 1;
}
}
let new_result: Result = Result::new(&result.get_text(), &result.get_raw_bytes(), &result.get_num_bits(), new_result_points, &result.get_barcode_format(), &result.get_timestamp());
new_result.put_all_metadata(&result.get_result_metadata());
return new_result;
}
}
-129
View File
@@ -1,129 +0,0 @@
use crate::{BarcodeFormat,BinaryBitmap,DecodeHintType,NotFoundException,ReaderException,RXingResult,ResultMetadataType,ResultPoint};
use crate::common::{DecoderResult,DetectorResult};
use crate::multi::{MultipleBarcodeReader};
use crate::multi::qrcode::detector::MultiDetector;
use create::qrcode::{QRCodeReader};
use crate::multi::qrcode::decoder::QRCodeDecoderMetaData;
// QRCodeMultiReader.java
/**
* This implementation can detect and decode multiple QR Codes in an image.
*
* @author Sean Owen
* @author Hannes Erven
*/
const EMPTY_RESULT_ARRAY: [Option<Result>; 0] = [None; 0];
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
pub struct QRCodeMultiReader {
super: QRCodeReader;
}
impl MultipleBarcodeReader for QRCodeMultiReader {
pub fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result<Vec<Result>, Rc<Exception>> {
return Ok(self.decode_multiple(image, null));
}
pub fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Vec<Result>, Rc<Exception>> {
let mut results: List<Result> = ArrayList<>::new();
let detector_results: Vec<DetectorResult> = MultiDetector::new(&image.get_black_matrix()).detect_multi(&hints);
for let detector_result: DetectorResult in detector_results {
let tryResult1 = 0;
'try1: loop {
{
let decoder_result: DecoderResult = get_decoder().decode(&detector_result.get_bits(), &hints);
let points: Vec<ResultPoint> = detector_result.get_points();
// If the code was mirrored: swap the bottom-left and the top-right points.
if decoder_result.get_other() instanceof QRCodeDecoderMetaData {
(decoder_result.get_other() as QRCodeDecoderMetaData).apply_mirrored_correction(points);
}
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::QR_CODE);
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
if byte_segments != null {
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
}
let ec_level: String = decoder_result.get_e_c_level();
if ec_level != null {
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
}
if decoder_result.has_structured_append() {
result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE, &decoder_result.get_structured_append_sequence_number());
result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_PARITY, &decoder_result.get_structured_append_parity());
}
results.add(result);
}
break 'try1
}
match tryResult1 {
catch ( re: &ReaderException) {
} 0 => break
}
}
if results.is_empty() {
return Ok(EMPTY_RESULT_ARRAY);
} else {
results = ::process_structured_append(&results);
return Ok(results.to_array(EMPTY_RESULT_ARRAY));
}
}
}
impl QRCodeMultiReader {
fn process_structured_append( results: &List<Result>) -> List<Result> {
let new_results: List<Result> = ArrayList<>::new();
let sa_results: List<Result> = ArrayList<>::new();
for let result: Result in results {
if result.get_result_metadata().contains_key(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) {
sa_results.add(result);
} else {
new_results.add(result);
}
}
if sa_results.is_empty() {
return results;
}
// sort and concatenate the SA list items
Collections::sort(&sa_results, SAComparator::new());
let new_text: StringBuilder = StringBuilder::new();
let new_raw_bytes: ByteArrayOutputStream = ByteArrayOutputStream::new();
let new_byte_segment: ByteArrayOutputStream = ByteArrayOutputStream::new();
for let sa_result: Result in sa_results {
new_text.append(&sa_result.get_text());
let sa_bytes: Vec<i8> = sa_result.get_raw_bytes();
new_raw_bytes.write(&sa_bytes, 0, sa_bytes.len());
let byte_segments: Iterable<Vec<i8>> = sa_result.get_result_metadata().get(ResultMetadataType::BYTE_SEGMENTS) as Iterable<Vec<i8>>;
if byte_segments != null {
for let segment: Vec<i8> in byte_segments {
new_byte_segment.write(&segment, 0, segment.len());
}
}
}
let new_result: Result = Result::new(&new_text.to_string(), &new_raw_bytes.to_byte_array(), NO_POINTS, BarcodeFormat::QR_CODE);
if new_byte_segment.size() > 0 {
new_result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &Collections::singleton_list(&new_byte_segment.to_byte_array()));
}
new_results.add(new_result);
return new_results;
}
#[derive(Comparator<Result>, Serializable)]
struct SAComparator {
}
impl SAComparator {
pub fn compare(&self, a: &Result, b: &Result) -> i32 {
let a_number: i32 = a.get_result_metadata().get(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) as i32;
let b_number: i32 = b.get_result_metadata().get(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) as i32;
return Integer::compare(a_number, b_number);
}
}
}
-344
View File
@@ -1,344 +0,0 @@
use crate::{DecodeHintType,NotFoundException,ReaderException,ResultPointCallback};
use crate::common::{BitMatrix,DetectorResult};
use crate::qrcode::detector::{Detector,FinderPatternInfo,FinderPattern,FinderPatternFinder};
// MultiDetector.java
/**
* <p>Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code
* is rotated or skewed, or partially obscured.</p>
*
* @author Sean Owen
* @author Hannes Erven
*/
const EMPTY_DETECTOR_RESULTS: [Option<DetectorResult>; 0] = [None; 0];
pub struct MultiDetector {
super: Detector;
}
impl Detector for MultiDetector{}
impl MultiDetector {
pub fn new( image: &BitMatrix) -> MultiDetector {
super(image);
}
pub fn detect_multi(&self, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Vec<DetectorResult>, Rc<Exception>> {
let image: BitMatrix = get_image();
let result_point_callback: ResultPointCallback = if hints == null { null } else { hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback };
let finder: MultiFinderPatternFinder = MultiFinderPatternFinder::new(image, result_point_callback);
let infos: Vec<FinderPatternInfo> = finder.find_multi(&hints);
if infos.len() == 0 {
throw NotFoundException::get_not_found_instance();
}
let result: List<DetectorResult> = ArrayList<>::new();
for let info: FinderPatternInfo in infos {
let tryResult1 = 0;
'try1: loop {
{
result.add(&process_finder_pattern_info(info));
}
break 'try1
}
match tryResult1 {
catch ( e: &ReaderException) {
} 0 => break
}
}
if result.is_empty() {
return Ok(EMPTY_DETECTOR_RESULTS);
} else {
return Ok(result.to_array(EMPTY_DETECTOR_RESULTS));
}
}
}
// MultiFinderPatternFinder.java
/**
* <p>This class attempts to find finder patterns in a QR Code. Finder patterns are the square
* markers at three corners of a QR Code.</p>
*
* <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.
*
* <p>In contrast to {@link FinderPatternFinder}, this class will return an array of all possible
* QR code locations in the image.</p>
*
* <p>Use the TRY_HARDER hint to ask for a more thorough detection.</p>
*
* @author Sean Owen
* @author Hannes Erven
*/
const EMPTY_RESULT_ARRAY: [Option<FinderPatternInfo>; 0] = [None; 0];
const EMPTY_FP_ARRAY: [Option<FinderPattern>; 0] = [None; 0];
const EMPTY_FP_2D_ARRAY: [Option<FinderPattern>; 0] = [None; 0];
// TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for
// since it limits the number of regions to decode
// max. legal count of modules per QR code edge (177)
const MAX_MODULE_COUNT_PER_EDGE: f32 = 180;
// min. legal count per modules per QR code edge (11)
const MIN_MODULE_COUNT_PER_EDGE: f32 = 9;
/**
* More or less arbitrary cutoff point for determining if two finder patterns might belong
* to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their
* estimated modules sizes.
*/
const DIFF_MODSIZE_CUTOFF_PERCENT: f32 = 0.05f;
/**
* More or less arbitrary cutoff point for determining if two finder patterns might belong
* to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their
* estimated modules sizes.
*/
const DIFF_MODSIZE_CUTOFF: f32 = 0.5f;
pub struct MultiFinderPatternFinder {
super: FinderPatternFinder;
}
impl FinderPatternFinder for MultiFinderPatternFinder {}
impl MultiFinderPatternFinder {
/**
* A comparator that orders FinderPatterns by their estimated module size.
*/
#[derive(Comparator<FinderPattern>, Serializable)]
struct ModuleSizeComparator {
}
impl ModuleSizeComparator {
pub fn compare(&self, center1: &FinderPattern, center2: &FinderPattern) -> i32 {
let value: f32 = center2.get_estimated_module_size() - center1.get_estimated_module_size();
return if value < 0.0 { -1 } else { if value > 0.0 { 1 } else { 0 } };
}
}
pub fn new( image: &BitMatrix, result_point_callback: &ResultPointCallback) -> MultiFinderPatternFinder {
super(image, result_point_callback);
}
/**
* @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
* those that have been detected at least 2 times, and whose module
* size differs from the average among those patterns the least
* @throws NotFoundException if 3 such finder patterns do not exist
*/
fn select_multiple_best_patterns(&self) -> /* throws NotFoundException */Result<Vec<Vec<FinderPattern>>, Rc<Exception>> {
let possible_centers: List<FinderPattern> = ArrayList<>::new();
for let fp: FinderPattern in get_possible_centers() {
if fp.get_count() >= 2 {
possible_centers.add(fp);
}
}
let size: i32 = possible_centers.size();
if size < 3 {
// Couldn't find enough finder patterns
throw NotFoundException::get_not_found_instance();
}
/*
* Begin HE modifications to safely detect multiple codes of equal size
*/
if size == 3 {
return Ok( : vec![FinderPattern; 1] = vec![possible_centers.to_array(EMPTY_FP_ARRAY), ]
);
}
// Sort by estimated module size to speed up the upcoming checks
Collections::sort(&possible_centers, ModuleSizeComparator::new());
/*
* Now lets start: build a list of tuples of three finder locations that
* - feature similar module sizes
* - are placed in a distance so the estimated module count is within the QR specification
* - have similar distance between upper left/right and left top/bottom finder patterns
* - form a triangle with 90° angle (checked by comparing top right/bottom left distance
* with pythagoras)
*
* Note: we allow each point to be used for more than one code region: this might seem
* counterintuitive at first, but the performance penalty is not that big. At this point,
* we cannot make a good quality decision whether the three finders actually represent
* a QR code, or are just by chance laid out so it looks like there might be a QR code there.
* So, if the layout seems right, lets have the decoder try to decode.
*/
// holder for the results
let results: List<Vec<FinderPattern>> = ArrayList<>::new();
{
let mut i1: i32 = 0;
while i1 < (size - 2) {
{
let p1: FinderPattern = possible_centers.get(i1);
if p1 == null {
continue;
}
{
let mut i2: i32 = i1 + 1;
while i2 < (size - 1) {
{
let p2: FinderPattern = possible_centers.get(i2);
if p2 == null {
continue;
}
// Compare the expected module sizes; if they are really off, skip
let v_mod_size12: f32 = (p1.get_estimated_module_size() - p2.get_estimated_module_size()) / Math::min(&p1.get_estimated_module_size(), &p2.get_estimated_module_size());
let v_mod_size12_a: f32 = Math::abs(p1.get_estimated_module_size() - p2.get_estimated_module_size());
if v_mod_size12_a > DIFF_MODSIZE_CUTOFF && v_mod_size12 >= DIFF_MODSIZE_CUTOFF_PERCENT {
// any more interesting elements for the given p1.
break;
}
{
let mut i3: i32 = i2 + 1;
while i3 < size {
{
let p3: FinderPattern = possible_centers.get(i3);
if p3 == null {
continue;
}
// Compare the expected module sizes; if they are really off, skip
let v_mod_size23: f32 = (p2.get_estimated_module_size() - p3.get_estimated_module_size()) / Math::min(&p2.get_estimated_module_size(), &p3.get_estimated_module_size());
let v_mod_size23_a: f32 = Math::abs(p2.get_estimated_module_size() - p3.get_estimated_module_size());
if v_mod_size23_a > DIFF_MODSIZE_CUTOFF && v_mod_size23 >= DIFF_MODSIZE_CUTOFF_PERCENT {
// any more interesting elements for the given p1.
break;
}
let test: vec![Vec<FinderPattern>; 3] = vec![p1, p2, p3, ]
;
ResultPoint::order_best_patterns(test);
// Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal
let info: FinderPatternInfo = FinderPatternInfo::new(test);
let d_a: f32 = ResultPoint::distance(&info.get_top_left(), &info.get_bottom_left());
let d_c: f32 = ResultPoint::distance(&info.get_top_right(), &info.get_bottom_left());
let d_b: f32 = ResultPoint::distance(&info.get_top_left(), &info.get_top_right());
// Check the sizes
let estimated_module_count: f32 = (d_a + d_b) / (p1.get_estimated_module_size() * 2.0f);
if estimated_module_count > MAX_MODULE_COUNT_PER_EDGE || estimated_module_count < MIN_MODULE_COUNT_PER_EDGE {
continue;
}
// Calculate the difference of the edge lengths in percent
let v_a_b_b_c: f32 = Math::abs((d_a - d_b) / Math::min(d_a, d_b));
if v_a_b_b_c >= 0.1f {
continue;
}
// Calculate the diagonal length by assuming a 90° angle at topleft
let d_cpy: f32 = Math::sqrt(d_a as f64 * d_a + d_b as f64 * d_b) as f32;
// Compare to the real distance in %
let v_py_c: f32 = Math::abs((d_c - d_cpy) / Math::min(d_c, d_cpy));
if v_py_c >= 0.1f {
continue;
}
// All tests passed!
results.add(test);
}
i3 += 1;
}
}
}
i2 += 1;
}
}
}
i1 += 1;
}
}
if !results.is_empty() {
return Ok(results.to_array(EMPTY_FP_2D_ARRAY));
}
// Nothing found!
throw NotFoundException::get_not_found_instance();
}
pub fn find_multi(&self, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Vec<FinderPatternInfo>, Rc<Exception>> {
let try_harder: bool = hints != null && hints.contains_key(DecodeHintType::TRY_HARDER);
let image: BitMatrix = get_image();
let max_i: i32 = image.get_height();
let max_j: i32 = image.get_width();
// We are looking for black/white/black/white/black modules in
// 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
// Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
// image, and then account for the center being 3 modules in size. This gives the smallest
// number of pixels the center could be, so skip this often. When trying harder, look for all
// QR versions regardless of how dense they are.
let i_skip: i32 = (3 * max_i) / (4 * MAX_MODULES);
if i_skip < MIN_SKIP || try_harder {
i_skip = MIN_SKIP;
}
let state_count: [i32; 5] = [0; 5];
{
let mut i: i32 = i_skip - 1;
while i < max_i {
{
// Get a row of black/white values
do_clear_counts(&state_count);
let current_state: i32 = 0;
{
let mut j: i32 = 0;
while j < max_j {
{
if image.get(j, i) {
// Black pixel
if (current_state & 1) == 1 {
// Counting white pixels
current_state += 1;
}
state_count[current_state] += 1;
} else {
// White pixel
if (current_state & 1) == 0 {
// Counting black pixels
if current_state == 4 {
// A winner?
if found_pattern_cross(&state_count) && handle_possible_center(&state_count, i, j) {
// Yes
// Clear state to start looking again
current_state = 0;
do_clear_counts(&state_count);
} else {
// No, shift counts back by two
do_shift_counts2(&state_count);
current_state = 3;
}
} else {
state_count[current_state += 1] += 1;
}
} else {
// Counting white pixels
state_count[current_state] += 1;
}
}
}
j += 1;
}
}
if found_pattern_cross(&state_count) {
handle_possible_center(&state_count, i, max_j);
}
}
i += i_skip;
}
}
// for i=iSkip-1 ...
let pattern_info: Vec<Vec<FinderPattern>> = self.select_multiple_best_patterns();
let result: List<FinderPatternInfo> = ArrayList<>::new();
for let pattern: Vec<FinderPattern> in pattern_info {
ResultPoint::order_best_patterns(pattern);
result.add(FinderPatternInfo::new(pattern));
}
if result.is_empty() {
return Ok(EMPTY_RESULT_ARRAY);
} else {
return Ok(result.to_array(EMPTY_RESULT_ARRAY));
}
}
}
-6246
View File
File diff suppressed because it is too large Load Diff
-959
View File
@@ -1,959 +0,0 @@
use crate::{NotFoundException,ResultPoint,BarcodeFormat,DecodeHintType,NotFoundException,RXingResult,ResultMetadataType,ResultPoint,ResultPointCallback};
use crate::common::BitArray;
use crate::common::detector::{MathUtils};
use crate::oned::{OneDReader};
// NEW FILE: abstract_r_s_s_reader.rs
/*
* Copyright (C) 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::oned::rss;
/**
* Superclass of {@link OneDReader} implementations that read barcodes in the RSS family
* of formats.
*/
const MAX_AVG_VARIANCE: f32 = 0.2f;
const MAX_INDIVIDUAL_VARIANCE: f32 = 0.45f;
const MIN_FINDER_PATTERN_RATIO: f32 = 9.5f / 12.0f;
const MAX_FINDER_PATTERN_RATIO: f32 = 12.5f / 14.0f;
pub struct AbstractRSSReader {
super: OneDReader;
let decode_finder_counters: Vec<i32>;
let data_character_counters: Vec<i32>;
let odd_rounding_errors: Vec<f32>;
let even_rounding_errors: Vec<f32>;
let odd_counts: Vec<i32>;
let even_counts: Vec<i32>;
}
impl AbstractRSSReader {
pub fn new() -> AbstractRSSReader {
decode_finder_counters = : [i32; 4] = [0; 4];
data_character_counters = : [i32; 8] = [0; 8];
odd_rounding_errors = : [f32; 4.0] = [0.0; 4.0];
even_rounding_errors = : [f32; 4.0] = [0.0; 4.0];
odd_counts = : [i32; data_character_counters.len() / 2] = [0; data_character_counters.len() / 2];
even_counts = : [i32; data_character_counters.len() / 2] = [0; data_character_counters.len() / 2];
}
pub fn get_decode_finder_counters(&self) -> Vec<i32> {
return self.decode_finder_counters;
}
pub fn get_data_character_counters(&self) -> Vec<i32> {
return self.data_character_counters;
}
pub fn get_odd_rounding_errors(&self) -> Vec<f32> {
return self.odd_rounding_errors;
}
pub fn get_even_rounding_errors(&self) -> Vec<f32> {
return self.even_rounding_errors;
}
pub fn get_odd_counts(&self) -> Vec<i32> {
return self.odd_counts;
}
pub fn get_even_counts(&self) -> Vec<i32> {
return self.even_counts;
}
pub fn parse_finder_value( counters: &Vec<i32>, finder_patterns: &Vec<Vec<i32>>) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
{
let mut value: i32 = 0;
while value < finder_patterns.len() {
{
if pattern_match_variance(&counters, finder_patterns[value], MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE {
return Ok(value);
}
}
value += 1;
}
}
throw NotFoundException::get_not_found_instance();
}
/**
* @param array values to sum
* @return sum of values
* @deprecated call {@link MathUtils#sum(int[])}
*/
pub fn count( array: &Vec<i32>) -> i32 {
return MathUtils::sum(&array);
}
pub fn increment( array: &Vec<i32>, errors: &Vec<f32>) {
let mut index: i32 = 0;
let biggest_error: f32 = errors[0];
{
let mut i: i32 = 1;
while i < array.len() {
{
if errors[i] > biggest_error {
biggest_error = errors[i];
index = i;
}
}
i += 1;
}
}
array[index] += 1;
}
pub fn decrement( array: &Vec<i32>, errors: &Vec<f32>) {
let mut index: i32 = 0;
let biggest_error: f32 = errors[0];
{
let mut i: i32 = 1;
while i < array.len() {
{
if errors[i] < biggest_error {
biggest_error = errors[i];
index = i;
}
}
i += 1;
}
}
array[index] -= 1;
}
pub fn is_finder_pattern( counters: &Vec<i32>) -> bool {
let first_two_sum: i32 = counters[0] + counters[1];
let sum: i32 = first_two_sum + counters[2] + counters[3];
let ratio: f32 = first_two_sum / sum as f32;
if ratio >= MIN_FINDER_PATTERN_RATIO && ratio <= MAX_FINDER_PATTERN_RATIO {
// passes ratio test in spec, but see if the counts are unreasonable
let min_counter: i32 = Integer::MAX_VALUE;
let max_counter: i32 = Integer::MIN_VALUE;
for let counter: i32 in counters {
if counter > max_counter {
max_counter = counter;
}
if counter < min_counter {
min_counter = counter;
}
}
return max_counter < 10 * min_counter;
}
return false;
}
}
// NEW FILE: data_character.rs
/*
* Copyright 2009 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::oned::rss;
/**
* Encapsulates a since character value in an RSS barcode, including its checksum information.
*/
pub struct DataCharacter {
let value: i32;
let checksum_portion: i32;
}
impl DataCharacter {
pub fn new( value: i32, checksum_portion: i32) -> DataCharacter {
let .value = value;
let .checksumPortion = checksum_portion;
}
pub fn get_value(&self) -> i32 {
return self.value;
}
pub fn get_checksum_portion(&self) -> i32 {
return self.checksum_portion;
}
pub fn to_string(&self) -> String {
return format!("{}({})", self.value, self.checksum_portion);
}
pub fn equals(&self, o: &Object) -> bool {
if !(o instanceof DataCharacter) {
return false;
}
let that: DataCharacter = o as DataCharacter;
return self.value == that.value && self.checksum_portion == that.checksumPortion;
}
pub fn hash_code(&self) -> i32 {
return self.value ^ self.checksum_portion;
}
}
// NEW FILE: finder_pattern.rs
/*
* Copyright 2009 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::oned::rss;
/**
* Encapsulates an RSS barcode finder pattern, including its start/end position and row.
*/
pub struct FinderPattern {
let value: i32;
let start_end: Vec<i32>;
let result_points: Vec<ResultPoint>;
}
impl FinderPattern {
pub fn new( value: i32, start_end: &Vec<i32>, start: i32, end: i32, row_number: i32) -> FinderPattern {
let .value = value;
let .startEnd = start_end;
let .resultPoints = : vec![ResultPoint; 2] = vec![ResultPoint::new(start, row_number), ResultPoint::new(end, row_number), ]
;
}
pub fn get_value(&self) -> i32 {
return self.value;
}
pub fn get_start_end(&self) -> Vec<i32> {
return self.start_end;
}
pub fn get_result_points(&self) -> Vec<ResultPoint> {
return self.result_points;
}
pub fn equals(&self, o: &Object) -> bool {
if !(o instanceof FinderPattern) {
return false;
}
let that: FinderPattern = o as FinderPattern;
return self.value == that.value;
}
pub fn hash_code(&self) -> i32 {
return self.value;
}
}
// NEW FILE: pair.rs
/*
* Copyright 2009 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::oned::rss;
struct Pair {
super: DataCharacter;
let finder_pattern: FinderPattern;
let mut count: i32;
}
impl Pair {
fn new( value: i32, checksum_portion: i32, finder_pattern: &FinderPattern) -> Pair {
super(value, checksum_portion);
let .finderPattern = finder_pattern;
}
fn get_finder_pattern(&self) -> FinderPattern {
return self.finder_pattern;
}
fn get_count(&self) -> i32 {
return self.count;
}
fn increment_count(&self) {
self.count += 1;
}
}
// NEW FILE: r_s_s14_reader.rs
/*
* Copyright 2009 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::oned::rss;
/**
* Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006.
*/
const OUTSIDE_EVEN_TOTAL_SUBSET: vec![Vec<i32>; 5] = vec![1, 10, 34, 70, 126, ]
;
const INSIDE_ODD_TOTAL_SUBSET: vec![Vec<i32>; 4] = vec![4, 20, 48, 81, ]
;
const OUTSIDE_GSUM: vec![Vec<i32>; 5] = vec![0, 161, 961, 2015, 2715, ]
;
const INSIDE_GSUM: vec![Vec<i32>; 4] = vec![0, 336, 1036, 1516, ]
;
const OUTSIDE_ODD_WIDEST: vec![Vec<i32>; 5] = vec![8, 6, 4, 3, 1, ]
;
const INSIDE_ODD_WIDEST: vec![Vec<i32>; 4] = vec![2, 4, 6, 8, ]
;
const FINDER_PATTERNS: vec![vec![Vec<Vec<i32>>; 4]; 9] = vec![vec![3, 8, 2, 1, ]
, vec![3, 5, 5, 1, ]
, vec![3, 3, 7, 1, ]
, vec![3, 1, 9, 1, ]
, vec![2, 7, 4, 1, ]
, vec![2, 5, 6, 1, ]
, vec![2, 3, 8, 1, ]
, vec![1, 5, 7, 1, ]
, vec![1, 3, 9, 1, ]
, ]
;
pub struct RSS14Reader {
super: AbstractRSSReader;
let possible_left_pairs: List<Pair>;
let possible_right_pairs: List<Pair>;
}
impl RSS14Reader {
pub fn new() -> RSS14Reader {
possible_left_pairs = ArrayList<>::new();
possible_right_pairs = ArrayList<>::new();
}
pub fn decode_row(&self, row_number: i32, row: &BitArray, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Result, Rc<Exception>> {
let left_pair: Pair = self.decode_pair(row, false, row_number, &hints);
::add_or_tally(&self.possible_left_pairs, left_pair);
row.reverse();
let right_pair: Pair = self.decode_pair(row, true, row_number, &hints);
::add_or_tally(&self.possible_right_pairs, right_pair);
row.reverse();
for let left: Pair in self.possible_left_pairs {
if left.get_count() > 1 {
for let right: Pair in self.possible_right_pairs {
if right.get_count() > 1 && ::check_checksum(left, right) {
return Ok(::construct_result(left, right));
}
}
}
}
throw NotFoundException::get_not_found_instance();
}
fn add_or_tally( possible_pairs: &Collection<Pair>, pair: &Pair) {
if pair == null {
return;
}
let mut found: bool = false;
for let other: Pair in possible_pairs {
if other.get_value() == pair.get_value() {
other.increment_count();
found = true;
break;
}
}
if !found {
possible_pairs.add(pair);
}
}
pub fn reset(&self) {
self.possible_left_pairs.clear();
self.possible_right_pairs.clear();
}
fn construct_result( left_pair: &Pair, right_pair: &Pair) -> Result {
let symbol_value: i64 = 4537077 * left_pair.get_value() + right_pair.get_value();
let text: String = String::value_of(symbol_value);
let buffer: StringBuilder = StringBuilder::new(14);
{
let mut i: i32 = 13 - text.length();
while i > 0 {
{
buffer.append('0');
}
i -= 1;
}
}
buffer.append(&text);
let check_digit: i32 = 0;
{
let mut i: i32 = 0;
while i < 13 {
{
let digit: i32 = buffer.char_at(i) - '0';
check_digit += if (i & 0x01) == 0 { 3 * digit } else { digit };
}
i += 1;
}
}
check_digit = 10 - (check_digit % 10);
if check_digit == 10 {
check_digit = 0;
}
buffer.append(check_digit);
let left_points: Vec<ResultPoint> = left_pair.get_finder_pattern().get_result_points();
let right_points: Vec<ResultPoint> = right_pair.get_finder_pattern().get_result_points();
let result: Result = Result::new(&buffer.to_string(), null, : vec![ResultPoint; 4] = vec![left_points[0], left_points[1], right_points[0], right_points[1], ]
, BarcodeFormat::RSS_14);
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, "]e0");
return result;
}
fn check_checksum( left_pair: &Pair, right_pair: &Pair) -> bool {
let check_value: i32 = (left_pair.get_checksum_portion() + 16 * right_pair.get_checksum_portion()) % 79;
let target_check_value: i32 = 9 * left_pair.get_finder_pattern().get_value() + right_pair.get_finder_pattern().get_value();
if target_check_value > 72 {
target_check_value -= 1;
}
if target_check_value > 8 {
target_check_value -= 1;
}
return check_value == target_check_value;
}
fn decode_pair(&self, row: &BitArray, right: bool, row_number: i32, hints: &Map<DecodeHintType, ?>) -> Pair {
let tryResult1 = 0;
'try1: loop {
{
let start_end: Vec<i32> = self.find_finder_pattern(row, right);
let pattern: FinderPattern = self.parse_found_finder_pattern(row, row_number, right, &start_end);
let result_point_callback: ResultPointCallback = if hints == null { null } else { hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback };
if result_point_callback != null {
start_end = pattern.get_start_end();
let mut center: f32 = (start_end[0] + start_end[1] - 1.0) / 2.0f;
if right {
// row is actually reversed
center = row.get_size() - 1.0 - center;
}
result_point_callback.found_possible_result_point(ResultPoint::new(center, row_number));
}
let outside: DataCharacter = self.decode_data_character(row, pattern, true);
let inside: DataCharacter = self.decode_data_character(row, pattern, false);
return Pair::new(1597 * outside.get_value() + inside.get_value(), outside.get_checksum_portion() + 4 * inside.get_checksum_portion(), pattern);
}
break 'try1
}
match tryResult1 {
catch ( ignored: &NotFoundException) {
return null;
} 0 => break
}
}
fn decode_data_character(&self, row: &BitArray, pattern: &FinderPattern, outside_char: bool) -> /* throws NotFoundException */Result<DataCharacter, Rc<Exception>> {
let mut counters: Vec<i32> = get_data_character_counters();
Arrays::fill(&counters, 0);
if outside_char {
record_pattern_in_reverse(row, pattern.get_start_end()[0], &counters);
} else {
record_pattern(row, pattern.get_start_end()[1], &counters);
// reverse it
{
let mut i: i32 = 0, let mut j: i32 = counters.len() - 1;
while i < j {
{
let temp: i32 = counters[i];
counters[i] = counters[j];
counters[j] = temp;
}
i += 1;
j -= 1;
}
}
}
let num_modules: i32 = if outside_char { 16 } else { 15 };
let element_width: f32 = MathUtils::sum(&counters) / num_modules as f32;
let odd_counts: Vec<i32> = self.get_odd_counts();
let even_counts: Vec<i32> = self.get_even_counts();
let odd_rounding_errors: Vec<f32> = self.get_odd_rounding_errors();
let even_rounding_errors: Vec<f32> = self.get_even_rounding_errors();
{
let mut i: i32 = 0;
while i < counters.len() {
{
let value: f32 = counters[i] / element_width;
// Round
let mut count: i32 = (value + 0.5f) as i32;
if count < 1 {
count = 1;
} else if count > 8 {
count = 8;
}
let mut offset: i32 = i / 2;
if (i & 0x01) == 0 {
odd_counts[offset] = count;
odd_rounding_errors[offset] = value - count;
} else {
even_counts[offset] = count;
even_rounding_errors[offset] = value - count;
}
}
i += 1;
}
}
self.adjust_odd_even_counts(outside_char, num_modules);
let odd_sum: i32 = 0;
let odd_checksum_portion: i32 = 0;
{
let mut i: i32 = odd_counts.len() - 1;
while i >= 0 {
{
odd_checksum_portion *= 9;
odd_checksum_portion += odd_counts[i];
odd_sum += odd_counts[i];
}
i -= 1;
}
}
let even_checksum_portion: i32 = 0;
let even_sum: i32 = 0;
{
let mut i: i32 = even_counts.len() - 1;
while i >= 0 {
{
even_checksum_portion *= 9;
even_checksum_portion += even_counts[i];
even_sum += even_counts[i];
}
i -= 1;
}
}
let checksum_portion: i32 = odd_checksum_portion + 3 * even_checksum_portion;
if outside_char {
if (odd_sum & 0x01) != 0 || odd_sum > 12 || odd_sum < 4 {
throw NotFoundException::get_not_found_instance();
}
let group: i32 = (12 - odd_sum) / 2;
let odd_widest: i32 = OUTSIDE_ODD_WIDEST[group];
let even_widest: i32 = 9 - odd_widest;
let v_odd: i32 = RSSUtils::get_r_s_svalue(&odd_counts, odd_widest, false);
let v_even: i32 = RSSUtils::get_r_s_svalue(&even_counts, even_widest, true);
let t_even: i32 = OUTSIDE_EVEN_TOTAL_SUBSET[group];
let g_sum: i32 = OUTSIDE_GSUM[group];
return Ok(DataCharacter::new(v_odd * t_even + v_even + g_sum, checksum_portion));
} else {
if (even_sum & 0x01) != 0 || even_sum > 10 || even_sum < 4 {
throw NotFoundException::get_not_found_instance();
}
let group: i32 = (10 - even_sum) / 2;
let odd_widest: i32 = INSIDE_ODD_WIDEST[group];
let even_widest: i32 = 9 - odd_widest;
let v_odd: i32 = RSSUtils::get_r_s_svalue(&odd_counts, odd_widest, true);
let v_even: i32 = RSSUtils::get_r_s_svalue(&even_counts, even_widest, false);
let t_odd: i32 = INSIDE_ODD_TOTAL_SUBSET[group];
let g_sum: i32 = INSIDE_GSUM[group];
return Ok(DataCharacter::new(v_even * t_odd + v_odd + g_sum, checksum_portion));
}
}
fn find_finder_pattern(&self, row: &BitArray, right_finder_pattern: bool) -> /* throws NotFoundException */Result<Vec<i32>, Rc<Exception>> {
let mut counters: Vec<i32> = get_decode_finder_counters();
counters[0] = 0;
counters[1] = 0;
counters[2] = 0;
counters[3] = 0;
let width: i32 = row.get_size();
let is_white: bool = false;
let row_offset: i32 = 0;
while row_offset < width {
is_white = !row.get(row_offset);
if right_finder_pattern == is_white {
// Will encounter white first when searching for right finder pattern
break;
}
row_offset += 1;
}
let counter_position: i32 = 0;
let pattern_start: i32 = row_offset;
{
let mut x: i32 = row_offset;
while x < width {
{
if row.get(x) != is_white {
counters[counter_position] += 1;
} else {
if counter_position == 3 {
if is_finder_pattern(&counters) {
return Ok( : vec![i32; 2] = vec![pattern_start, x, ]
);
}
pattern_start += counters[0] + counters[1];
counters[0] = counters[2];
counters[1] = counters[3];
counters[2] = 0;
counters[3] = 0;
counter_position -= 1;
} else {
counter_position += 1;
}
counters[counter_position] = 1;
is_white = !is_white;
}
}
x += 1;
}
}
throw NotFoundException::get_not_found_instance();
}
fn parse_found_finder_pattern(&self, row: &BitArray, row_number: i32, right: bool, start_end: &Vec<i32>) -> /* throws NotFoundException */Result<FinderPattern, Rc<Exception>> {
// Actually we found elements 2-5
let first_is_black: bool = row.get(start_end[0]);
let first_element_start: i32 = start_end[0] - 1;
// Locate element 1
while first_element_start >= 0 && first_is_black != row.get(first_element_start) {
first_element_start -= 1;
}
first_element_start += 1;
let first_counter: i32 = start_end[0] - first_element_start;
// Make 'counters' hold 1-4
let mut counters: Vec<i32> = get_decode_finder_counters();
System::arraycopy(&counters, 0, &counters, 1, counters.len() - 1);
counters[0] = first_counter;
let value: i32 = parse_finder_value(&counters, &FINDER_PATTERNS);
let mut start: i32 = first_element_start;
let mut end: i32 = start_end[1];
if right {
// row is actually reversed
start = row.get_size() - 1 - start;
end = row.get_size() - 1 - end;
}
return Ok(FinderPattern::new(value, : vec![i32; 2] = vec![first_element_start, start_end[1], ]
, start, end, row_number));
}
fn adjust_odd_even_counts(&self, outside_char: bool, num_modules: i32) -> /* throws NotFoundException */Result<Void, Rc<Exception>> {
let odd_sum: i32 = MathUtils::sum(&get_odd_counts());
let even_sum: i32 = MathUtils::sum(&get_even_counts());
let increment_odd: bool = false;
let decrement_odd: bool = false;
let increment_even: bool = false;
let decrement_even: bool = false;
if outside_char {
if odd_sum > 12 {
decrement_odd = true;
} else if odd_sum < 4 {
increment_odd = true;
}
if even_sum > 12 {
decrement_even = true;
} else if even_sum < 4 {
increment_even = true;
}
} else {
if odd_sum > 11 {
decrement_odd = true;
} else if odd_sum < 5 {
increment_odd = true;
}
if even_sum > 10 {
decrement_even = true;
} else if even_sum < 4 {
increment_even = true;
}
}
let mismatch: i32 = odd_sum + even_sum - num_modules;
let odd_parity_bad: bool = (odd_sum & 0x01) == ( if outside_char { 1 } else { 0 });
let even_parity_bad: bool = (even_sum & 0x01) == 1;
/*if (mismatch == 2) {
if (!(oddParityBad && evenParityBad)) {
throw ReaderException.getInstance();
}
decrementOdd = true;
decrementEven = true;
} else if (mismatch == -2) {
if (!(oddParityBad && evenParityBad)) {
throw ReaderException.getInstance();
}
incrementOdd = true;
incrementEven = true;
} else */
match mismatch {
1 =>
{
if odd_parity_bad {
if even_parity_bad {
throw NotFoundException::get_not_found_instance();
}
decrement_odd = true;
} else {
if !even_parity_bad {
throw NotFoundException::get_not_found_instance();
}
decrement_even = true;
}
break;
}
-1 =>
{
if odd_parity_bad {
if even_parity_bad {
throw NotFoundException::get_not_found_instance();
}
increment_odd = true;
} else {
if !even_parity_bad {
throw NotFoundException::get_not_found_instance();
}
increment_even = true;
}
break;
}
0 =>
{
if odd_parity_bad {
if !even_parity_bad {
throw NotFoundException::get_not_found_instance();
}
// Both bad
if odd_sum < even_sum {
increment_odd = true;
decrement_even = true;
} else {
decrement_odd = true;
increment_even = true;
}
} else {
if even_parity_bad {
throw NotFoundException::get_not_found_instance();
}
// Nothing to do!
}
break;
}
_ =>
{
throw NotFoundException::get_not_found_instance();
}
}
if increment_odd {
if decrement_odd {
throw NotFoundException::get_not_found_instance();
}
increment(&get_odd_counts(), &get_odd_rounding_errors());
}
if decrement_odd {
decrement(&get_odd_counts(), &get_odd_rounding_errors());
}
if increment_even {
if decrement_even {
throw NotFoundException::get_not_found_instance();
}
increment(&get_even_counts(), &get_odd_rounding_errors());
}
if decrement_even {
decrement(&get_even_counts(), &get_even_rounding_errors());
}
}
}
// NEW FILE: r_s_s_utils.rs
/*
* Copyright 2009 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::oned::rss;
/** Adapted from listings in ISO/IEC 24724 Appendix B and Appendix G. */
pub struct RSSUtils {
}
impl RSSUtils {
fn new() -> RSSUtils {
}
pub fn get_r_s_svalue( widths: &Vec<i32>, max_width: i32, no_narrow: bool) -> i32 {
let mut n: i32 = 0;
for let width: i32 in widths {
n += width;
}
let mut val: i32 = 0;
let narrow_mask: i32 = 0;
let elements: i32 = widths.len();
{
let mut bar: i32 = 0;
while bar < elements - 1 {
{
let elm_width: i32;
{
elm_width = 1;
narrow_mask |= 1 << bar;
while elm_width < widths[bar] {
{
let sub_val: i32 = ::combins(n - elm_width - 1, elements - bar - 2);
if no_narrow && (narrow_mask == 0) && (n - elm_width - (elements - bar - 1) >= elements - bar - 1) {
sub_val -= ::combins(n - elm_width - (elements - bar), elements - bar - 2);
}
if elements - bar - 1 > 1 {
let less_val: i32 = 0;
{
let mxw_element: i32 = n - elm_width - (elements - bar - 2);
while mxw_element > max_width {
{
less_val += ::combins(n - elm_width - mxw_element - 1, elements - bar - 3);
}
mxw_element -= 1;
}
}
sub_val -= less_val * (elements - 1 - bar);
} else if n - elm_width > max_width {
sub_val -= 1;
}
val += sub_val;
}
elm_width += 1;
narrow_mask &= ~(1 << bar);
}
}
n -= elm_width;
}
bar += 1;
}
}
return val;
}
fn combins( n: i32, r: i32) -> i32 {
let max_denom: i32;
let min_denom: i32;
if n - r > r {
min_denom = r;
max_denom = n - r;
} else {
min_denom = n - r;
max_denom = r;
}
let mut val: i32 = 1;
let mut j: i32 = 1;
{
let mut i: i32 = n;
while i > max_denom {
{
val *= i;
if j <= min_denom {
val /= j;
j += 1;
}
}
i -= 1;
}
}
while j <= min_denom {
val /= j;
j += 1;
}
return val;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-570
View File
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
-630
View File
@@ -1,630 +0,0 @@
use crate::ChecksumException;
use crate::pdf417::PDF417Common;
// NEW FILE: error_correction.rs
/*
* Copyright 2012 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::pdf417::decoder::ec;
/**
* <p>PDF417 error correction implementation.</p>
*
* <p>This <a href="http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction#Example">example</a>
* is quite useful in understanding the algorithm.</p>
*
* @author Sean Owen
* @see com.google.zxing.common.reedsolomon.ReedSolomonDecoder
*/
pub struct ErrorCorrection {
let mut field: ModulusGF;
}
impl ErrorCorrection {
pub fn new() -> ErrorCorrection {
let .field = ModulusGF::PDF417_GF;
}
/**
* @param received received codewords
* @param numECCodewords number of those codewords used for EC
* @param erasures location of erasures
* @return number of errors
* @throws ChecksumException if errors cannot be corrected, maybe because of too many errors
*/
pub fn decode(&self, received: &Vec<i32>, num_e_c_codewords: i32, erasures: &Vec<i32>) -> /* throws ChecksumException */Result<i32, Rc<Exception>> {
let poly: ModulusPoly = ModulusPoly::new(self.field, &received);
const S: [i32; num_e_c_codewords] = [0; num_e_c_codewords];
let mut error: bool = false;
{
let mut i: i32 = num_e_c_codewords;
while i > 0 {
{
let eval: i32 = poly.evaluate_at(&self.field.exp(i));
S[num_e_c_codewords - i] = eval;
if eval != 0 {
error = true;
}
}
i -= 1;
}
}
if !error {
return Ok(0);
}
let known_errors: ModulusPoly = self.field.get_one();
if erasures != null {
for let erasure: i32 in erasures {
let b: i32 = self.field.exp(received.len() - 1 - erasure);
// Add (1 - bx) term:
let term: ModulusPoly = ModulusPoly::new(self.field, : vec![i32; 2] = vec![self.field.subtract(0, b), 1, ]
);
known_errors = known_errors.multiply(term);
}
}
let syndrome: ModulusPoly = ModulusPoly::new(self.field, &S);
//syndrome = syndrome.multiply(knownErrors);
let sigma_omega: Vec<ModulusPoly> = self.run_euclidean_algorithm(&self.field.build_monomial(num_e_c_codewords, 1), syndrome, num_e_c_codewords);
let sigma: ModulusPoly = sigma_omega[0];
let omega: ModulusPoly = sigma_omega[1];
//sigma = sigma.multiply(knownErrors);
let error_locations: Vec<i32> = self.find_error_locations(sigma);
let error_magnitudes: Vec<i32> = self.find_error_magnitudes(omega, sigma, &error_locations);
{
let mut i: i32 = 0;
while i < error_locations.len() {
{
let mut position: i32 = received.len() - 1 - self.field.log(error_locations[i]);
if position < 0 {
throw ChecksumException::get_checksum_instance();
}
received[position] = self.field.subtract(received[position], error_magnitudes[i]);
}
i += 1;
}
}
return Ok(error_locations.len());
}
fn run_euclidean_algorithm(&self, a: &ModulusPoly, b: &ModulusPoly, R: i32) -> /* throws ChecksumException */Result<Vec<ModulusPoly>, Rc<Exception>> {
// Assume a's degree is >= b's
if a.get_degree() < b.get_degree() {
let temp: ModulusPoly = a;
a = b;
b = temp;
}
let r_last: ModulusPoly = a;
let mut r: ModulusPoly = b;
let t_last: ModulusPoly = self.field.get_zero();
let mut t: ModulusPoly = self.field.get_one();
// Run Euclidean algorithm until r's degree is less than R/2
while r.get_degree() >= R / 2 {
let r_last_last: ModulusPoly = r_last;
let t_last_last: ModulusPoly = t_last;
r_last = r;
t_last = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if r_last.is_zero() {
// Oops, Euclidean algorithm already terminated?
throw ChecksumException::get_checksum_instance();
}
r = r_last_last;
let mut q: ModulusPoly = self.field.get_zero();
let denominator_leading_term: i32 = r_last.get_coefficient(&r_last.get_degree());
let dlt_inverse: i32 = self.field.inverse(denominator_leading_term);
while r.get_degree() >= r_last.get_degree() && !r.is_zero() {
let degree_diff: i32 = r.get_degree() - r_last.get_degree();
let scale: i32 = self.field.multiply(&r.get_coefficient(&r.get_degree()), dlt_inverse);
q = q.add(&self.field.build_monomial(degree_diff, scale));
r = r.subtract(&r_last.multiply_by_monomial(degree_diff, scale));
}
t = q.multiply(t_last).subtract(t_last_last).negative();
}
let sigma_tilde_at_zero: i32 = t.get_coefficient(0);
if sigma_tilde_at_zero == 0 {
throw ChecksumException::get_checksum_instance();
}
let inverse: i32 = self.field.inverse(sigma_tilde_at_zero);
let sigma: ModulusPoly = t.multiply(inverse);
let omega: ModulusPoly = r.multiply(inverse);
return Ok( : vec![ModulusPoly; 2] = vec![sigma, omega, ]
);
}
fn find_error_locations(&self, error_locator: &ModulusPoly) -> /* throws ChecksumException */Result<Vec<i32>, Rc<Exception>> {
// This is a direct application of Chien's search
let num_errors: i32 = error_locator.get_degree();
let mut result: [i32; num_errors] = [0; num_errors];
let mut e: i32 = 0;
{
let mut i: i32 = 1;
while i < self.field.get_size() && e < num_errors {
{
if error_locator.evaluate_at(i) == 0 {
result[e] = self.field.inverse(i);
e += 1;
}
}
i += 1;
}
}
if e != num_errors {
throw ChecksumException::get_checksum_instance();
}
return Ok(result);
}
fn find_error_magnitudes(&self, error_evaluator: &ModulusPoly, error_locator: &ModulusPoly, error_locations: &Vec<i32>) -> Vec<i32> {
let error_locator_degree: i32 = error_locator.get_degree();
if error_locator_degree < 1 {
return : [i32; 0] = [0; 0];
}
let formal_derivative_coefficients: [i32; error_locator_degree] = [0; error_locator_degree];
{
let mut i: i32 = 1;
while i <= error_locator_degree {
{
formal_derivative_coefficients[error_locator_degree - i] = self.field.multiply(i, &error_locator.get_coefficient(i));
}
i += 1;
}
}
let formal_derivative: ModulusPoly = ModulusPoly::new(self.field, &formal_derivative_coefficients);
// This is directly applying Forney's Formula
let s: i32 = error_locations.len();
let mut result: [i32; s] = [0; s];
{
let mut i: i32 = 0;
while i < s {
{
let xi_inverse: i32 = self.field.inverse(error_locations[i]);
let numerator: i32 = self.field.subtract(0, &error_evaluator.evaluate_at(xi_inverse));
let denominator: i32 = self.field.inverse(&formal_derivative.evaluate_at(xi_inverse));
result[i] = self.field.multiply(numerator, denominator);
}
i += 1;
}
}
return result;
}
}
// NEW FILE: modulus_g_f.rs
/*
* Copyright 2012 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::pdf417::decoder::ec;
/**
* <p>A field based on powers of a generator integer, modulo some modulus.</p>
*
* @author Sean Owen
* @see com.google.zxing.common.reedsolomon.GenericGF
*/
const PDF417_GF: ModulusGF = ModulusGF::new(PDF417Common.NUMBER_OF_CODEWORDS, 3);
pub struct ModulusGF {
let exp_table: Vec<i32>;
let log_table: Vec<i32>;
let mut zero: ModulusPoly;
let mut one: ModulusPoly;
let modulus: i32;
}
impl ModulusGF {
fn new( modulus: i32, generator: i32) -> ModulusGF {
let .modulus = modulus;
exp_table = : [i32; modulus] = [0; modulus];
log_table = : [i32; modulus] = [0; modulus];
let mut x: i32 = 1;
{
let mut i: i32 = 0;
while i < modulus {
{
exp_table[i] = x;
x = (x * generator) % modulus;
}
i += 1;
}
}
{
let mut i: i32 = 0;
while i < modulus - 1 {
{
log_table[exp_table[i]] = i;
}
i += 1;
}
}
// logTable[0] == 0 but this should never be used
zero = ModulusPoly::new(let , : vec![i32; 1] = vec![0, ]
);
one = ModulusPoly::new(let , : vec![i32; 1] = vec![1, ]
);
}
fn get_zero(&self) -> ModulusPoly {
return self.zero;
}
fn get_one(&self) -> ModulusPoly {
return self.one;
}
fn build_monomial(&self, degree: i32, coefficient: i32) -> ModulusPoly {
if degree < 0 {
throw IllegalArgumentException::new();
}
if coefficient == 0 {
return self.zero;
}
let mut coefficients: [i32; degree + 1] = [0; degree + 1];
coefficients[0] = coefficient;
return ModulusPoly::new(self, &coefficients);
}
fn add(&self, a: i32, b: i32) -> i32 {
return (a + b) % self.modulus;
}
fn subtract(&self, a: i32, b: i32) -> i32 {
return (self.modulus + a - b) % self.modulus;
}
fn exp(&self, a: i32) -> i32 {
return self.exp_table[a];
}
fn log(&self, a: i32) -> i32 {
if a == 0 {
throw IllegalArgumentException::new();
}
return self.log_table[a];
}
fn inverse(&self, a: i32) -> i32 {
if a == 0 {
throw ArithmeticException::new();
}
return self.exp_table[self.modulus - self.log_table[a] - 1];
}
fn multiply(&self, a: i32, b: i32) -> i32 {
if a == 0 || b == 0 {
return 0;
}
return self.exp_table[(self.log_table[a] + self.log_table[b]) % (self.modulus - 1)];
}
fn get_size(&self) -> i32 {
return self.modulus;
}
}
// NEW FILE: modulus_poly.rs
/*
* Copyright 2012 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::pdf417::decoder::ec;
/**
* @author Sean Owen
*/
struct ModulusPoly {
let field: ModulusGF;
let coefficients: Vec<i32>;
}
impl ModulusPoly {
fn new( field: &ModulusGF, coefficients: &Vec<i32>) -> ModulusPoly {
if coefficients.len() == 0 {
throw IllegalArgumentException::new();
}
let .field = field;
let coefficients_length: i32 = coefficients.len();
if coefficients_length > 1 && coefficients[0] == 0 {
// Leading term must be non-zero for anything except the constant polynomial "0"
let first_non_zero: i32 = 1;
while first_non_zero < coefficients_length && coefficients[first_non_zero] == 0 {
first_non_zero += 1;
}
if first_non_zero == coefficients_length {
let .coefficients = : vec![i32; 1] = vec![0, ]
;
} else {
let .coefficients = : [i32; coefficients_length - first_non_zero] = [0; coefficients_length - first_non_zero];
System::arraycopy(&coefficients, first_non_zero, let .coefficients, 0, let .coefficients.len());
}
} else {
let .coefficients = coefficients;
}
}
fn get_coefficients(&self) -> Vec<i32> {
return self.coefficients;
}
/**
* @return degree of this polynomial
*/
fn get_degree(&self) -> i32 {
return self.coefficients.len() - 1;
}
/**
* @return true iff this polynomial is the monomial "0"
*/
fn is_zero(&self) -> bool {
return self.coefficients[0] == 0;
}
/**
* @return coefficient of x^degree term in this polynomial
*/
fn get_coefficient(&self, degree: i32) -> i32 {
return self.coefficients[self.coefficients.len() - 1 - degree];
}
/**
* @return evaluation of this polynomial at a given point
*/
fn evaluate_at(&self, a: i32) -> i32 {
if a == 0 {
// Just return the x^0 coefficient
return self.get_coefficient(0);
}
if a == 1 {
// Just the sum of the coefficients
let mut result: i32 = 0;
for let coefficient: i32 in self.coefficients {
result = self.field.add(result, coefficient);
}
return result;
}
let mut result: i32 = self.coefficients[0];
let size: i32 = self.coefficients.len();
{
let mut i: i32 = 1;
while i < size {
{
result = self.field.add(&self.field.multiply(a, result), self.coefficients[i]);
}
i += 1;
}
}
return result;
}
fn add(&self, other: &ModulusPoly) -> ModulusPoly {
if !self.field.equals(other.field) {
throw IllegalArgumentException::new("ModulusPolys do not have same ModulusGF field");
}
if self.is_zero() {
return other;
}
if other.is_zero() {
return self;
}
let smaller_coefficients: Vec<i32> = self.coefficients;
let larger_coefficients: Vec<i32> = other.coefficients;
if smaller_coefficients.len() > larger_coefficients.len() {
let temp: Vec<i32> = smaller_coefficients;
smaller_coefficients = larger_coefficients;
larger_coefficients = temp;
}
let sum_diff: [i32; larger_coefficients.len()] = [0; larger_coefficients.len()];
let length_diff: i32 = larger_coefficients.len() - smaller_coefficients.len();
// Copy high-order terms only found in higher-degree polynomial's coefficients
System::arraycopy(&larger_coefficients, 0, &sum_diff, 0, length_diff);
{
let mut i: i32 = length_diff;
while i < larger_coefficients.len() {
{
sum_diff[i] = self.field.add(smaller_coefficients[i - length_diff], larger_coefficients[i]);
}
i += 1;
}
}
return ModulusPoly::new(self.field, &sum_diff);
}
fn subtract(&self, other: &ModulusPoly) -> ModulusPoly {
if !self.field.equals(other.field) {
throw IllegalArgumentException::new("ModulusPolys do not have same ModulusGF field");
}
if other.is_zero() {
return self;
}
return self.add(&other.negative());
}
fn multiply(&self, other: &ModulusPoly) -> ModulusPoly {
if !self.field.equals(other.field) {
throw IllegalArgumentException::new("ModulusPolys do not have same ModulusGF field");
}
if self.is_zero() || other.is_zero() {
return self.field.get_zero();
}
let a_coefficients: Vec<i32> = self.coefficients;
let a_length: i32 = a_coefficients.len();
let b_coefficients: Vec<i32> = other.coefficients;
let b_length: i32 = b_coefficients.len();
let mut product: [i32; a_length + b_length - 1] = [0; a_length + b_length - 1];
{
let mut i: i32 = 0;
while i < a_length {
{
let a_coeff: i32 = a_coefficients[i];
{
let mut j: i32 = 0;
while j < b_length {
{
product[i + j] = self.field.add(product[i + j], &self.field.multiply(a_coeff, b_coefficients[j]));
}
j += 1;
}
}
}
i += 1;
}
}
return ModulusPoly::new(self.field, &product);
}
fn negative(&self) -> ModulusPoly {
let size: i32 = self.coefficients.len();
let negative_coefficients: [i32; size] = [0; size];
{
let mut i: i32 = 0;
while i < size {
{
negative_coefficients[i] = self.field.subtract(0, self.coefficients[i]);
}
i += 1;
}
}
return ModulusPoly::new(self.field, &negative_coefficients);
}
fn multiply(&self, scalar: i32) -> ModulusPoly {
if scalar == 0 {
return self.field.get_zero();
}
if scalar == 1 {
return self;
}
let size: i32 = self.coefficients.len();
let mut product: [i32; size] = [0; size];
{
let mut i: i32 = 0;
while i < size {
{
product[i] = self.field.multiply(self.coefficients[i], scalar);
}
i += 1;
}
}
return ModulusPoly::new(self.field, &product);
}
fn multiply_by_monomial(&self, degree: i32, coefficient: i32) -> ModulusPoly {
if degree < 0 {
throw IllegalArgumentException::new();
}
if coefficient == 0 {
return self.field.get_zero();
}
let size: i32 = self.coefficients.len();
let mut product: [i32; size + degree] = [0; size + degree];
{
let mut i: i32 = 0;
while i < size {
{
product[i] = self.field.multiply(self.coefficients[i], coefficient);
}
i += 1;
}
}
return ModulusPoly::new(self.field, &product);
}
pub fn to_string(&self) -> String {
let result: StringBuilder = StringBuilder::new(8 * self.get_degree());
{
let mut degree: i32 = self.get_degree();
while degree >= 0 {
{
let mut coefficient: i32 = self.get_coefficient(degree);
if coefficient != 0 {
if coefficient < 0 {
result.append(" - ");
coefficient = -coefficient;
} else {
if result.length() > 0 {
result.append(" + ");
}
}
if degree == 0 || coefficient != 1 {
result.append(coefficient);
}
if degree != 0 {
if degree == 1 {
result.append('x');
} else {
result.append("x^");
result.append(degree);
}
}
}
}
degree -= 1;
}
}
return result.to_string();
}
}
-433
View File
@@ -1,433 +0,0 @@
use crate::{BinaryBitmap,NotFoundException,DecodeHintType,ResultPoint};
use crate::common::BitMatrix;
// NEW FILE: detector.rs
/*
* Copyright 2009 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::pdf417::detector;
/**
* <p>Encapsulates logic that can detect a PDF417 Code in an image, even if the
* PDF417 Code is rotated or skewed, or partially obscured.</p>
*
* @author SITA Lab (kevin.osullivan@sita.aero)
* @author dswitkin@google.com (Daniel Switkin)
* @author Guenther Grau
*/
const INDEXES_START_PATTERN: vec![Vec<i32>; 4] = vec![0, 4, 1, 5, ]
;
const INDEXES_STOP_PATTERN: vec![Vec<i32>; 4] = vec![6, 2, 7, 3, ]
;
const MAX_AVG_VARIANCE: f32 = 0.42f;
const MAX_INDIVIDUAL_VARIANCE: f32 = 0.8f;
// B S B S B S B S Bar/Space pattern
// 11111111 0 1 0 1 0 1 000
const START_PATTERN: vec![Vec<i32>; 8] = vec![8, 1, 1, 1, 1, 1, 1, 3, ]
;
// 1111111 0 1 000 1 0 1 00 1
const STOP_PATTERN: vec![Vec<i32>; 9] = vec![7, 1, 1, 3, 1, 1, 1, 2, 1, ]
;
const MAX_PIXEL_DRIFT: i32 = 3;
const MAX_PATTERN_DRIFT: i32 = 5;
// if we set the value too low, then we don't detect the correct height of the bar if the start patterns are damaged.
// if we set the value too high, then we might detect the start pattern from a neighbor barcode.
const SKIPPED_ROW_COUNT_MAX: i32 = 25;
// A PDF471 barcode should have at least 3 rows, with each row being >= 3 times the module width.
// Therefore it should be at least 9 pixels tall. To be conservative, we use about half the size to
// ensure we don't miss it.
const ROW_STEP: i32 = 5;
const BARCODE_MIN_HEIGHT: i32 = 10;
const ROTATIONS: vec![Vec<i32>; 4] = vec![0, 180, 270, 90, ]
;
pub struct Detector {
}
impl Detector {
fn new() -> Detector {
}
/**
* <p>Detects a PDF417 Code in an image. Checks 0, 90, 180, and 270 degree rotations.</p>
*
* @param image barcode image to decode
* @param hints optional hints to detector
* @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will
* be found and returned
* @return {@link PDF417DetectorResult} encapsulating results of detecting a PDF417 code
* @throws NotFoundException if no PDF417 Code can be found
*/
pub fn detect( image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>, multiple: bool) -> /* throws NotFoundException */Result<PDF417DetectorResult, Rc<Exception>> {
// TODO detection improvement, tryHarder could try several different luminance thresholds/blackpoints or even
// different binarizers
//boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
let original_matrix: BitMatrix = image.get_black_matrix();
for let rotation: i32 in ROTATIONS {
let bit_matrix: BitMatrix = ::apply_rotation(original_matrix, rotation);
let barcode_coordinates: List<Vec<ResultPoint>> = ::detect(multiple, bit_matrix);
if !barcode_coordinates.is_empty() {
return Ok(PDF417DetectorResult::new(bit_matrix, &barcode_coordinates, rotation));
}
}
return Ok(PDF417DetectorResult::new(original_matrix, ArrayList<>::new(), 0));
}
/**
* Applies a rotation to the supplied BitMatrix.
* @param matrix bit matrix to apply rotation to
* @param rotation the degrees of rotation to apply
* @return BitMatrix with applied rotation
*/
fn apply_rotation( matrix: &BitMatrix, rotation: i32) -> BitMatrix {
if rotation % 360 == 0 {
return matrix;
}
let new_matrix: BitMatrix = matrix.clone();
new_matrix.rotate(rotation);
return new_matrix;
}
/**
* Detects PDF417 codes in an image. Only checks 0 degree rotation
* @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will
* be found and returned
* @param bitMatrix bit matrix to detect barcodes in
* @return List of ResultPoint arrays containing the coordinates of found barcodes
*/
fn detect( multiple: bool, bit_matrix: &BitMatrix) -> List<Vec<ResultPoint>> {
let barcode_coordinates: List<Vec<ResultPoint>> = ArrayList<>::new();
let mut row: i32 = 0;
let mut column: i32 = 0;
let found_barcode_in_row: bool = false;
while row < bit_matrix.get_height() {
let vertices: Vec<ResultPoint> = ::find_vertices(bit_matrix, row, column);
if vertices[0] == null && vertices[3] == null {
if !found_barcode_in_row {
// we didn't find any barcode so that's the end of searching
break;
}
// we didn't find a barcode starting at the given column and row. Try again from the first column and slightly
// below the lowest barcode we found so far.
found_barcode_in_row = false;
column = 0;
for let barcode_coordinate: Vec<ResultPoint> in barcode_coordinates {
if barcode_coordinate[1] != null {
row = Math::max(row, &barcode_coordinate[1].get_y()) as i32;
}
if barcode_coordinate[3] != null {
row = Math::max(row, barcode_coordinate[3].get_y() as i32);
}
}
row += ROW_STEP;
continue;
}
found_barcode_in_row = true;
barcode_coordinates.add(vertices);
if !multiple {
break;
}
// start pattern of the barcode just found.
if vertices[2] != null {
column = vertices[2].get_x() as i32;
row = vertices[2].get_y() as i32;
} else {
column = vertices[4].get_x() as i32;
row = vertices[4].get_y() as i32;
}
}
return Ok(barcode_coordinates);
}
/**
* Locate the vertices and the codewords area of a black blob using the Start
* and Stop patterns as locators.
*
* @param matrix the scanned barcode image.
* @return an array containing the vertices:
* vertices[0] x, y top left barcode
* vertices[1] x, y bottom left barcode
* vertices[2] x, y top right barcode
* vertices[3] x, y bottom right barcode
* vertices[4] x, y top left codeword area
* vertices[5] x, y bottom left codeword area
* vertices[6] x, y top right codeword area
* vertices[7] x, y bottom right codeword area
*/
fn find_vertices( matrix: &BitMatrix, start_row: i32, start_column: i32) -> Vec<ResultPoint> {
let height: i32 = matrix.get_height();
let width: i32 = matrix.get_width();
let result: [Option<ResultPoint>; 8] = [None; 8];
::copy_to_result(result, &::find_rows_with_pattern(matrix, height, width, start_row, start_column, &START_PATTERN), &INDEXES_START_PATTERN);
if result[4] != null {
start_column = result[4].get_x() as i32;
start_row = result[4].get_y() as i32;
}
::copy_to_result(result, &::find_rows_with_pattern(matrix, height, width, start_row, start_column, &STOP_PATTERN), &INDEXES_STOP_PATTERN);
return result;
}
fn copy_to_result( result: &Vec<ResultPoint>, tmp_result: &Vec<ResultPoint>, destination_indexes: &Vec<i32>) {
{
let mut i: i32 = 0;
while i < destination_indexes.len() {
{
result[destination_indexes[i]] = tmp_result[i];
}
i += 1;
}
}
}
fn find_rows_with_pattern( matrix: &BitMatrix, height: i32, width: i32, start_row: i32, start_column: i32, pattern: &Vec<i32>) -> Vec<ResultPoint> {
let mut result: [Option<ResultPoint>; 4] = [None; 4];
let mut found: bool = false;
let counters: [i32; pattern.len()] = [0; pattern.len()];
while start_row < height {
{
let mut loc: Vec<i32> = ::find_guard_pattern(matrix, start_column, start_row, width, &pattern, &counters);
if loc != null {
while start_row > 0 {
let previous_row_loc: Vec<i32> = ::find_guard_pattern(matrix, start_column, start_row -= 1, width, &pattern, &counters);
if previous_row_loc != null {
loc = previous_row_loc;
} else {
start_row += 1;
break;
}
}
result[0] = ResultPoint::new(loc[0], start_row);
result[1] = ResultPoint::new(loc[1], start_row);
found = true;
break;
}
}
start_row += ROW_STEP;
}
let stop_row: i32 = start_row + 1;
// Last row of the current symbol that contains pattern
if found {
let skipped_row_count: i32 = 0;
let previous_row_loc: vec![Vec<i32>; 2] = vec![result[0].get_x() as i32, result[1].get_x() as i32, ]
;
while stop_row < height {
{
let loc: Vec<i32> = ::find_guard_pattern(matrix, previous_row_loc[0], stop_row, width, &pattern, &counters);
// larger drift and don't check for skipped rows.
if loc != null && Math::abs(previous_row_loc[0] - loc[0]) < MAX_PATTERN_DRIFT && Math::abs(previous_row_loc[1] - loc[1]) < MAX_PATTERN_DRIFT {
previous_row_loc = loc;
skipped_row_count = 0;
} else {
if skipped_row_count > SKIPPED_ROW_COUNT_MAX {
break;
} else {
skipped_row_count += 1;
}
}
}
stop_row += 1;
}
stop_row -= skipped_row_count + 1;
result[2] = ResultPoint::new(previous_row_loc[0], stop_row);
result[3] = ResultPoint::new(previous_row_loc[1], stop_row);
}
if stop_row - start_row < BARCODE_MIN_HEIGHT {
Arrays::fill(result, null);
}
return result;
}
/**
* @param matrix row of black/white values to search
* @param column x position to start search
* @param row y position to start search
* @param width the number of pixels to search on this row
* @param pattern pattern of counts of number of black and white pixels that are
* being searched for as a pattern
* @param counters array of counters, as long as pattern, to re-use
* @return start/end horizontal offset of guard pattern, as an array of two ints.
*/
fn find_guard_pattern( matrix: &BitMatrix, column: i32, row: i32, width: i32, pattern: &Vec<i32>, counters: &Vec<i32>) -> Vec<i32> {
Arrays::fill(&counters, 0, counters.len(), 0);
let pattern_start: i32 = column;
let pixel_drift: i32 = 0;
// if there are black pixels left of the current pixel shift to the left, but only for MAX_PIXEL_DRIFT pixels
while matrix.get(pattern_start, row) && pattern_start > 0 && pixel_drift += 1 !!!check!!! post increment < MAX_PIXEL_DRIFT {
pattern_start -= 1;
}
let mut x: i32 = pattern_start;
let counter_position: i32 = 0;
let pattern_length: i32 = pattern.len();
{
let is_white: bool = false;
while x < width {
{
let pixel: bool = matrix.get(x, row);
if pixel != is_white {
counters[counter_position] += 1;
} else {
if counter_position == pattern_length - 1 {
if ::pattern_match_variance(&counters, &pattern) < MAX_AVG_VARIANCE {
return : vec![i32; 2] = vec![pattern_start, x, ]
;
}
pattern_start += counters[0] + counters[1];
System::arraycopy(&counters, 2, &counters, 0, counter_position - 1);
counters[counter_position - 1] = 0;
counters[counter_position] = 0;
counter_position -= 1;
} else {
counter_position += 1;
}
counters[counter_position] = 1;
is_white = !is_white;
}
}
x += 1;
}
}
if counter_position == pattern_length - 1 && ::pattern_match_variance(&counters, &pattern) < MAX_AVG_VARIANCE {
return : vec![i32; 2] = vec![pattern_start, x - 1, ]
;
}
return null;
}
/**
* Determines how closely a set of observed counts of runs of black/white
* values matches a given target pattern. This is reported as the ratio of
* the total variance from the expected pattern proportions across all
* pattern elements, to the length of the pattern.
*
* @param counters observed counters
* @param pattern expected pattern
* @return ratio of total variance between counters and pattern compared to total pattern size
*/
fn pattern_match_variance( counters: &Vec<i32>, pattern: &Vec<i32>) -> f32 {
let num_counters: i32 = counters.len();
let mut total: i32 = 0;
let pattern_length: i32 = 0;
{
let mut i: i32 = 0;
while i < num_counters {
{
total += counters[i];
pattern_length += pattern[i];
}
i += 1;
}
}
if total < pattern_length {
// is too small to reliably match, so fail:
return Float::POSITIVE_INFINITY;
}
// We're going to fake floating-point math in integers. We just need to use more bits.
// Scale up patternLength so that intermediate values below like scaledCounter will have
// more "significant digits".
let unit_bar_width: f32 = total as f32 / pattern_length;
let max_individual_variance: f32 = MAX_INDIVIDUAL_VARIANCE * unit_bar_width;
let total_variance: f32 = 0.0f;
{
let mut x: i32 = 0;
while x < num_counters {
{
let counter: i32 = counters[x];
let scaled_pattern: f32 = pattern[x] * unit_bar_width;
let variance: f32 = if counter > scaled_pattern { counter - scaled_pattern } else { scaled_pattern - counter };
if variance > max_individual_variance {
return Float::POSITIVE_INFINITY;
}
total_variance += variance;
}
x += 1;
}
}
return total_variance / total;
}
}
// NEW FILE: p_d_f417_detector_result.rs
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com::google::zxing::pdf417::detector;
/**
* @author Guenther Grau
*/
pub struct PDF417DetectorResult {
let bits: BitMatrix;
let points: List<Vec<ResultPoint>>;
let rotation: i32;
}
impl PDF417DetectorResult {
pub fn new( bits: &BitMatrix, points: &List<Vec<ResultPoint>>, rotation: i32) -> PDF417DetectorResult {
let .bits = bits;
let .points = points;
let .rotation = rotation;
}
pub fn new( bits: &BitMatrix, points: &List<Vec<ResultPoint>>) -> PDF417DetectorResult {
this(bits, &points, 0);
}
pub fn get_bits(&self) -> BitMatrix {
return self.bits;
}
pub fn get_points(&self) -> List<Vec<ResultPoint>> {
return self.points;
}
pub fn get_rotation(&self) -> i32 {
return self.rotation;
}
}
File diff suppressed because one or more lines are too long
-316
View File
@@ -1,316 +0,0 @@
use crate::{BarcodeFormat,BinaryBitmap,ChecksumException,DecodeHintType,FormatException,NotFoundException,Reader,XRingResult,ResultMetadataType,ResultPoint,EncodeHintType,Writer,WriterException,};
use crate::common::{BitMatrix,DecoderResult,DetectorResult,};
use crate::qrcode::decoder::{Decoder,QRCodeDecoderMetaData};
use crate::qrcode::detector::{Detector};
use crate::qrcode::encoder::{ByteMatrix,ErrorCorrectionLevel,Encoder,QRCode};
// NEW FILE: q_r_code_reader.rs
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com::google::zxing::qrcode;
/**
* This implementation can detect and decode QR Codes in an image.
*
* @author Sean Owen
*/
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
#[derive(Reader)]
pub struct QRCodeReader {
let decoder: Decoder = Decoder::new();
}
impl QRCodeReader {
pub fn get_decoder(&self) -> Decoder {
return self.decoder;
}
/**
* Locates and decodes a QR code in an image.
*
* @return a String representing the content encoded by the QR code
* @throws NotFoundException if a QR code cannot be found
* @throws FormatException if a QR code cannot be decoded
* @throws ChecksumException if error correction fails
*/
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
return Ok(self.decode(image, null));
}
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, ChecksumException, FormatException */Result<Result, Rc<Exception>> {
let decoder_result: DecoderResult;
let mut points: Vec<ResultPoint>;
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
decoder_result = self.decoder.decode(bits, &hints);
points = NO_POINTS;
} else {
let detector_result: DetectorResult = Detector::new(&image.get_black_matrix()).detect(&hints);
decoder_result = self.decoder.decode(&detector_result.get_bits(), &hints);
points = detector_result.get_points();
}
// If the code was mirrored: swap the bottom-left and the top-right points.
if decoder_result.get_other() instanceof QRCodeDecoderMetaData {
(decoder_result.get_other() as QRCodeDecoderMetaData).apply_mirrored_correction(points);
}
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::QR_CODE);
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
if byte_segments != null {
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
}
let ec_level: String = decoder_result.get_e_c_level();
if ec_level != null {
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
}
if decoder_result.has_structured_append() {
result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE, &decoder_result.get_structured_append_sequence_number());
result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_PARITY, &decoder_result.get_structured_append_parity());
}
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]Q{}", decoder_result.get_symbology_modifier()));
return Ok(result);
}
pub fn reset(&self) {
// do nothing
}
/**
* This method detects a code in a "pure" image -- that is, pure monochrome image
* which contains only an unrotated, unskewed, image of a code, with some white border
* around it. This is a specialized method that works exceptionally fast in this special
* case.
*/
fn extract_pure_bits( image: &BitMatrix) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
let left_top_black: Vec<i32> = image.get_top_left_on_bit();
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
if left_top_black == null || right_bottom_black == null {
throw NotFoundException::get_not_found_instance();
}
let module_size: f32 = self.module_size(&left_top_black, image);
let mut top: i32 = left_top_black[1];
let bottom: i32 = right_bottom_black[1];
let mut left: i32 = left_top_black[0];
let mut right: i32 = right_bottom_black[0];
// Sanity check!
if left >= right || top >= bottom {
throw NotFoundException::get_not_found_instance();
}
if bottom - top != right - left {
// Special case, where bottom-right module wasn't black so we found something else in the last row
// Assume it's a square, so use height as the width
right = left + (bottom - top);
if right >= image.get_width() {
// Abort if that would not make sense -- off image
throw NotFoundException::get_not_found_instance();
}
}
let matrix_width: i32 = Math::round((right - left + 1.0) / module_size);
let matrix_height: i32 = Math::round((bottom - top + 1.0) / module_size);
if matrix_width <= 0 || matrix_height <= 0 {
throw NotFoundException::get_not_found_instance();
}
if matrix_height != matrix_width {
// Only possibly decode square regions
throw NotFoundException::get_not_found_instance();
}
// Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a
// little off, this will help recover.
let nudge: i32 = (module_size / 2.0f) as i32;
top += nudge;
left += nudge;
// But careful that this does not sample off the edge
// "right" is the farthest-right valid pixel location -- right+1 is not necessarily
// This is positive by how much the inner x loop below would be too large
let nudged_too_far_right: i32 = left + ((matrix_width - 1.0) * module_size) as i32 - right;
if nudged_too_far_right > 0 {
if nudged_too_far_right > nudge {
// Neither way fits; abort
throw NotFoundException::get_not_found_instance();
}
left -= nudged_too_far_right;
}
// See logic above
let nudged_too_far_down: i32 = top + ((matrix_height - 1.0) * module_size) as i32 - bottom;
if nudged_too_far_down > 0 {
if nudged_too_far_down > nudge {
// Neither way fits; abort
throw NotFoundException::get_not_found_instance();
}
top -= nudged_too_far_down;
}
// Now just read off the bits
let bits: BitMatrix = BitMatrix::new(matrix_width, matrix_height);
{
let mut y: i32 = 0;
while y < matrix_height {
{
let i_offset: i32 = top + (y * module_size) as i32;
{
let mut x: i32 = 0;
while x < matrix_width {
{
if image.get(left + (x * module_size) as i32, i_offset) {
bits.set(x, y);
}
}
x += 1;
}
}
}
y += 1;
}
}
return Ok(bits);
}
fn module_size( left_top_black: &Vec<i32>, image: &BitMatrix) -> /* throws NotFoundException */Result<f32, Rc<Exception>> {
let height: i32 = image.get_height();
let width: i32 = image.get_width();
let mut x: i32 = left_top_black[0];
let mut y: i32 = left_top_black[1];
let in_black: bool = true;
let mut transitions: i32 = 0;
while x < width && y < height {
if in_black != image.get(x, y) {
if transitions += 1 == 5 {
break;
}
in_black = !in_black;
}
x += 1;
y += 1;
}
if x == width || y == height {
throw NotFoundException::get_not_found_instance();
}
return Ok((x - left_top_black[0]) / 7.0f);
}
}
// NEW FILE: q_r_code_writer.rs
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com::google::zxing::qrcode;
/**
* This object renders a QR Code as a BitMatrix 2D array of greyscale values.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
const QUIET_ZONE_SIZE: i32 = 4;
#[derive(Writer)]
pub struct QRCodeWriter {
}
impl QRCodeWriter {
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32) -> /* throws WriterException */Result<BitMatrix, Rc<Exception>> {
return Ok(self.encode(&contents, format, width, height, null));
}
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, ?>) -> /* throws WriterException */Result<BitMatrix, Rc<Exception>> {
if contents.is_empty() {
throw IllegalArgumentException::new("Found empty contents");
}
if format != BarcodeFormat::QR_CODE {
throw IllegalArgumentException::new(format!("Can only encode QR_CODE, but got {}", format));
}
if width < 0 || height < 0 {
throw IllegalArgumentException::new(format!("Requested dimensions are too small: {}x{}", width, height));
}
let error_correction_level: ErrorCorrectionLevel = ErrorCorrectionLevel::L;
let quiet_zone: i32 = QUIET_ZONE_SIZE;
if hints != null {
if hints.contains_key(EncodeHintType::ERROR_CORRECTION) {
error_correction_level = ErrorCorrectionLevel::value_of(&hints.get(EncodeHintType::ERROR_CORRECTION).to_string());
}
if hints.contains_key(EncodeHintType::MARGIN) {
quiet_zone = Integer::parse_int(&hints.get(EncodeHintType::MARGIN).to_string());
}
}
let code: QRCode = Encoder::encode(&contents, error_correction_level, &hints);
return Ok(::render_result(code, width, height, quiet_zone));
}
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
fn render_result( code: &QRCode, width: i32, height: i32, quiet_zone: i32) -> BitMatrix {
let input: ByteMatrix = code.get_matrix();
if input == null {
throw IllegalStateException::new();
}
let input_width: i32 = input.get_width();
let input_height: i32 = input.get_height();
let qr_width: i32 = input_width + (quiet_zone * 2);
let qr_height: i32 = input_height + (quiet_zone * 2);
let output_width: i32 = Math::max(width, qr_width);
let output_height: i32 = Math::max(height, qr_height);
let multiple: i32 = Math::min(output_width / qr_width, output_height / qr_height);
// Padding includes both the quiet zone and the extra white pixels to accommodate the requested
// dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
// If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
// handle all the padding from 100x100 (the actual QR) up to 200x160.
let left_padding: i32 = (output_width - (input_width * multiple)) / 2;
let top_padding: i32 = (output_height - (input_height * multiple)) / 2;
let output: BitMatrix = BitMatrix::new(output_width, output_height);
{
let input_y: i32 = 0, let output_y: i32 = top_padding;
while input_y < input_height {
{
// Write the contents of this row of the barcode
{
let input_x: i32 = 0, let output_x: i32 = left_padding;
while input_x < input_width {
{
if input.get(input_x, input_y) == 1 {
output.set_region(output_x, output_y, multiple, multiple);
}
}
input_x += 1;
output_x += multiple;
}
}
}
input_y += 1;
output_y += multiple;
}
}
return output;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff