mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
move pdf417
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.common.BitArray;
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.common.BitArray;
|
||||
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.common.BitArray;
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
|
||||
|
||||
|
||||
|
||||
// NEW FILE: a_i013103decoder.rs
|
||||
/*
|
||||
* Copyright (C) 2010 ZXing authors
|
||||
|
||||
588
src/pdf417.rs
588
src/pdf417.rs
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
310
src/qrcode.rs
310
src/qrcode.rs
@@ -0,0 +1,310 @@
|
||||
// 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
Reference in New Issue
Block a user