move pdf417

This commit is contained in:
Henry Schimke
2022-08-14 18:08:45 -05:00
parent aff9e1088a
commit 7ade09dc7b
64 changed files with 12507 additions and 5995 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,632 @@
import com.google.zxing.ChecksumException;
import com.google.zxing.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();
}
}

View File

@@ -0,0 +1,441 @@
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.NotFoundException;
import com.google.zxing.ResultPoint;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.ResultPoint;
import com.google.zxing.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