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,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
struct BarcodeMetadata {
|
||||
|
||||
let column_count: i32;
|
||||
|
||||
let error_correction_level: i32;
|
||||
|
||||
let row_count_upper_part: i32;
|
||||
|
||||
let row_count_lower_part: i32;
|
||||
|
||||
let row_count: i32;
|
||||
}
|
||||
|
||||
impl BarcodeMetadata {
|
||||
|
||||
fn new( column_count: i32, row_count_upper_part: i32, row_count_lower_part: i32, error_correction_level: i32) -> BarcodeMetadata {
|
||||
let .columnCount = column_count;
|
||||
let .errorCorrectionLevel = error_correction_level;
|
||||
let .rowCountUpperPart = row_count_upper_part;
|
||||
let .rowCountLowerPart = row_count_lower_part;
|
||||
let .rowCount = row_count_upper_part + row_count_lower_part;
|
||||
}
|
||||
|
||||
fn get_column_count(&self) -> i32 {
|
||||
return self.column_count;
|
||||
}
|
||||
|
||||
fn get_error_correction_level(&self) -> i32 {
|
||||
return self.error_correction_level;
|
||||
}
|
||||
|
||||
fn get_row_count(&self) -> i32 {
|
||||
return self.row_count;
|
||||
}
|
||||
|
||||
fn get_row_count_upper_part(&self) -> i32 {
|
||||
return self.row_count_upper_part;
|
||||
}
|
||||
|
||||
fn get_row_count_lower_part(&self) -> i32 {
|
||||
return self.row_count_lower_part;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
struct BarcodeValue {
|
||||
|
||||
let values: Map<Integer, Integer> = HashMap<>::new();
|
||||
}
|
||||
|
||||
impl BarcodeValue {
|
||||
|
||||
/**
|
||||
* Add an occurrence of a value
|
||||
*/
|
||||
fn set_value(&self, value: i32) {
|
||||
let mut confidence: Integer = self.values.get(value);
|
||||
if confidence == null {
|
||||
confidence = 0;
|
||||
}
|
||||
confidence += 1;
|
||||
self.values.put(value, &confidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the maximum occurrence of a set value and returns all values which were set with this occurrence.
|
||||
* @return an array of int, containing the values with the highest occurrence, or null, if no value was set
|
||||
*/
|
||||
fn get_value(&self) -> Vec<i32> {
|
||||
let max_confidence: i32 = -1;
|
||||
let result: Collection<Integer> = ArrayList<>::new();
|
||||
for let entry: Entry<Integer, Integer> in self.values.entry_set() {
|
||||
if entry.get_value() > max_confidence {
|
||||
max_confidence = entry.get_value();
|
||||
result.clear();
|
||||
result.add(&entry.get_key());
|
||||
} else if entry.get_value() == max_confidence {
|
||||
result.add(&entry.get_key());
|
||||
}
|
||||
}
|
||||
return PDF417Common::to_int_array(&result);
|
||||
}
|
||||
|
||||
fn get_confidence(&self, value: i32) -> Integer {
|
||||
return self.values.get(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
struct BoundingBox {
|
||||
|
||||
let mut image: BitMatrix;
|
||||
|
||||
let top_left: ResultPoint;
|
||||
|
||||
let bottom_left: ResultPoint;
|
||||
|
||||
let top_right: ResultPoint;
|
||||
|
||||
let bottom_right: ResultPoint;
|
||||
|
||||
let min_x: i32;
|
||||
|
||||
let max_x: i32;
|
||||
|
||||
let min_y: i32;
|
||||
|
||||
let max_y: i32;
|
||||
}
|
||||
|
||||
impl BoundingBox {
|
||||
|
||||
fn new( image: &BitMatrix, top_left: &ResultPoint, bottom_left: &ResultPoint, top_right: &ResultPoint, bottom_right: &ResultPoint) -> BoundingBox throws NotFoundException {
|
||||
let left_unspecified: bool = top_left == null || bottom_left == null;
|
||||
let right_unspecified: bool = top_right == null || bottom_right == null;
|
||||
if left_unspecified && right_unspecified {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
if left_unspecified {
|
||||
top_left = ResultPoint::new(0, &top_right.get_y());
|
||||
bottom_left = ResultPoint::new(0, &bottom_right.get_y());
|
||||
} else if right_unspecified {
|
||||
top_right = ResultPoint::new(image.get_width() - 1, &top_left.get_y());
|
||||
bottom_right = ResultPoint::new(image.get_width() - 1, &bottom_left.get_y());
|
||||
}
|
||||
let .image = image;
|
||||
let .topLeft = top_left;
|
||||
let .bottomLeft = bottom_left;
|
||||
let .topRight = top_right;
|
||||
let .bottomRight = bottom_right;
|
||||
let .minX = Math::min(&top_left.get_x(), &bottom_left.get_x()) as i32;
|
||||
let .maxX = Math::max(&top_right.get_x(), &bottom_right.get_x()) as i32;
|
||||
let .minY = Math::min(&top_left.get_y(), &top_right.get_y()) as i32;
|
||||
let .maxY = Math::max(&bottom_left.get_y(), &bottom_right.get_y()) as i32;
|
||||
}
|
||||
|
||||
fn new( bounding_box: &BoundingBox) -> BoundingBox {
|
||||
let .image = bounding_box.image;
|
||||
let .topLeft = bounding_box.topLeft;
|
||||
let .bottomLeft = bounding_box.bottomLeft;
|
||||
let .topRight = bounding_box.topRight;
|
||||
let .bottomRight = bounding_box.bottomRight;
|
||||
let .minX = bounding_box.minX;
|
||||
let .maxX = bounding_box.maxX;
|
||||
let .minY = bounding_box.minY;
|
||||
let .maxY = bounding_box.maxY;
|
||||
}
|
||||
|
||||
fn merge( left_box: &BoundingBox, right_box: &BoundingBox) -> /* throws NotFoundException */Result<BoundingBox, Rc<Exception>> {
|
||||
if left_box == null {
|
||||
return Ok(right_box);
|
||||
}
|
||||
if right_box == null {
|
||||
return Ok(left_box);
|
||||
}
|
||||
return Ok(BoundingBox::new(left_box.image, left_box.topLeft, left_box.bottomLeft, right_box.topRight, right_box.bottomRight));
|
||||
}
|
||||
|
||||
fn add_missing_rows(&self, missing_start_rows: i32, missing_end_rows: i32, is_left: bool) -> /* throws NotFoundException */Result<BoundingBox, Rc<Exception>> {
|
||||
let new_top_left: ResultPoint = self.top_left;
|
||||
let new_bottom_left: ResultPoint = self.bottom_left;
|
||||
let new_top_right: ResultPoint = self.top_right;
|
||||
let new_bottom_right: ResultPoint = self.bottom_right;
|
||||
if missing_start_rows > 0 {
|
||||
let top: ResultPoint = if is_left { self.top_left } else { self.top_right };
|
||||
let new_min_y: i32 = top.get_y() as i32 - missing_start_rows;
|
||||
if new_min_y < 0 {
|
||||
new_min_y = 0;
|
||||
}
|
||||
let new_top: ResultPoint = ResultPoint::new(&top.get_x(), new_min_y);
|
||||
if is_left {
|
||||
new_top_left = new_top;
|
||||
} else {
|
||||
new_top_right = new_top;
|
||||
}
|
||||
}
|
||||
if missing_end_rows > 0 {
|
||||
let bottom: ResultPoint = if is_left { self.bottom_left } else { self.bottom_right };
|
||||
let new_max_y: i32 = bottom.get_y() as i32 + missing_end_rows;
|
||||
if new_max_y >= self.image.get_height() {
|
||||
new_max_y = self.image.get_height() - 1;
|
||||
}
|
||||
let new_bottom: ResultPoint = ResultPoint::new(&bottom.get_x(), new_max_y);
|
||||
if is_left {
|
||||
new_bottom_left = new_bottom;
|
||||
} else {
|
||||
new_bottom_right = new_bottom;
|
||||
}
|
||||
}
|
||||
return Ok(BoundingBox::new(self.image, new_top_left, new_bottom_left, new_top_right, new_bottom_right));
|
||||
}
|
||||
|
||||
fn get_min_x(&self) -> i32 {
|
||||
return self.min_x;
|
||||
}
|
||||
|
||||
fn get_max_x(&self) -> i32 {
|
||||
return self.max_x;
|
||||
}
|
||||
|
||||
fn get_min_y(&self) -> i32 {
|
||||
return self.min_y;
|
||||
}
|
||||
|
||||
fn get_max_y(&self) -> i32 {
|
||||
return self.max_y;
|
||||
}
|
||||
|
||||
fn get_top_left(&self) -> ResultPoint {
|
||||
return self.top_left;
|
||||
}
|
||||
|
||||
fn get_top_right(&self) -> ResultPoint {
|
||||
return self.top_right;
|
||||
}
|
||||
|
||||
fn get_bottom_left(&self) -> ResultPoint {
|
||||
return self.bottom_left;
|
||||
}
|
||||
|
||||
fn get_bottom_right(&self) -> ResultPoint {
|
||||
return self.bottom_right;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
const BARCODE_ROW_UNKNOWN: i32 = -1;
|
||||
struct Codeword {
|
||||
|
||||
let start_x: i32;
|
||||
|
||||
let end_x: i32;
|
||||
|
||||
let bucket: i32;
|
||||
|
||||
let value: i32;
|
||||
|
||||
let row_number: i32 = BARCODE_ROW_UNKNOWN;
|
||||
}
|
||||
|
||||
impl Codeword {
|
||||
|
||||
fn new( start_x: i32, end_x: i32, bucket: i32, value: i32) -> Codeword {
|
||||
let .startX = start_x;
|
||||
let .endX = end_x;
|
||||
let .bucket = bucket;
|
||||
let .value = value;
|
||||
}
|
||||
|
||||
fn has_valid_row_number(&self) -> bool {
|
||||
return self.is_valid_row_number(self.row_number);
|
||||
}
|
||||
|
||||
fn is_valid_row_number(&self, row_number: i32) -> bool {
|
||||
return row_number != BARCODE_ROW_UNKNOWN && self.bucket == (row_number % 3) * 3;
|
||||
}
|
||||
|
||||
fn set_row_number_as_row_indicator_column(&self) {
|
||||
self.row_number = (self.value / 30) * 3 + self.bucket / 3;
|
||||
}
|
||||
|
||||
fn get_width(&self) -> i32 {
|
||||
return self.end_x - self.start_x;
|
||||
}
|
||||
|
||||
fn get_start_x(&self) -> i32 {
|
||||
return self.start_x;
|
||||
}
|
||||
|
||||
fn get_end_x(&self) -> i32 {
|
||||
return self.end_x;
|
||||
}
|
||||
|
||||
fn get_bucket(&self) -> i32 {
|
||||
return self.bucket;
|
||||
}
|
||||
|
||||
fn get_value(&self) -> i32 {
|
||||
return self.value;
|
||||
}
|
||||
|
||||
fn get_row_number(&self) -> i32 {
|
||||
return self.row_number;
|
||||
}
|
||||
|
||||
fn set_row_number(&self, row_number: i32) {
|
||||
self.rowNumber = row_number;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("{}|{}", self.row_number, self.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,857 +0,0 @@
|
||||
/*
|
||||
* 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::decoder;
|
||||
|
||||
/**
|
||||
* <p>This class contains the methods for decoding the PDF417 codewords.</p>
|
||||
*
|
||||
* @author SITA Lab (kevin.osullivan@sita.aero)
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
const TEXT_COMPACTION_MODE_LATCH: i32 = 900;
|
||||
|
||||
const BYTE_COMPACTION_MODE_LATCH: i32 = 901;
|
||||
|
||||
const NUMERIC_COMPACTION_MODE_LATCH: i32 = 902;
|
||||
|
||||
const BYTE_COMPACTION_MODE_LATCH_6: i32 = 924;
|
||||
|
||||
const ECI_USER_DEFINED: i32 = 925;
|
||||
|
||||
const ECI_GENERAL_PURPOSE: i32 = 926;
|
||||
|
||||
const ECI_CHARSET: i32 = 927;
|
||||
|
||||
const BEGIN_MACRO_PDF417_CONTROL_BLOCK: i32 = 928;
|
||||
|
||||
const BEGIN_MACRO_PDF417_OPTIONAL_FIELD: i32 = 923;
|
||||
|
||||
const MACRO_PDF417_TERMINATOR: i32 = 922;
|
||||
|
||||
const MODE_SHIFT_TO_BYTE_COMPACTION_MODE: i32 = 913;
|
||||
|
||||
const MAX_NUMERIC_CODEWORDS: i32 = 15;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME: i32 = 0;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT: i32 = 1;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP: i32 = 2;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_SENDER: i32 = 3;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE: i32 = 4;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE: i32 = 5;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM: i32 = 6;
|
||||
|
||||
const PL: i32 = 25;
|
||||
|
||||
const LL: i32 = 27;
|
||||
|
||||
const AS: i32 = 27;
|
||||
|
||||
const ML: i32 = 28;
|
||||
|
||||
const AL: i32 = 28;
|
||||
|
||||
const PS: i32 = 29;
|
||||
|
||||
const PAL: i32 = 29;
|
||||
|
||||
const PUNCT_CHARS: Vec<char> = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'".to_char_array();
|
||||
|
||||
const MIXED_CHARS: Vec<char> = "0123456789&\r\t,:#-.$/+%*=^".to_char_array();
|
||||
|
||||
/**
|
||||
* Table containing values for the exponent of 900.
|
||||
* This is used in the numeric compaction decode algorithm.
|
||||
*/
|
||||
const EXP900: Vec<BigInteger>;
|
||||
|
||||
const NUMBER_OF_SEQUENCE_CODEWORDS: i32 = 2;
|
||||
struct DecodedBitStreamParser {
|
||||
}
|
||||
|
||||
impl DecodedBitStreamParser {
|
||||
|
||||
enum Mode {
|
||||
|
||||
ALPHA(), LOWER(), MIXED(), PUNCT(), ALPHA_SHIFT(), PUNCT_SHIFT()
|
||||
}
|
||||
|
||||
static {
|
||||
EXP900 = : [Option<BigInteger>; 16] = [None; 16];
|
||||
EXP900[0] = BigInteger::ONE;
|
||||
let nine_hundred: BigInteger = BigInteger::value_of(900);
|
||||
EXP900[1] = nine_hundred;
|
||||
{
|
||||
let mut i: i32 = 2;
|
||||
while i < EXP900.len() {
|
||||
{
|
||||
EXP900[i] = EXP900[i - 1]::multiply(&nine_hundred);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn new() -> DecodedBitStreamParser {
|
||||
}
|
||||
|
||||
fn decode( codewords: &Vec<i32>, ec_level: &String) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
|
||||
let result: ECIStringBuilder = ECIStringBuilder::new(codewords.len() * 2);
|
||||
let code_index: i32 = ::text_compaction(&codewords, 1, result);
|
||||
let result_metadata: PDF417ResultMetadata = PDF417ResultMetadata::new();
|
||||
while code_index < codewords[0] {
|
||||
let code: i32 = codewords[code_index += 1 !!!check!!! post increment];
|
||||
match code {
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
code_index = ::text_compaction(&codewords, code_index, result);
|
||||
break;
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH_6 =>
|
||||
{
|
||||
code_index = ::byte_compaction(code, &codewords, code_index, result);
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
result.append(codewords[code_index += 1 !!!check!!! post increment] as char);
|
||||
break;
|
||||
}
|
||||
NUMERIC_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
code_index = ::numeric_compaction(&codewords, code_index, result);
|
||||
break;
|
||||
}
|
||||
ECI_CHARSET =>
|
||||
{
|
||||
result.append_e_c_i(codewords[code_index += 1 !!!check!!! post increment]);
|
||||
break;
|
||||
}
|
||||
ECI_GENERAL_PURPOSE =>
|
||||
{
|
||||
// Can't do anything with generic ECI; skip its 2 characters
|
||||
code_index += 2;
|
||||
break;
|
||||
}
|
||||
ECI_USER_DEFINED =>
|
||||
{
|
||||
// Can't do anything with user ECI; skip its 1 character
|
||||
code_index += 1;
|
||||
break;
|
||||
}
|
||||
BEGIN_MACRO_PDF417_CONTROL_BLOCK =>
|
||||
{
|
||||
code_index = ::decode_macro_block(&codewords, code_index, result_metadata);
|
||||
break;
|
||||
}
|
||||
BEGIN_MACRO_PDF417_OPTIONAL_FIELD =>
|
||||
{
|
||||
}
|
||||
MACRO_PDF417_TERMINATOR =>
|
||||
{
|
||||
// Should not see these outside a macro block
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// Default to text compaction. During testing numerous barcodes
|
||||
// appeared to be missing the starting mode. In these cases defaulting
|
||||
// to text compaction seems to work.
|
||||
code_index -= 1;
|
||||
code_index = ::text_compaction(&codewords, code_index, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.is_empty() && result_metadata.get_file_id() == null {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let decoder_result: DecoderResult = DecoderResult::new(null, &result.to_string(), null, &ec_level);
|
||||
decoder_result.set_other(result_metadata);
|
||||
return Ok(decoder_result);
|
||||
}
|
||||
|
||||
fn decode_macro_block( codewords: &Vec<i32>, code_index: i32, result_metadata: &PDF417ResultMetadata) -> /* throws FormatException */Result<i32, Rc<Exception>> {
|
||||
if code_index + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0] {
|
||||
// we must have at least two bytes left for the segment index
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let segment_index_array: [i32; NUMBER_OF_SEQUENCE_CODEWORDS] = [0; NUMBER_OF_SEQUENCE_CODEWORDS];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < NUMBER_OF_SEQUENCE_CODEWORDS {
|
||||
{
|
||||
segment_index_array[i] = codewords[code_index];
|
||||
}
|
||||
i += 1;
|
||||
code_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let segment_index_string: String = ::decode_base900to_base10(&segment_index_array, NUMBER_OF_SEQUENCE_CODEWORDS);
|
||||
if segment_index_string.is_empty() {
|
||||
result_metadata.set_segment_index(0);
|
||||
} else {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
result_metadata.set_segment_index(&Integer::parse_int(&segment_index_string));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( nfe: &NumberFormatException) {
|
||||
throw FormatException::get_format_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
// Decoding the fileId codewords as 0-899 numbers, each 0-filled to width 3. This follows the spec
|
||||
// (See ISO/IEC 15438:2015 Annex H.6) and preserves all info, but some generators (e.g. TEC-IT) write
|
||||
// the fileId using text compaction, so in those cases the fileId will appear mangled.
|
||||
let file_id: StringBuilder = StringBuilder::new();
|
||||
while code_index < codewords[0] && code_index < codewords.len() && codewords[code_index] != MACRO_PDF417_TERMINATOR && codewords[code_index] != BEGIN_MACRO_PDF417_OPTIONAL_FIELD {
|
||||
file_id.append(&String::format("%03d", codewords[code_index]));
|
||||
code_index += 1;
|
||||
}
|
||||
if file_id.length() == 0 {
|
||||
// at least one fileId codeword is required (Annex H.2)
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
result_metadata.set_file_id(&file_id.to_string());
|
||||
let optional_fields_start: i32 = -1;
|
||||
if codewords[code_index] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD {
|
||||
optional_fields_start = code_index + 1;
|
||||
}
|
||||
while code_index < codewords[0] {
|
||||
match codewords[code_index] {
|
||||
BEGIN_MACRO_PDF417_OPTIONAL_FIELD =>
|
||||
{
|
||||
code_index += 1;
|
||||
match codewords[code_index] {
|
||||
MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME =>
|
||||
{
|
||||
let file_name: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::text_compaction(&codewords, code_index + 1, file_name);
|
||||
result_metadata.set_file_name(&file_name.to_string());
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_SENDER =>
|
||||
{
|
||||
let sender: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::text_compaction(&codewords, code_index + 1, sender);
|
||||
result_metadata.set_sender(&sender.to_string());
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE =>
|
||||
{
|
||||
let addressee: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::text_compaction(&codewords, code_index + 1, addressee);
|
||||
result_metadata.set_addressee(&addressee.to_string());
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT =>
|
||||
{
|
||||
let segment_count: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::numeric_compaction(&codewords, code_index + 1, segment_count);
|
||||
result_metadata.set_segment_count(&Integer::parse_int(&segment_count.to_string()));
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP =>
|
||||
{
|
||||
let timestamp: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::numeric_compaction(&codewords, code_index + 1, timestamp);
|
||||
result_metadata.set_timestamp(&Long::parse_long(×tamp.to_string()));
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM =>
|
||||
{
|
||||
let checksum: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::numeric_compaction(&codewords, code_index + 1, checksum);
|
||||
result_metadata.set_checksum(&Integer::parse_int(&checksum.to_string()));
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE =>
|
||||
{
|
||||
let file_size: ECIStringBuilder = ECIStringBuilder::new();
|
||||
code_index = ::numeric_compaction(&codewords, code_index + 1, file_size);
|
||||
result_metadata.set_file_size(&Long::parse_long(&file_size.to_string()));
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
MACRO_PDF417_TERMINATOR =>
|
||||
{
|
||||
code_index += 1;
|
||||
result_metadata.set_last_segment(true);
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy optional fields to additional options
|
||||
if optional_fields_start != -1 {
|
||||
let optional_fields_length: i32 = code_index - optional_fields_start;
|
||||
if result_metadata.is_last_segment() {
|
||||
// do not include terminator
|
||||
optional_fields_length -= 1;
|
||||
}
|
||||
result_metadata.set_optional_data(&Arrays::copy_of_range(&codewords, optional_fields_start, optional_fields_start + optional_fields_length));
|
||||
}
|
||||
return Ok(code_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be
|
||||
* encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as
|
||||
* well as selected control characters.
|
||||
*
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
fn text_compaction( codewords: &Vec<i32>, code_index: i32, result: &ECIStringBuilder) -> /* throws FormatException */Result<i32, Rc<Exception>> {
|
||||
// 2 character per codeword
|
||||
let text_compaction_data: [i32; (codewords[0] - code_index) * 2] = [0; (codewords[0] - code_index) * 2];
|
||||
// Used to hold the byte compaction value if there is a mode shift
|
||||
let byte_compaction_data: [i32; (codewords[0] - code_index) * 2] = [0; (codewords[0] - code_index) * 2];
|
||||
let mut index: i32 = 0;
|
||||
let mut end: bool = false;
|
||||
let sub_mode: Mode = Mode::ALPHA;
|
||||
while (code_index < codewords[0]) && !end {
|
||||
let mut code: i32 = codewords[code_index += 1 !!!check!!! post increment];
|
||||
if code < TEXT_COMPACTION_MODE_LATCH {
|
||||
text_compaction_data[index] = code / 30;
|
||||
text_compaction_data[index + 1] = code % 30;
|
||||
index += 2;
|
||||
} else {
|
||||
match code {
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
// reinitialize text compaction mode to alpha sub mode
|
||||
text_compaction_data[index += 1 !!!check!!! post increment] = TEXT_COMPACTION_MODE_LATCH;
|
||||
break;
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH_6 =>
|
||||
{
|
||||
}
|
||||
NUMERIC_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
}
|
||||
BEGIN_MACRO_PDF417_CONTROL_BLOCK =>
|
||||
{
|
||||
}
|
||||
BEGIN_MACRO_PDF417_OPTIONAL_FIELD =>
|
||||
{
|
||||
}
|
||||
MACRO_PDF417_TERMINATOR =>
|
||||
{
|
||||
code_index -= 1;
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
// The Mode Shift codeword 913 shall cause a temporary
|
||||
// switch from Text Compaction mode to Byte Compaction mode.
|
||||
// This switch shall be in effect for only the next codeword,
|
||||
// after which the mode shall revert to the prevailing sub-mode
|
||||
// of the Text Compaction mode. Codeword 913 is only available
|
||||
// in Text Compaction mode; its use is described in 5.4.2.4.
|
||||
text_compaction_data[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
|
||||
code = codewords[code_index += 1 !!!check!!! post increment];
|
||||
byte_compaction_data[index] = code;
|
||||
index += 1;
|
||||
break;
|
||||
}
|
||||
ECI_CHARSET =>
|
||||
{
|
||||
sub_mode = ::decode_text_compaction(&text_compaction_data, &byte_compaction_data, index, result, sub_mode);
|
||||
result.append_e_c_i(codewords[code_index += 1 !!!check!!! post increment]);
|
||||
text_compaction_data = : [i32; (codewords[0] - code_index) * 2] = [0; (codewords[0] - code_index) * 2];
|
||||
byte_compaction_data = : [i32; (codewords[0] - code_index) * 2] = [0; (codewords[0] - code_index) * 2];
|
||||
index = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
::decode_text_compaction(&text_compaction_data, &byte_compaction_data, index, result, sub_mode);
|
||||
return Ok(code_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Text Compaction mode includes all the printable ASCII characters
|
||||
* (i.e. values from 32 to 126) and three ASCII control characters: HT or tab
|
||||
* (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage
|
||||
* return (ASCII value 13). The Text Compaction mode also includes various latch
|
||||
* and shift characters which are used exclusively within the mode. The Text
|
||||
* Compaction mode encodes up to 2 characters per codeword. The compaction rules
|
||||
* for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode
|
||||
* switches are defined in 5.4.2.3.
|
||||
*
|
||||
* @param textCompactionData The text compaction data.
|
||||
* @param byteCompactionData The byte compaction data if there
|
||||
* was a mode shift.
|
||||
* @param length The size of the text compaction and byte compaction data.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @param startMode The mode in which decoding starts
|
||||
* @return The mode in which decoding ended
|
||||
*/
|
||||
fn decode_text_compaction( text_compaction_data: &Vec<i32>, byte_compaction_data: &Vec<i32>, length: i32, result: &ECIStringBuilder, start_mode: &Mode) -> Mode {
|
||||
// Beginning from an initial state
|
||||
// The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text
|
||||
// Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text
|
||||
// Compaction mode shall always switch to the Text Compaction Alpha sub-mode.
|
||||
let sub_mode: Mode = start_mode;
|
||||
let prior_to_shift_mode: Mode = start_mode;
|
||||
let latched_mode: Mode = start_mode;
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
let sub_mode_ch: i32 = text_compaction_data[i];
|
||||
let mut ch: char = 0;
|
||||
match sub_mode {
|
||||
ALPHA =>
|
||||
{
|
||||
// Alpha (uppercase alphabetic)
|
||||
if sub_mode_ch < 26 {
|
||||
// Upper case Alpha Character
|
||||
ch = ('A' + sub_mode_ch) as char;
|
||||
} else {
|
||||
match sub_mode_ch {
|
||||
26 =>
|
||||
{
|
||||
ch = ' ';
|
||||
break;
|
||||
}
|
||||
LL =>
|
||||
{
|
||||
sub_mode = Mode::LOWER;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
ML =>
|
||||
{
|
||||
sub_mode = Mode::MIXED;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
PS =>
|
||||
{
|
||||
// Shift to punctuation
|
||||
prior_to_shift_mode = sub_mode;
|
||||
sub_mode = Mode::PUNCT_SHIFT;
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
result.append(byte_compaction_data[i] as char);
|
||||
break;
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
sub_mode = Mode::ALPHA;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
LOWER =>
|
||||
{
|
||||
// Lower (lowercase alphabetic)
|
||||
if sub_mode_ch < 26 {
|
||||
ch = ('a' + sub_mode_ch) as char;
|
||||
} else {
|
||||
match sub_mode_ch {
|
||||
26 =>
|
||||
{
|
||||
ch = ' ';
|
||||
break;
|
||||
}
|
||||
AS =>
|
||||
{
|
||||
// Shift to alpha
|
||||
prior_to_shift_mode = sub_mode;
|
||||
sub_mode = Mode::ALPHA_SHIFT;
|
||||
break;
|
||||
}
|
||||
ML =>
|
||||
{
|
||||
sub_mode = Mode::MIXED;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
PS =>
|
||||
{
|
||||
// Shift to punctuation
|
||||
prior_to_shift_mode = sub_mode;
|
||||
sub_mode = Mode::PUNCT_SHIFT;
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
result.append(byte_compaction_data[i] as char);
|
||||
break;
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
sub_mode = Mode::ALPHA;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
MIXED =>
|
||||
{
|
||||
// Mixed (numeric and some punctuation)
|
||||
if sub_mode_ch < PL {
|
||||
ch = MIXED_CHARS[sub_mode_ch];
|
||||
} else {
|
||||
match sub_mode_ch {
|
||||
PL =>
|
||||
{
|
||||
sub_mode = Mode::PUNCT;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
26 =>
|
||||
{
|
||||
ch = ' ';
|
||||
break;
|
||||
}
|
||||
LL =>
|
||||
{
|
||||
sub_mode = Mode::LOWER;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
AL =>
|
||||
{
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
sub_mode = Mode::ALPHA;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
PS =>
|
||||
{
|
||||
// Shift to punctuation
|
||||
prior_to_shift_mode = sub_mode;
|
||||
sub_mode = Mode::PUNCT_SHIFT;
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
result.append(byte_compaction_data[i] as char);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
PUNCT =>
|
||||
{
|
||||
// Punctuation
|
||||
if sub_mode_ch < PAL {
|
||||
ch = PUNCT_CHARS[sub_mode_ch];
|
||||
} else {
|
||||
match sub_mode_ch {
|
||||
PAL =>
|
||||
{
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
sub_mode = Mode::ALPHA;
|
||||
latched_mode = sub_mode;
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
result.append(byte_compaction_data[i] as char);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
ALPHA_SHIFT =>
|
||||
{
|
||||
// Restore sub-mode
|
||||
sub_mode = prior_to_shift_mode;
|
||||
if sub_mode_ch < 26 {
|
||||
ch = ('A' + sub_mode_ch) as char;
|
||||
} else {
|
||||
match sub_mode_ch {
|
||||
26 =>
|
||||
{
|
||||
ch = ' ';
|
||||
break;
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
sub_mode = Mode::ALPHA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
PUNCT_SHIFT =>
|
||||
{
|
||||
// Restore sub-mode
|
||||
sub_mode = prior_to_shift_mode;
|
||||
if sub_mode_ch < PAL {
|
||||
ch = PUNCT_CHARS[sub_mode_ch];
|
||||
} else {
|
||||
match sub_mode_ch {
|
||||
PAL =>
|
||||
{
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
sub_mode = Mode::ALPHA;
|
||||
break;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
{
|
||||
// PS before Shift-to-Byte is used as a padding character,
|
||||
// see 5.4.2.4 of the specification
|
||||
result.append(byte_compaction_data[i] as char);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ch != 0 {
|
||||
// Append decoded character to result
|
||||
result.append(ch);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return latched_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.
|
||||
* This includes all ASCII characters value 0 to 127 inclusive and provides for international
|
||||
* character set support.
|
||||
*
|
||||
* @param mode The byte compaction mode i.e. 901 or 924
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
fn byte_compaction( mode: i32, codewords: &Vec<i32>, code_index: i32, result: &ECIStringBuilder) -> /* throws FormatException */Result<i32, Rc<Exception>> {
|
||||
let mut end: bool = false;
|
||||
while code_index < codewords[0] && !end {
|
||||
//handle leading ECIs
|
||||
while code_index < codewords[0] && codewords[code_index] == ECI_CHARSET {
|
||||
result.append_e_c_i(codewords[code_index += 1]);
|
||||
code_index += 1;
|
||||
}
|
||||
if code_index >= codewords[0] || codewords[code_index] >= TEXT_COMPACTION_MODE_LATCH {
|
||||
end = true;
|
||||
} else {
|
||||
//decode one block of 5 codewords to 6 bytes
|
||||
let mut value: i64 = 0;
|
||||
let mut count: i32 = 0;
|
||||
loop { {
|
||||
value = 900 * value + codewords[code_index += 1 !!!check!!! post increment];
|
||||
count += 1;
|
||||
}if !(count < 5 && code_index < codewords[0] && codewords[code_index] < TEXT_COMPACTION_MODE_LATCH) break;}
|
||||
if count == 5 && (mode == BYTE_COMPACTION_MODE_LATCH_6 || code_index < codewords[0] && codewords[code_index] < TEXT_COMPACTION_MODE_LATCH) {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 6 {
|
||||
{
|
||||
result.append((value >> (8 * (5 - i))) as i8);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
code_index -= count;
|
||||
while (code_index < codewords[0]) && !end {
|
||||
let code: i32 = codewords[code_index += 1 !!!check!!! post increment];
|
||||
if code < TEXT_COMPACTION_MODE_LATCH {
|
||||
result.append(code as i8);
|
||||
} else if code == ECI_CHARSET {
|
||||
result.append_e_c_i(codewords[code_index += 1 !!!check!!! post increment]);
|
||||
} else {
|
||||
code_index -= 1;
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(code_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.
|
||||
*
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
fn numeric_compaction( codewords: &Vec<i32>, code_index: i32, result: &ECIStringBuilder) -> /* throws FormatException */Result<i32, Rc<Exception>> {
|
||||
let mut count: i32 = 0;
|
||||
let mut end: bool = false;
|
||||
let numeric_codewords: [i32; MAX_NUMERIC_CODEWORDS] = [0; MAX_NUMERIC_CODEWORDS];
|
||||
while code_index < codewords[0] && !end {
|
||||
let code: i32 = codewords[code_index += 1 !!!check!!! post increment];
|
||||
if code_index == codewords[0] {
|
||||
end = true;
|
||||
}
|
||||
if code < TEXT_COMPACTION_MODE_LATCH {
|
||||
numeric_codewords[count] = code;
|
||||
count += 1;
|
||||
} else {
|
||||
match code {
|
||||
TEXT_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH =>
|
||||
{
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH_6 =>
|
||||
{
|
||||
}
|
||||
BEGIN_MACRO_PDF417_CONTROL_BLOCK =>
|
||||
{
|
||||
}
|
||||
BEGIN_MACRO_PDF417_OPTIONAL_FIELD =>
|
||||
{
|
||||
}
|
||||
MACRO_PDF417_TERMINATOR =>
|
||||
{
|
||||
}
|
||||
ECI_CHARSET =>
|
||||
{
|
||||
code_index -= 1;
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count % MAX_NUMERIC_CODEWORDS == 0 || code == NUMERIC_COMPACTION_MODE_LATCH || end) && count > 0 {
|
||||
// Re-invoking Numeric Compaction mode (by using codeword 902
|
||||
// while in Numeric Compaction mode) serves to terminate the
|
||||
// current Numeric Compaction mode grouping as described in 5.4.4.2,
|
||||
// and then to start a new one grouping.
|
||||
result.append(&::decode_base900to_base10(&numeric_codewords, count));
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
return Ok(code_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of Numeric Compacted codewords from Base 900 to Base 10.
|
||||
*
|
||||
* @param codewords The array of codewords
|
||||
* @param count The number of codewords
|
||||
* @return The decoded string representing the Numeric data.
|
||||
*/
|
||||
/*
|
||||
EXAMPLE
|
||||
Encode the fifteen digit numeric string 000213298174000
|
||||
Prefix the numeric string with a 1 and set the initial value of
|
||||
t = 1 000 213 298 174 000
|
||||
Calculate codeword 0
|
||||
d0 = 1 000 213 298 174 000 mod 900 = 200
|
||||
|
||||
t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082
|
||||
Calculate codeword 1
|
||||
d1 = 1 111 348 109 082 mod 900 = 282
|
||||
|
||||
t = 1 111 348 109 082 div 900 = 1 234 831 232
|
||||
Calculate codeword 2
|
||||
d2 = 1 234 831 232 mod 900 = 632
|
||||
|
||||
t = 1 234 831 232 div 900 = 1 372 034
|
||||
Calculate codeword 3
|
||||
d3 = 1 372 034 mod 900 = 434
|
||||
|
||||
t = 1 372 034 div 900 = 1 524
|
||||
Calculate codeword 4
|
||||
d4 = 1 524 mod 900 = 624
|
||||
|
||||
t = 1 524 div 900 = 1
|
||||
Calculate codeword 5
|
||||
d5 = 1 mod 900 = 1
|
||||
t = 1 div 900 = 0
|
||||
Codeword sequence is: 1, 624, 434, 632, 282, 200
|
||||
|
||||
Decode the above codewords involves
|
||||
1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +
|
||||
632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000
|
||||
|
||||
Remove leading 1 => Result is 000213298174000
|
||||
*/
|
||||
fn decode_base900to_base10( codewords: &Vec<i32>, count: i32) -> /* throws FormatException */Result<String, Rc<Exception>> {
|
||||
let mut result: BigInteger = BigInteger::ZERO;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < count {
|
||||
{
|
||||
result = result.add(&EXP900[count - i - 1]::multiply(&BigInteger::value_of(codewords[i])));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let result_string: String = result.to_string();
|
||||
if result_string.char_at(0) != '1' {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
return Ok(result_string.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,367 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
const ADJUST_ROW_NUMBER_SKIP: i32 = 2;
|
||||
struct DetectionResult {
|
||||
|
||||
let barcode_metadata: BarcodeMetadata;
|
||||
|
||||
let detection_result_columns: Vec<DetectionResultColumn>;
|
||||
|
||||
let bounding_box: BoundingBox;
|
||||
|
||||
let barcode_column_count: i32;
|
||||
}
|
||||
|
||||
impl DetectionResult {
|
||||
|
||||
fn new( barcode_metadata: &BarcodeMetadata, bounding_box: &BoundingBox) -> DetectionResult {
|
||||
let .barcodeMetadata = barcode_metadata;
|
||||
let .barcodeColumnCount = barcode_metadata.get_column_count();
|
||||
let .boundingBox = bounding_box;
|
||||
detection_result_columns = : [Option<DetectionResultColumn>; barcode_column_count + 2] = [None; barcode_column_count + 2];
|
||||
}
|
||||
|
||||
fn get_detection_result_columns(&self) -> Vec<DetectionResultColumn> {
|
||||
self.adjust_indicator_column_row_numbers(self.detection_result_columns[0]);
|
||||
self.adjust_indicator_column_row_numbers(self.detection_result_columns[self.barcode_column_count + 1]);
|
||||
let unadjusted_codeword_count: i32 = PDF417Common.MAX_CODEWORDS_IN_BARCODE;
|
||||
let previous_unadjusted_count: i32;
|
||||
loop { {
|
||||
previous_unadjusted_count = unadjusted_codeword_count;
|
||||
unadjusted_codeword_count = self.adjust_row_numbers();
|
||||
}if !(unadjusted_codeword_count > 0 && unadjusted_codeword_count < previous_unadjusted_count) break;}
|
||||
return self.detection_result_columns;
|
||||
}
|
||||
|
||||
fn adjust_indicator_column_row_numbers(&self, detection_result_column: &DetectionResultColumn) {
|
||||
if detection_result_column != null {
|
||||
(detection_result_column as DetectionResultRowIndicatorColumn).adjust_complete_indicator_column_row_numbers(self.barcode_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO ensure that no detected codewords with unknown row number are left
|
||||
// we should be able to estimate the row height and use it as a hint for the row number
|
||||
// we should also fill the rows top to bottom and bottom to top
|
||||
/**
|
||||
* @return number of codewords which don't have a valid row number. Note that the count is not accurate as codewords
|
||||
* will be counted several times. It just serves as an indicator to see when we can stop adjusting row numbers
|
||||
*/
|
||||
fn adjust_row_numbers(&self) -> i32 {
|
||||
let unadjusted_count: i32 = self.adjust_row_numbers_by_row();
|
||||
if unadjusted_count == 0 {
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
let barcode_column: i32 = 1;
|
||||
while barcode_column < self.barcode_column_count + 1 {
|
||||
{
|
||||
let codewords: Vec<Codeword> = self.detection_result_columns[barcode_column].get_codewords();
|
||||
{
|
||||
let codewords_row: i32 = 0;
|
||||
while codewords_row < codewords.len() {
|
||||
{
|
||||
if codewords[codewords_row] == null {
|
||||
continue;
|
||||
}
|
||||
if !codewords[codewords_row].has_valid_row_number() {
|
||||
self.adjust_row_numbers(barcode_column, codewords_row, codewords);
|
||||
}
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
barcode_column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return unadjusted_count;
|
||||
}
|
||||
|
||||
fn adjust_row_numbers_by_row(&self) -> i32 {
|
||||
self.adjust_row_numbers_from_both_r_i();
|
||||
// TODO we should only do full row adjustments if row numbers of left and right row indicator column match.
|
||||
// Maybe it's even better to calculated the height (in codeword rows) and divide it by the number of barcode
|
||||
// rows. This, together with the LRI and RRI row numbers should allow us to get a good estimate where a row
|
||||
// number starts and ends.
|
||||
let unadjusted_count: i32 = self.adjust_row_numbers_from_l_r_i();
|
||||
return unadjusted_count + self.adjust_row_numbers_from_r_r_i();
|
||||
}
|
||||
|
||||
fn adjust_row_numbers_from_both_r_i(&self) {
|
||||
if self.detection_result_columns[0] == null || self.detection_result_columns[self.barcode_column_count + 1] == null {
|
||||
return;
|
||||
}
|
||||
const LRIcodewords: Vec<Codeword> = self.detection_result_columns[0].get_codewords();
|
||||
const RRIcodewords: Vec<Codeword> = self.detection_result_columns[self.barcode_column_count + 1].get_codewords();
|
||||
{
|
||||
let codewords_row: i32 = 0;
|
||||
while codewords_row < LRIcodewords.len() {
|
||||
{
|
||||
if LRIcodewords[codewords_row] != null && RRIcodewords[codewords_row] != null && LRIcodewords[codewords_row]::get_row_number() == RRIcodewords[codewords_row]::get_row_number() {
|
||||
{
|
||||
let barcode_column: i32 = 1;
|
||||
while barcode_column <= self.barcode_column_count {
|
||||
{
|
||||
let codeword: Codeword = self.detection_result_columns[barcode_column].get_codewords()[codewords_row];
|
||||
if codeword == null {
|
||||
continue;
|
||||
}
|
||||
codeword.set_row_number(&LRIcodewords[codewords_row]::get_row_number());
|
||||
if !codeword.has_valid_row_number() {
|
||||
self.detection_result_columns[barcode_column].get_codewords()[codewords_row] = null;
|
||||
}
|
||||
}
|
||||
barcode_column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn adjust_row_numbers_from_r_r_i(&self) -> i32 {
|
||||
if self.detection_result_columns[self.barcode_column_count + 1] == null {
|
||||
return 0;
|
||||
}
|
||||
let unadjusted_count: i32 = 0;
|
||||
let codewords: Vec<Codeword> = self.detection_result_columns[self.barcode_column_count + 1].get_codewords();
|
||||
{
|
||||
let codewords_row: i32 = 0;
|
||||
while codewords_row < codewords.len() {
|
||||
{
|
||||
if codewords[codewords_row] == null {
|
||||
continue;
|
||||
}
|
||||
let row_indicator_row_number: i32 = codewords[codewords_row].get_row_number();
|
||||
let invalid_row_counts: i32 = 0;
|
||||
{
|
||||
let barcode_column: i32 = self.barcode_column_count + 1;
|
||||
while barcode_column > 0 && invalid_row_counts < ADJUST_ROW_NUMBER_SKIP {
|
||||
{
|
||||
let codeword: Codeword = self.detection_result_columns[barcode_column].get_codewords()[codewords_row];
|
||||
if codeword != null {
|
||||
invalid_row_counts = ::adjust_row_number_if_valid(row_indicator_row_number, invalid_row_counts, codeword);
|
||||
if !codeword.has_valid_row_number() {
|
||||
unadjusted_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
barcode_column -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return unadjusted_count;
|
||||
}
|
||||
|
||||
fn adjust_row_numbers_from_l_r_i(&self) -> i32 {
|
||||
if self.detection_result_columns[0] == null {
|
||||
return 0;
|
||||
}
|
||||
let unadjusted_count: i32 = 0;
|
||||
let codewords: Vec<Codeword> = self.detection_result_columns[0].get_codewords();
|
||||
{
|
||||
let codewords_row: i32 = 0;
|
||||
while codewords_row < codewords.len() {
|
||||
{
|
||||
if codewords[codewords_row] == null {
|
||||
continue;
|
||||
}
|
||||
let row_indicator_row_number: i32 = codewords[codewords_row].get_row_number();
|
||||
let invalid_row_counts: i32 = 0;
|
||||
{
|
||||
let barcode_column: i32 = 1;
|
||||
while barcode_column < self.barcode_column_count + 1 && invalid_row_counts < ADJUST_ROW_NUMBER_SKIP {
|
||||
{
|
||||
let codeword: Codeword = self.detection_result_columns[barcode_column].get_codewords()[codewords_row];
|
||||
if codeword != null {
|
||||
invalid_row_counts = ::adjust_row_number_if_valid(row_indicator_row_number, invalid_row_counts, codeword);
|
||||
if !codeword.has_valid_row_number() {
|
||||
unadjusted_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
barcode_column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return unadjusted_count;
|
||||
}
|
||||
|
||||
fn adjust_row_number_if_valid( row_indicator_row_number: i32, invalid_row_counts: i32, codeword: &Codeword) -> i32 {
|
||||
if codeword == null {
|
||||
return invalid_row_counts;
|
||||
}
|
||||
if !codeword.has_valid_row_number() {
|
||||
if codeword.is_valid_row_number(row_indicator_row_number) {
|
||||
codeword.set_row_number(row_indicator_row_number);
|
||||
invalid_row_counts = 0;
|
||||
} else {
|
||||
invalid_row_counts += 1;
|
||||
}
|
||||
}
|
||||
return invalid_row_counts;
|
||||
}
|
||||
|
||||
fn adjust_row_numbers(&self, barcode_column: i32, codewords_row: i32, codewords: &Vec<Codeword>) {
|
||||
let codeword: Codeword = codewords[codewords_row];
|
||||
let previous_column_codewords: Vec<Codeword> = self.detection_result_columns[barcode_column - 1].get_codewords();
|
||||
let next_column_codewords: Vec<Codeword> = previous_column_codewords;
|
||||
if self.detection_result_columns[barcode_column + 1] != null {
|
||||
next_column_codewords = self.detection_result_columns[barcode_column + 1].get_codewords();
|
||||
}
|
||||
let other_codewords: [Option<Codeword>; 14] = [None; 14];
|
||||
other_codewords[2] = previous_column_codewords[codewords_row];
|
||||
other_codewords[3] = next_column_codewords[codewords_row];
|
||||
if codewords_row > 0 {
|
||||
other_codewords[0] = codewords[codewords_row - 1];
|
||||
other_codewords[4] = previous_column_codewords[codewords_row - 1];
|
||||
other_codewords[5] = next_column_codewords[codewords_row - 1];
|
||||
}
|
||||
if codewords_row > 1 {
|
||||
other_codewords[8] = codewords[codewords_row - 2];
|
||||
other_codewords[10] = previous_column_codewords[codewords_row - 2];
|
||||
other_codewords[11] = next_column_codewords[codewords_row - 2];
|
||||
}
|
||||
if codewords_row < codewords.len() - 1 {
|
||||
other_codewords[1] = codewords[codewords_row + 1];
|
||||
other_codewords[6] = previous_column_codewords[codewords_row + 1];
|
||||
other_codewords[7] = next_column_codewords[codewords_row + 1];
|
||||
}
|
||||
if codewords_row < codewords.len() - 2 {
|
||||
other_codewords[9] = codewords[codewords_row + 2];
|
||||
other_codewords[12] = previous_column_codewords[codewords_row + 2];
|
||||
other_codewords[13] = next_column_codewords[codewords_row + 2];
|
||||
}
|
||||
for let other_codeword: Codeword in other_codewords {
|
||||
if ::adjust_row_number(codeword, other_codeword) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if row number was adjusted, false otherwise
|
||||
*/
|
||||
fn adjust_row_number( codeword: &Codeword, other_codeword: &Codeword) -> bool {
|
||||
if other_codeword == null {
|
||||
return false;
|
||||
}
|
||||
if other_codeword.has_valid_row_number() && other_codeword.get_bucket() == codeword.get_bucket() {
|
||||
codeword.set_row_number(&other_codeword.get_row_number());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn get_barcode_column_count(&self) -> i32 {
|
||||
return self.barcode_column_count;
|
||||
}
|
||||
|
||||
fn get_barcode_row_count(&self) -> i32 {
|
||||
return self.barcode_metadata.get_row_count();
|
||||
}
|
||||
|
||||
fn get_barcode_e_c_level(&self) -> i32 {
|
||||
return self.barcode_metadata.get_error_correction_level();
|
||||
}
|
||||
|
||||
fn set_bounding_box(&self, bounding_box: &BoundingBox) {
|
||||
self.boundingBox = bounding_box;
|
||||
}
|
||||
|
||||
fn get_bounding_box(&self) -> BoundingBox {
|
||||
return self.bounding_box;
|
||||
}
|
||||
|
||||
fn set_detection_result_column(&self, barcode_column: i32, detection_result_column: &DetectionResultColumn) {
|
||||
self.detection_result_columns[barcode_column] = detection_result_column;
|
||||
}
|
||||
|
||||
fn get_detection_result_column(&self, barcode_column: i32) -> DetectionResultColumn {
|
||||
return self.detection_result_columns[barcode_column];
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let row_indicator_column: DetectionResultColumn = self.detection_result_columns[0];
|
||||
if row_indicator_column == null {
|
||||
row_indicator_column = self.detection_result_columns[self.barcode_column_count + 1];
|
||||
}
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
( let formatter: Formatter = Formatter::new()) {
|
||||
{
|
||||
let codewords_row: i32 = 0;
|
||||
while codewords_row < row_indicator_column.get_codewords().len() {
|
||||
{
|
||||
formatter.format("CW %3d:", codewords_row);
|
||||
{
|
||||
let barcode_column: i32 = 0;
|
||||
while barcode_column < self.barcode_column_count + 2 {
|
||||
{
|
||||
if self.detection_result_columns[barcode_column] == null {
|
||||
formatter.format(" | ");
|
||||
continue;
|
||||
}
|
||||
let codeword: Codeword = self.detection_result_columns[barcode_column].get_codewords()[codewords_row];
|
||||
if codeword == null {
|
||||
formatter.format(" | ");
|
||||
continue;
|
||||
}
|
||||
formatter.format(" %3d|%3d", &codeword.get_row_number(), &codeword.get_value());
|
||||
}
|
||||
barcode_column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
formatter.format("%n");
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return formatter.to_string();
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
0 => break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
const MAX_NEARBY_DISTANCE: i32 = 5;
|
||||
struct DetectionResultColumn {
|
||||
|
||||
let bounding_box: BoundingBox;
|
||||
|
||||
let mut codewords: Vec<Codeword>;
|
||||
}
|
||||
|
||||
impl DetectionResultColumn {
|
||||
|
||||
fn new( bounding_box: &BoundingBox) -> DetectionResultColumn {
|
||||
let .boundingBox = BoundingBox::new(bounding_box);
|
||||
codewords = : [Option<Codeword>; bounding_box.get_max_y() - bounding_box.get_min_y() + 1] = [None; bounding_box.get_max_y() - bounding_box.get_min_y() + 1];
|
||||
}
|
||||
|
||||
fn get_codeword_nearby(&self, image_row: i32) -> Codeword {
|
||||
let mut codeword: Codeword = self.get_codeword(image_row);
|
||||
if codeword != null {
|
||||
return codeword;
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i < MAX_NEARBY_DISTANCE {
|
||||
{
|
||||
let near_image_row: i32 = self.image_row_to_codeword_index(image_row) - i;
|
||||
if near_image_row >= 0 {
|
||||
codeword = self.codewords[near_image_row];
|
||||
if codeword != null {
|
||||
return codeword;
|
||||
}
|
||||
}
|
||||
near_image_row = self.image_row_to_codeword_index(image_row) + i;
|
||||
if near_image_row < self.codewords.len() {
|
||||
codeword = self.codewords[near_image_row];
|
||||
if codeword != null {
|
||||
return codeword;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn image_row_to_codeword_index(&self, image_row: i32) -> i32 {
|
||||
return image_row - self.bounding_box.get_min_y();
|
||||
}
|
||||
|
||||
fn set_codeword(&self, image_row: i32, codeword: &Codeword) {
|
||||
self.codewords[self.image_row_to_codeword_index(image_row)] = codeword;
|
||||
}
|
||||
|
||||
fn get_codeword(&self, image_row: i32) -> Codeword {
|
||||
return self.codewords[self.image_row_to_codeword_index(image_row)];
|
||||
}
|
||||
|
||||
fn get_bounding_box(&self) -> BoundingBox {
|
||||
return self.bounding_box;
|
||||
}
|
||||
|
||||
fn get_codewords(&self) -> Vec<Codeword> {
|
||||
return self.codewords;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
( let formatter: Formatter = Formatter::new()) {
|
||||
let mut row: i32 = 0;
|
||||
for let codeword: Codeword in self.codewords {
|
||||
if codeword == null {
|
||||
formatter.format("%3d: | %n", row += 1 !!!check!!! post increment);
|
||||
continue;
|
||||
}
|
||||
formatter.format("%3d: %3d|%3d%n", row += 1 !!!check!!! post increment, &codeword.get_row_number(), &codeword.get_value());
|
||||
}
|
||||
return formatter.to_string();
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
0 => break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
struct DetectionResultRowIndicatorColumn {
|
||||
super: DetectionResultColumn;
|
||||
|
||||
let is_left: bool;
|
||||
}
|
||||
|
||||
impl DetectionResultRowIndicatorColumn {
|
||||
|
||||
fn new( bounding_box: &BoundingBox, is_left: bool) -> DetectionResultRowIndicatorColumn {
|
||||
super(bounding_box);
|
||||
let .isLeft = is_left;
|
||||
}
|
||||
|
||||
fn set_row_numbers(&self) {
|
||||
for let codeword: Codeword in get_codewords() {
|
||||
if codeword != null {
|
||||
codeword.set_row_number_as_row_indicator_column();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO implement properly
|
||||
// TODO maybe we should add missing codewords to store the correct row number to make
|
||||
// finding row numbers for other columns easier
|
||||
// use row height count to make detection of invalid row numbers more reliable
|
||||
fn adjust_complete_indicator_column_row_numbers(&self, barcode_metadata: &BarcodeMetadata) {
|
||||
let mut codewords: Vec<Codeword> = get_codewords();
|
||||
self.set_row_numbers();
|
||||
self.remove_incorrect_codewords(codewords, barcode_metadata);
|
||||
let bounding_box: BoundingBox = get_bounding_box();
|
||||
let top: ResultPoint = if self.is_left { bounding_box.get_top_left() } else { bounding_box.get_top_right() };
|
||||
let bottom: ResultPoint = if self.is_left { bounding_box.get_bottom_left() } else { bounding_box.get_bottom_right() };
|
||||
let first_row: i32 = image_row_to_codeword_index(top.get_y() as i32);
|
||||
let last_row: i32 = image_row_to_codeword_index(bottom.get_y() as i32);
|
||||
// We need to be careful using the average row height. Barcode could be skewed so that we have smaller and
|
||||
// taller rows
|
||||
//float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount();
|
||||
let barcode_row: i32 = -1;
|
||||
let max_row_height: i32 = 1;
|
||||
let current_row_height: i32 = 0;
|
||||
{
|
||||
let codewords_row: i32 = first_row;
|
||||
while codewords_row < last_row {
|
||||
{
|
||||
if codewords[codewords_row] == null {
|
||||
continue;
|
||||
}
|
||||
let codeword: Codeword = codewords[codewords_row];
|
||||
let row_difference: i32 = codeword.get_row_number() - barcode_row;
|
||||
if row_difference == 0 {
|
||||
current_row_height += 1;
|
||||
} else if row_difference == 1 {
|
||||
max_row_height = Math::max(max_row_height, current_row_height);
|
||||
current_row_height = 1;
|
||||
barcode_row = codeword.get_row_number();
|
||||
} else if row_difference < 0 || codeword.get_row_number() >= barcode_metadata.get_row_count() || row_difference > codewords_row {
|
||||
codewords[codewords_row] = null;
|
||||
} else {
|
||||
let checked_rows: i32;
|
||||
if max_row_height > 2 {
|
||||
checked_rows = (max_row_height - 2) * row_difference;
|
||||
} else {
|
||||
checked_rows = row_difference;
|
||||
}
|
||||
let close_previous_codeword_found: bool = checked_rows >= codewords_row;
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i <= checked_rows && !close_previous_codeword_found {
|
||||
{
|
||||
// there must be (height * rowDifference) number of codewords missing. For now we assume height = 1.
|
||||
// This should hopefully get rid of most problems already.
|
||||
close_previous_codeword_found = codewords[codewords_row - i] != null;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if close_previous_codeword_found {
|
||||
codewords[codewords_row] = null;
|
||||
} else {
|
||||
barcode_row = codeword.get_row_number();
|
||||
current_row_height = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//return (int) (averageRowHeight + 0.5);
|
||||
}
|
||||
|
||||
fn get_row_heights(&self) -> Vec<i32> {
|
||||
let barcode_metadata: BarcodeMetadata = self.get_barcode_metadata();
|
||||
if barcode_metadata == null {
|
||||
return null;
|
||||
}
|
||||
self.adjust_incomplete_indicator_column_row_numbers(barcode_metadata);
|
||||
let mut result: [i32; barcode_metadata.get_row_count()] = [0; barcode_metadata.get_row_count()];
|
||||
for let codeword: Codeword in get_codewords() {
|
||||
if codeword != null {
|
||||
let row_number: i32 = codeword.get_row_number();
|
||||
if row_number >= result.len() {
|
||||
// We have more rows than the barcode metadata allows for, ignore them.
|
||||
continue;
|
||||
}
|
||||
result[row_number] += 1;
|
||||
}
|
||||
// else throw exception?
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO maybe we should add missing codewords to store the correct row number to make
|
||||
// finding row numbers for other columns easier
|
||||
// use row height count to make detection of invalid row numbers more reliable
|
||||
fn adjust_incomplete_indicator_column_row_numbers(&self, barcode_metadata: &BarcodeMetadata) {
|
||||
let bounding_box: BoundingBox = get_bounding_box();
|
||||
let top: ResultPoint = if self.is_left { bounding_box.get_top_left() } else { bounding_box.get_top_right() };
|
||||
let bottom: ResultPoint = if self.is_left { bounding_box.get_bottom_left() } else { bounding_box.get_bottom_right() };
|
||||
let first_row: i32 = image_row_to_codeword_index(top.get_y() as i32);
|
||||
let last_row: i32 = image_row_to_codeword_index(bottom.get_y() as i32);
|
||||
//float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount();
|
||||
let mut codewords: Vec<Codeword> = get_codewords();
|
||||
let barcode_row: i32 = -1;
|
||||
let max_row_height: i32 = 1;
|
||||
let current_row_height: i32 = 0;
|
||||
{
|
||||
let codewords_row: i32 = first_row;
|
||||
while codewords_row < last_row {
|
||||
{
|
||||
if codewords[codewords_row] == null {
|
||||
continue;
|
||||
}
|
||||
let codeword: Codeword = codewords[codewords_row];
|
||||
codeword.set_row_number_as_row_indicator_column();
|
||||
let row_difference: i32 = codeword.get_row_number() - barcode_row;
|
||||
if row_difference == 0 {
|
||||
current_row_height += 1;
|
||||
} else if row_difference == 1 {
|
||||
max_row_height = Math::max(max_row_height, current_row_height);
|
||||
current_row_height = 1;
|
||||
barcode_row = codeword.get_row_number();
|
||||
} else if codeword.get_row_number() >= barcode_metadata.get_row_count() {
|
||||
codewords[codewords_row] = null;
|
||||
} else {
|
||||
barcode_row = codeword.get_row_number();
|
||||
current_row_height = 1;
|
||||
}
|
||||
}
|
||||
codewords_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//return (int) (averageRowHeight + 0.5);
|
||||
}
|
||||
|
||||
fn get_barcode_metadata(&self) -> BarcodeMetadata {
|
||||
let codewords: Vec<Codeword> = get_codewords();
|
||||
let barcode_column_count: BarcodeValue = BarcodeValue::new();
|
||||
let barcode_row_count_upper_part: BarcodeValue = BarcodeValue::new();
|
||||
let barcode_row_count_lower_part: BarcodeValue = BarcodeValue::new();
|
||||
let barcode_e_c_level: BarcodeValue = BarcodeValue::new();
|
||||
for let codeword: Codeword in codewords {
|
||||
if codeword == null {
|
||||
continue;
|
||||
}
|
||||
codeword.set_row_number_as_row_indicator_column();
|
||||
let row_indicator_value: i32 = codeword.get_value() % 30;
|
||||
let codeword_row_number: i32 = codeword.get_row_number();
|
||||
if !self.is_left {
|
||||
codeword_row_number += 2;
|
||||
}
|
||||
match codeword_row_number % 3 {
|
||||
0 =>
|
||||
{
|
||||
barcode_row_count_upper_part.set_value(row_indicator_value * 3 + 1);
|
||||
break;
|
||||
}
|
||||
1 =>
|
||||
{
|
||||
barcode_e_c_level.set_value(row_indicator_value / 3);
|
||||
barcode_row_count_lower_part.set_value(row_indicator_value % 3);
|
||||
break;
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
barcode_column_count.set_value(row_indicator_value + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Maybe we should check if we have ambiguous values?
|
||||
if (barcode_column_count.get_value().len() == 0) || (barcode_row_count_upper_part.get_value().len() == 0) || (barcode_row_count_lower_part.get_value().len() == 0) || (barcode_e_c_level.get_value().len() == 0) || barcode_column_count.get_value()[0] < 1 || barcode_row_count_upper_part.get_value()[0] + barcode_row_count_lower_part.get_value()[0] < PDF417Common.MIN_ROWS_IN_BARCODE || barcode_row_count_upper_part.get_value()[0] + barcode_row_count_lower_part.get_value()[0] > PDF417Common.MAX_ROWS_IN_BARCODE {
|
||||
return null;
|
||||
}
|
||||
let barcode_metadata: BarcodeMetadata = BarcodeMetadata::new(barcode_column_count.get_value()[0], barcode_row_count_upper_part.get_value()[0], barcode_row_count_lower_part.get_value()[0], barcode_e_c_level.get_value()[0]);
|
||||
self.remove_incorrect_codewords(codewords, barcode_metadata);
|
||||
return barcode_metadata;
|
||||
}
|
||||
|
||||
fn remove_incorrect_codewords(&self, codewords: &Vec<Codeword>, barcode_metadata: &BarcodeMetadata) {
|
||||
// TODO Maybe we should keep the incorrect codewords for the start and end positions?
|
||||
{
|
||||
let codeword_row: i32 = 0;
|
||||
while codeword_row < codewords.len() {
|
||||
{
|
||||
let codeword: Codeword = codewords[codeword_row];
|
||||
if codewords[codeword_row] == null {
|
||||
continue;
|
||||
}
|
||||
let row_indicator_value: i32 = codeword.get_value() % 30;
|
||||
let codeword_row_number: i32 = codeword.get_row_number();
|
||||
if codeword_row_number > barcode_metadata.get_row_count() {
|
||||
codewords[codeword_row] = null;
|
||||
continue;
|
||||
}
|
||||
if !self.is_left {
|
||||
codeword_row_number += 2;
|
||||
}
|
||||
match codeword_row_number % 3 {
|
||||
0 =>
|
||||
{
|
||||
if row_indicator_value * 3 + 1 != barcode_metadata.get_row_count_upper_part() {
|
||||
codewords[codeword_row] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
1 =>
|
||||
{
|
||||
if row_indicator_value / 3 != barcode_metadata.get_error_correction_level() || row_indicator_value % 3 != barcode_metadata.get_row_count_lower_part() {
|
||||
codewords[codeword_row] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
2 =>
|
||||
{
|
||||
if row_indicator_value + 1 != barcode_metadata.get_column_count() {
|
||||
codewords[codeword_row] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
codeword_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn is_left(&self) -> bool {
|
||||
return self.is_left;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return format!("IsLeft: {}\n{}", self.is_left, super.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
* @author creatale GmbH (christoph.schulz@creatale.de)
|
||||
*/
|
||||
|
||||
const RATIOS_TABLE: [[f32; PDF417Common.BARS_IN_MODULE]; PDF417Common.SYMBOL_TABLE.len()] = [[0.0; PDF417Common.BARS_IN_MODULE]; PDF417Common.SYMBOL_TABLE.len()];
|
||||
struct PDF417CodewordDecoder {
|
||||
}
|
||||
|
||||
impl PDF417CodewordDecoder {
|
||||
|
||||
static {
|
||||
// Pre-computes the symbol ratio table.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < PDF417Common.SYMBOL_TABLE.len() {
|
||||
{
|
||||
let current_symbol: i32 = PDF417Common.SYMBOL_TABLE[i];
|
||||
let current_bit: i32 = current_symbol & 0x1;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < PDF417Common.BARS_IN_MODULE {
|
||||
{
|
||||
let mut size: f32 = 0.0f;
|
||||
while (current_symbol & 0x1) == current_bit {
|
||||
size += 1.0f;
|
||||
current_symbol >>= 1;
|
||||
}
|
||||
current_bit = current_symbol & 0x1;
|
||||
RATIOS_TABLE[i][PDF417Common.BARS_IN_MODULE - j - 1] = size / PDF417Common.MODULES_IN_CODEWORD;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn new() -> PDF417CodewordDecoder {
|
||||
}
|
||||
|
||||
fn get_decoded_value( module_bit_count: &Vec<i32>) -> i32 {
|
||||
let decoded_value: i32 = ::get_decoded_codeword_value(&::sample_bit_counts(&module_bit_count));
|
||||
if decoded_value != -1 {
|
||||
return decoded_value;
|
||||
}
|
||||
return ::get_closest_decoded_value(&module_bit_count);
|
||||
}
|
||||
|
||||
fn sample_bit_counts( module_bit_count: &Vec<i32>) -> Vec<i32> {
|
||||
let bit_count_sum: f32 = MathUtils::sum(&module_bit_count);
|
||||
let mut result: [i32; PDF417Common.BARS_IN_MODULE] = [0; PDF417Common.BARS_IN_MODULE];
|
||||
let bit_count_index: i32 = 0;
|
||||
let sum_previous_bits: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < PDF417Common.MODULES_IN_CODEWORD {
|
||||
{
|
||||
let sample_index: f32 = bit_count_sum / (2.0 * PDF417Common.MODULES_IN_CODEWORD) + (i * bit_count_sum) / PDF417Common.MODULES_IN_CODEWORD;
|
||||
if sum_previous_bits + module_bit_count[bit_count_index] <= sample_index {
|
||||
sum_previous_bits += module_bit_count[bit_count_index];
|
||||
bit_count_index += 1;
|
||||
}
|
||||
result[bit_count_index] += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_decoded_codeword_value( module_bit_count: &Vec<i32>) -> i32 {
|
||||
let decoded_value: i32 = ::get_bit_value(&module_bit_count);
|
||||
return if PDF417Common::get_codeword(decoded_value) == -1 { -1 } else { decoded_value };
|
||||
}
|
||||
|
||||
fn get_bit_value( module_bit_count: &Vec<i32>) -> i32 {
|
||||
let mut result: i64 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < module_bit_count.len() {
|
||||
{
|
||||
{
|
||||
let mut bit: i32 = 0;
|
||||
while bit < module_bit_count[i] {
|
||||
{
|
||||
result = (result << 1) | ( if i % 2 == 0 { 1 } else { 0 });
|
||||
}
|
||||
bit += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result as i32;
|
||||
}
|
||||
|
||||
fn get_closest_decoded_value( module_bit_count: &Vec<i32>) -> i32 {
|
||||
let bit_count_sum: i32 = MathUtils::sum(&module_bit_count);
|
||||
let bit_count_ratios: [f32; PDF417Common.BARS_IN_MODULE] = [0.0; PDF417Common.BARS_IN_MODULE];
|
||||
if bit_count_sum > 1 {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < bit_count_ratios.len() {
|
||||
{
|
||||
bit_count_ratios[i] = module_bit_count[i] / bit_count_sum as f32;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let best_match_error: f32 = Float::MAX_VALUE;
|
||||
let best_match: i32 = -1;
|
||||
{
|
||||
let mut j: i32 = 0;
|
||||
while j < RATIOS_TABLE.len() {
|
||||
{
|
||||
let mut error: f32 = 0.0f;
|
||||
let ratio_table_row: Vec<f32> = RATIOS_TABLE[j];
|
||||
{
|
||||
let mut k: i32 = 0;
|
||||
while k < PDF417Common.BARS_IN_MODULE {
|
||||
{
|
||||
let diff: f32 = ratio_table_row[k] - bit_count_ratios[k];
|
||||
error += diff * diff;
|
||||
if error >= best_match_error {
|
||||
break;
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if error < best_match_error {
|
||||
best_match_error = error;
|
||||
best_match = PDF417Common.SYMBOL_TABLE[j];
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return best_match;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,675 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417::decoder;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
const CODEWORD_SKEW_SIZE: i32 = 2;
|
||||
|
||||
const MAX_ERRORS: i32 = 3;
|
||||
|
||||
const MAX_EC_CODEWORDS: i32 = 512;
|
||||
|
||||
let error_correction: ErrorCorrection = ErrorCorrection::new();
|
||||
pub struct PDF417ScanningDecoder {
|
||||
}
|
||||
|
||||
impl PDF417ScanningDecoder {
|
||||
|
||||
fn new() -> PDF417ScanningDecoder {
|
||||
}
|
||||
|
||||
// TODO don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern
|
||||
// columns. That way width can be deducted from the pattern column.
|
||||
// This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider
|
||||
// than it should be. This can happen if the scanner used a bad blackpoint.
|
||||
pub fn decode( image: &BitMatrix, image_top_left: &ResultPoint, image_bottom_left: &ResultPoint, image_top_right: &ResultPoint, image_bottom_right: &ResultPoint, min_codeword_width: i32, max_codeword_width: i32) -> /* throws NotFoundException, FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
let bounding_box: BoundingBox = BoundingBox::new(image, image_top_left, image_bottom_left, image_top_right, image_bottom_right);
|
||||
let left_row_indicator_column: DetectionResultRowIndicatorColumn = null;
|
||||
let right_row_indicator_column: DetectionResultRowIndicatorColumn = null;
|
||||
let detection_result: DetectionResult;
|
||||
{
|
||||
let first_pass: bool = true;
|
||||
loop {
|
||||
{
|
||||
if image_top_left != null {
|
||||
left_row_indicator_column = ::get_row_indicator_column(image, bounding_box, image_top_left, true, min_codeword_width, max_codeword_width);
|
||||
}
|
||||
if image_top_right != null {
|
||||
right_row_indicator_column = ::get_row_indicator_column(image, bounding_box, image_top_right, false, min_codeword_width, max_codeword_width);
|
||||
}
|
||||
detection_result = ::merge(left_row_indicator_column, right_row_indicator_column);
|
||||
if detection_result == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let result_box: BoundingBox = detection_result.get_bounding_box();
|
||||
if first_pass && result_box != null && (result_box.get_min_y() < bounding_box.get_min_y() || result_box.get_max_y() > bounding_box.get_max_y()) {
|
||||
bounding_box = result_box;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
first_pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
detection_result.set_bounding_box(bounding_box);
|
||||
let max_barcode_column: i32 = detection_result.get_barcode_column_count() + 1;
|
||||
detection_result.set_detection_result_column(0, left_row_indicator_column);
|
||||
detection_result.set_detection_result_column(max_barcode_column, right_row_indicator_column);
|
||||
let left_to_right: bool = left_row_indicator_column != null;
|
||||
{
|
||||
let barcode_column_count: i32 = 1;
|
||||
while barcode_column_count <= max_barcode_column {
|
||||
{
|
||||
let barcode_column: i32 = if left_to_right { barcode_column_count } else { max_barcode_column - barcode_column_count };
|
||||
if detection_result.get_detection_result_column(barcode_column) != null {
|
||||
// This will be the case for the opposite row indicator column, which doesn't need to be decoded again.
|
||||
continue;
|
||||
}
|
||||
let detection_result_column: DetectionResultColumn;
|
||||
if barcode_column == 0 || barcode_column == max_barcode_column {
|
||||
detection_result_column = DetectionResultRowIndicatorColumn::new(bounding_box, barcode_column == 0);
|
||||
} else {
|
||||
detection_result_column = DetectionResultColumn::new(bounding_box);
|
||||
}
|
||||
detection_result.set_detection_result_column(barcode_column, detection_result_column);
|
||||
let start_column: i32 = -1;
|
||||
let previous_start_column: i32 = start_column;
|
||||
// TODO start at a row for which we know the start position, then detect upwards and downwards from there.
|
||||
{
|
||||
let image_row: i32 = bounding_box.get_min_y();
|
||||
while image_row <= bounding_box.get_max_y() {
|
||||
{
|
||||
start_column = ::get_start_column(detection_result, barcode_column, image_row, left_to_right);
|
||||
if start_column < 0 || start_column > bounding_box.get_max_x() {
|
||||
if previous_start_column == -1 {
|
||||
continue;
|
||||
}
|
||||
start_column = previous_start_column;
|
||||
}
|
||||
let codeword: Codeword = ::detect_codeword(image, &bounding_box.get_min_x(), &bounding_box.get_max_x(), left_to_right, start_column, image_row, min_codeword_width, max_codeword_width);
|
||||
if codeword != null {
|
||||
detection_result_column.set_codeword(image_row, codeword);
|
||||
previous_start_column = start_column;
|
||||
min_codeword_width = Math::min(min_codeword_width, &codeword.get_width());
|
||||
max_codeword_width = Math::max(max_codeword_width, &codeword.get_width());
|
||||
}
|
||||
}
|
||||
image_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
barcode_column_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(::create_decoder_result(detection_result));
|
||||
}
|
||||
|
||||
fn merge( left_row_indicator_column: &DetectionResultRowIndicatorColumn, right_row_indicator_column: &DetectionResultRowIndicatorColumn) -> /* throws NotFoundException */Result<DetectionResult, Rc<Exception>> {
|
||||
if left_row_indicator_column == null && right_row_indicator_column == null {
|
||||
return Ok(null);
|
||||
}
|
||||
let barcode_metadata: BarcodeMetadata = ::get_barcode_metadata(left_row_indicator_column, right_row_indicator_column);
|
||||
if barcode_metadata == null {
|
||||
return Ok(null);
|
||||
}
|
||||
let bounding_box: BoundingBox = BoundingBox::merge(&::adjust_bounding_box(left_row_indicator_column), &::adjust_bounding_box(right_row_indicator_column));
|
||||
return Ok(DetectionResult::new(barcode_metadata, bounding_box));
|
||||
}
|
||||
|
||||
fn adjust_bounding_box( row_indicator_column: &DetectionResultRowIndicatorColumn) -> /* throws NotFoundException */Result<BoundingBox, Rc<Exception>> {
|
||||
if row_indicator_column == null {
|
||||
return Ok(null);
|
||||
}
|
||||
let row_heights: Vec<i32> = row_indicator_column.get_row_heights();
|
||||
if row_heights == null {
|
||||
return Ok(null);
|
||||
}
|
||||
let max_row_height: i32 = ::get_max(&row_heights);
|
||||
let missing_start_rows: i32 = 0;
|
||||
for let row_height: i32 in row_heights {
|
||||
missing_start_rows += max_row_height - row_height;
|
||||
if row_height > 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let codewords: Vec<Codeword> = row_indicator_column.get_codewords();
|
||||
{
|
||||
let mut row: i32 = 0;
|
||||
while missing_start_rows > 0 && codewords[row] == null {
|
||||
{
|
||||
missing_start_rows -= 1;
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let missing_end_rows: i32 = 0;
|
||||
{
|
||||
let mut row: i32 = row_heights.len() - 1;
|
||||
while row >= 0 {
|
||||
{
|
||||
missing_end_rows += max_row_height - row_heights[row];
|
||||
if row_heights[row] > 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
row -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut row: i32 = codewords.len() - 1;
|
||||
while missing_end_rows > 0 && codewords[row] == null {
|
||||
{
|
||||
missing_end_rows -= 1;
|
||||
}
|
||||
row -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(row_indicator_column.get_bounding_box().add_missing_rows(missing_start_rows, missing_end_rows, &row_indicator_column.is_left()));
|
||||
}
|
||||
|
||||
fn get_max( values: &Vec<i32>) -> i32 {
|
||||
let max_value: i32 = -1;
|
||||
for let value: i32 in values {
|
||||
max_value = Math::max(max_value, value);
|
||||
}
|
||||
return max_value;
|
||||
}
|
||||
|
||||
fn get_barcode_metadata( left_row_indicator_column: &DetectionResultRowIndicatorColumn, right_row_indicator_column: &DetectionResultRowIndicatorColumn) -> BarcodeMetadata {
|
||||
let left_barcode_metadata: BarcodeMetadata;
|
||||
if left_row_indicator_column == null || (left_barcode_metadata = left_row_indicator_column.get_barcode_metadata()) == null {
|
||||
return if right_row_indicator_column == null { null } else { right_row_indicator_column.get_barcode_metadata() };
|
||||
}
|
||||
let right_barcode_metadata: BarcodeMetadata;
|
||||
if right_row_indicator_column == null || (right_barcode_metadata = right_row_indicator_column.get_barcode_metadata()) == null {
|
||||
return left_barcode_metadata;
|
||||
}
|
||||
if left_barcode_metadata.get_column_count() != right_barcode_metadata.get_column_count() && left_barcode_metadata.get_error_correction_level() != right_barcode_metadata.get_error_correction_level() && left_barcode_metadata.get_row_count() != right_barcode_metadata.get_row_count() {
|
||||
return null;
|
||||
}
|
||||
return left_barcode_metadata;
|
||||
}
|
||||
|
||||
fn get_row_indicator_column( image: &BitMatrix, bounding_box: &BoundingBox, start_point: &ResultPoint, left_to_right: bool, min_codeword_width: i32, max_codeword_width: i32) -> DetectionResultRowIndicatorColumn {
|
||||
let row_indicator_column: DetectionResultRowIndicatorColumn = DetectionResultRowIndicatorColumn::new(bounding_box, left_to_right);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 2 {
|
||||
{
|
||||
let increment: i32 = if i == 0 { 1 } else { -1 };
|
||||
let start_column: i32 = start_point.get_x() as i32;
|
||||
{
|
||||
let image_row: i32 = start_point.get_y() as i32;
|
||||
while image_row <= bounding_box.get_max_y() && image_row >= bounding_box.get_min_y() {
|
||||
{
|
||||
let codeword: Codeword = ::detect_codeword(image, 0, &image.get_width(), left_to_right, start_column, image_row, min_codeword_width, max_codeword_width);
|
||||
if codeword != null {
|
||||
row_indicator_column.set_codeword(image_row, codeword);
|
||||
if left_to_right {
|
||||
start_column = codeword.get_start_x();
|
||||
} else {
|
||||
start_column = codeword.get_end_x();
|
||||
}
|
||||
}
|
||||
}
|
||||
image_row += increment;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return row_indicator_column;
|
||||
}
|
||||
|
||||
fn adjust_codeword_count( detection_result: &DetectionResult, barcode_matrix: &Vec<Vec<BarcodeValue>>) -> /* throws NotFoundException */Result<Void, Rc<Exception>> {
|
||||
let barcode_matrix01: BarcodeValue = barcode_matrix[0][1];
|
||||
let number_of_codewords: Vec<i32> = barcode_matrix01.get_value();
|
||||
let calculated_number_of_codewords: i32 = detection_result.get_barcode_column_count() * detection_result.get_barcode_row_count() - ::get_number_of_e_c_code_words(&detection_result.get_barcode_e_c_level());
|
||||
if number_of_codewords.len() == 0 {
|
||||
if calculated_number_of_codewords < 1 || calculated_number_of_codewords > PDF417Common.MAX_CODEWORDS_IN_BARCODE {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
barcode_matrix01.set_value(calculated_number_of_codewords);
|
||||
} else if number_of_codewords[0] != calculated_number_of_codewords {
|
||||
if calculated_number_of_codewords >= 1 && calculated_number_of_codewords <= PDF417Common.MAX_CODEWORDS_IN_BARCODE {
|
||||
// The calculated one is more reliable as it is derived from the row indicator columns
|
||||
barcode_matrix01.set_value(calculated_number_of_codewords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_decoder_result( detection_result: &DetectionResult) -> /* throws FormatException, ChecksumException, NotFoundException */Result<DecoderResult, Rc<Exception>> {
|
||||
let barcode_matrix: Vec<Vec<BarcodeValue>> = ::create_barcode_matrix(detection_result);
|
||||
::adjust_codeword_count(detection_result, barcode_matrix);
|
||||
let erasures: Collection<Integer> = ArrayList<>::new();
|
||||
let mut codewords: [i32; detection_result.get_barcode_row_count() * detection_result.get_barcode_column_count()] = [0; detection_result.get_barcode_row_count() * detection_result.get_barcode_column_count()];
|
||||
let ambiguous_index_values_list: List<Vec<i32>> = ArrayList<>::new();
|
||||
let ambiguous_indexes_list: Collection<Integer> = ArrayList<>::new();
|
||||
{
|
||||
let mut row: i32 = 0;
|
||||
while row < detection_result.get_barcode_row_count() {
|
||||
{
|
||||
{
|
||||
let mut column: i32 = 0;
|
||||
while column < detection_result.get_barcode_column_count() {
|
||||
{
|
||||
let values: Vec<i32> = barcode_matrix[row][column + 1].get_value();
|
||||
let codeword_index: i32 = row * detection_result.get_barcode_column_count() + column;
|
||||
if values.len() == 0 {
|
||||
erasures.add(codeword_index);
|
||||
} else if values.len() == 1 {
|
||||
codewords[codeword_index] = values[0];
|
||||
} else {
|
||||
ambiguous_indexes_list.add(codeword_index);
|
||||
ambiguous_index_values_list.add(&values);
|
||||
}
|
||||
}
|
||||
column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let ambiguous_index_values: [i32; ambiguous_index_values_list.size()] = [0; ambiguous_index_values_list.size()];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < ambiguous_index_values.len() {
|
||||
{
|
||||
ambiguous_index_values[i] = ambiguous_index_values_list.get(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(::create_decoder_result_from_ambiguous_values(&detection_result.get_barcode_e_c_level(), &codewords, &PDF417Common::to_int_array(&erasures), &PDF417Common::to_int_array(&ambiguous_indexes_list), &ambiguous_index_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deals with the fact, that the decoding process doesn't always yield a single most likely value. The
|
||||
* current error correction implementation doesn't deal with erasures very well, so it's better to provide a value
|
||||
* for these ambiguous codewords instead of treating it as an erasure. The problem is that we don't know which of
|
||||
* the ambiguous values to choose. We try decode using the first value, and if that fails, we use another of the
|
||||
* ambiguous values and try to decode again. This usually only happens on very hard to read and decode barcodes,
|
||||
* so decoding the normal barcodes is not affected by this.
|
||||
*
|
||||
* @param erasureArray contains the indexes of erasures
|
||||
* @param ambiguousIndexes array with the indexes that have more than one most likely value
|
||||
* @param ambiguousIndexValues two dimensional array that contains the ambiguous values. The first dimension must
|
||||
* be the same length as the ambiguousIndexes array
|
||||
*/
|
||||
fn create_decoder_result_from_ambiguous_values( ec_level: i32, codewords: &Vec<i32>, erasure_array: &Vec<i32>, ambiguous_indexes: &Vec<i32>, ambiguous_index_values: &Vec<Vec<i32>>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
let ambiguous_index_count: [i32; ambiguous_indexes.len()] = [0; ambiguous_indexes.len()];
|
||||
let mut tries: i32 = 100;
|
||||
while tries -= 1 !!!check!!! post decrement > 0 {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < ambiguous_index_count.len() {
|
||||
{
|
||||
codewords[ambiguous_indexes[i]] = ambiguous_index_values[i][ambiguous_index_count[i]];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return Ok(::decode_codewords(&codewords, ec_level, &erasure_array));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &ChecksumException) {
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
if ambiguous_index_count.len() == 0 {
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
}
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < ambiguous_index_count.len() {
|
||||
{
|
||||
if ambiguous_index_count[i] < ambiguous_index_values[i].len() - 1 {
|
||||
ambiguous_index_count[i] += 1;
|
||||
break;
|
||||
} else {
|
||||
ambiguous_index_count[i] = 0;
|
||||
if i == ambiguous_index_count.len() - 1 {
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
}
|
||||
|
||||
fn create_barcode_matrix( detection_result: &DetectionResult) -> Vec<Vec<BarcodeValue>> {
|
||||
let barcode_matrix: [[Option<BarcodeValue>; detection_result.get_barcode_column_count() + 2]; detection_result.get_barcode_row_count()] = [[None; detection_result.get_barcode_column_count() + 2]; detection_result.get_barcode_row_count()];
|
||||
{
|
||||
let mut row: i32 = 0;
|
||||
while row < barcode_matrix.len() {
|
||||
{
|
||||
{
|
||||
let mut column: i32 = 0;
|
||||
while column < barcode_matrix[row].len() {
|
||||
{
|
||||
barcode_matrix[row][column] = BarcodeValue::new();
|
||||
}
|
||||
column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut column: i32 = 0;
|
||||
for let detection_result_column: DetectionResultColumn in detection_result.get_detection_result_columns() {
|
||||
if detection_result_column != null {
|
||||
for let codeword: Codeword in detection_result_column.get_codewords() {
|
||||
if codeword != null {
|
||||
let row_number: i32 = codeword.get_row_number();
|
||||
if row_number >= 0 {
|
||||
if row_number >= barcode_matrix.len() {
|
||||
// We have more rows than the barcode metadata allows for, ignore them.
|
||||
continue;
|
||||
}
|
||||
barcode_matrix[row_number][column].set_value(&codeword.get_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
column += 1;
|
||||
}
|
||||
return barcode_matrix;
|
||||
}
|
||||
|
||||
fn is_valid_barcode_column( detection_result: &DetectionResult, barcode_column: i32) -> bool {
|
||||
return barcode_column >= 0 && barcode_column <= detection_result.get_barcode_column_count() + 1;
|
||||
}
|
||||
|
||||
fn get_start_column( detection_result: &DetectionResult, barcode_column: i32, image_row: i32, left_to_right: bool) -> i32 {
|
||||
let offset: i32 = if left_to_right { 1 } else { -1 };
|
||||
let mut codeword: Codeword = null;
|
||||
if ::is_valid_barcode_column(detection_result, barcode_column - offset) {
|
||||
codeword = detection_result.get_detection_result_column(barcode_column - offset).get_codeword(image_row);
|
||||
}
|
||||
if codeword != null {
|
||||
return if left_to_right { codeword.get_end_x() } else { codeword.get_start_x() };
|
||||
}
|
||||
codeword = detection_result.get_detection_result_column(barcode_column).get_codeword_nearby(image_row);
|
||||
if codeword != null {
|
||||
return if left_to_right { codeword.get_start_x() } else { codeword.get_end_x() };
|
||||
}
|
||||
if ::is_valid_barcode_column(detection_result, barcode_column - offset) {
|
||||
codeword = detection_result.get_detection_result_column(barcode_column - offset).get_codeword_nearby(image_row);
|
||||
}
|
||||
if codeword != null {
|
||||
return if left_to_right { codeword.get_end_x() } else { codeword.get_start_x() };
|
||||
}
|
||||
let skipped_columns: i32 = 0;
|
||||
while ::is_valid_barcode_column(detection_result, barcode_column - offset) {
|
||||
barcode_column -= offset;
|
||||
for let previous_row_codeword: Codeword in detection_result.get_detection_result_column(barcode_column).get_codewords() {
|
||||
if previous_row_codeword != null {
|
||||
return ( if left_to_right { previous_row_codeword.get_end_x() } else { previous_row_codeword.get_start_x() }) + offset * skipped_columns * (previous_row_codeword.get_end_x() - previous_row_codeword.get_start_x());
|
||||
}
|
||||
}
|
||||
skipped_columns += 1;
|
||||
}
|
||||
return if left_to_right { detection_result.get_bounding_box().get_min_x() } else { detection_result.get_bounding_box().get_max_x() };
|
||||
}
|
||||
|
||||
fn detect_codeword( image: &BitMatrix, min_column: i32, max_column: i32, left_to_right: bool, start_column: i32, image_row: i32, min_codeword_width: i32, max_codeword_width: i32) -> Codeword {
|
||||
start_column = ::adjust_codeword_start_column(image, min_column, max_column, left_to_right, start_column, image_row);
|
||||
// we usually know fairly exact now how long a codeword is. We should provide minimum and maximum expected length
|
||||
// and try to adjust the read pixels, e.g. remove single pixel errors or try to cut off exceeding pixels.
|
||||
// min and maxCodewordWidth should not be used as they are calculated for the whole barcode an can be inaccurate
|
||||
// for the current position
|
||||
let module_bit_count: Vec<i32> = ::get_module_bit_count(image, min_column, max_column, left_to_right, start_column, image_row);
|
||||
if module_bit_count == null {
|
||||
return null;
|
||||
}
|
||||
let end_column: i32;
|
||||
let codeword_bit_count: i32 = MathUtils::sum(&module_bit_count);
|
||||
if left_to_right {
|
||||
end_column = start_column + codeword_bit_count;
|
||||
} else {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < module_bit_count.len() / 2 {
|
||||
{
|
||||
let tmp_count: i32 = module_bit_count[i];
|
||||
module_bit_count[i] = module_bit_count[module_bit_count.len() - 1 - i];
|
||||
module_bit_count[module_bit_count.len() - 1 - i] = tmp_count;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
end_column = start_column;
|
||||
start_column = end_column - codeword_bit_count;
|
||||
}
|
||||
// sufficient for now
|
||||
if !::check_codeword_skew(codeword_bit_count, min_codeword_width, max_codeword_width) {
|
||||
// create the bit count from it and normalize it to 8. This would help with single pixel errors.
|
||||
return null;
|
||||
}
|
||||
let decoded_value: i32 = PDF417CodewordDecoder::get_decoded_value(&module_bit_count);
|
||||
let codeword: i32 = PDF417Common::get_codeword(decoded_value);
|
||||
if codeword == -1 {
|
||||
return null;
|
||||
}
|
||||
return Codeword::new(start_column, end_column, &::get_codeword_bucket_number(decoded_value), codeword);
|
||||
}
|
||||
|
||||
fn get_module_bit_count( image: &BitMatrix, min_column: i32, max_column: i32, left_to_right: bool, start_column: i32, image_row: i32) -> Vec<i32> {
|
||||
let image_column: i32 = start_column;
|
||||
let module_bit_count: [i32; 8] = [0; 8];
|
||||
let module_number: i32 = 0;
|
||||
let increment: i32 = if left_to_right { 1 } else { -1 };
|
||||
let previous_pixel_value: bool = left_to_right;
|
||||
while ( if left_to_right { image_column < max_column } else { image_column >= min_column }) && module_number < module_bit_count.len() {
|
||||
if image.get(image_column, image_row) == previous_pixel_value {
|
||||
module_bit_count[module_number] += 1;
|
||||
image_column += increment;
|
||||
} else {
|
||||
module_number += 1;
|
||||
previous_pixel_value = !previous_pixel_value;
|
||||
}
|
||||
}
|
||||
if module_number == module_bit_count.len() || ((image_column == ( if left_to_right { max_column } else { min_column })) && module_number == module_bit_count.len() - 1) {
|
||||
return module_bit_count;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn get_number_of_e_c_code_words( barcode_e_c_level: i32) -> i32 {
|
||||
return 2 << barcode_e_c_level;
|
||||
}
|
||||
|
||||
fn adjust_codeword_start_column( image: &BitMatrix, min_column: i32, max_column: i32, left_to_right: bool, codeword_start_column: i32, image_row: i32) -> i32 {
|
||||
let corrected_start_column: i32 = codeword_start_column;
|
||||
let mut increment: i32 = if left_to_right { -1 } else { 1 };
|
||||
// there should be no black pixels before the start column. If there are, then we need to start earlier.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 2 {
|
||||
{
|
||||
while ( if left_to_right { corrected_start_column >= min_column } else { corrected_start_column < max_column }) && left_to_right == image.get(corrected_start_column, image_row) {
|
||||
if Math::abs(codeword_start_column - corrected_start_column) > CODEWORD_SKEW_SIZE {
|
||||
return codeword_start_column;
|
||||
}
|
||||
corrected_start_column += increment;
|
||||
}
|
||||
increment = -increment;
|
||||
left_to_right = !left_to_right;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return corrected_start_column;
|
||||
}
|
||||
|
||||
fn check_codeword_skew( codeword_size: i32, min_codeword_width: i32, max_codeword_width: i32) -> bool {
|
||||
return min_codeword_width - CODEWORD_SKEW_SIZE <= codeword_size && codeword_size <= max_codeword_width + CODEWORD_SKEW_SIZE;
|
||||
}
|
||||
|
||||
fn decode_codewords( codewords: &Vec<i32>, ec_level: i32, erasures: &Vec<i32>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
||||
if codewords.len() == 0 {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
let num_e_c_codewords: i32 = 1 << (ec_level + 1);
|
||||
let corrected_errors_count: i32 = ::correct_errors(&codewords, &erasures, num_e_c_codewords);
|
||||
::verify_codeword_count(&codewords, num_e_c_codewords);
|
||||
// Decode the codewords
|
||||
let decoder_result: DecoderResult = DecodedBitStreamParser::decode(&codewords, &String::value_of(ec_level));
|
||||
decoder_result.set_errors_corrected(corrected_errors_count);
|
||||
decoder_result.set_erasures(erasures.len());
|
||||
return Ok(decoder_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||
* correct the errors in-place.</p>
|
||||
*
|
||||
* @param codewords data and error correction codewords
|
||||
* @param erasures positions of any known erasures
|
||||
* @param numECCodewords number of error correction codewords that are available in codewords
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
fn correct_errors( codewords: &Vec<i32>, erasures: &Vec<i32>, num_e_c_codewords: i32) -> /* throws ChecksumException */Result<i32, Rc<Exception>> {
|
||||
if erasures != null && erasures.len() > num_e_c_codewords / 2 + MAX_ERRORS || num_e_c_codewords < 0 || num_e_c_codewords > MAX_EC_CODEWORDS {
|
||||
// Too many errors or EC Codewords is corrupted
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
}
|
||||
return Ok(error_correction.decode(&codewords, num_e_c_codewords, &erasures));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that all is OK with the codeword array.
|
||||
*/
|
||||
fn verify_codeword_count( codewords: &Vec<i32>, num_e_c_codewords: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
||||
if codewords.len() < 4 {
|
||||
// Count CW, At least one Data CW, Error Correction CW, Error Correction CW
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
// The first codeword, the Symbol Length Descriptor, shall always encode the total number of data
|
||||
// codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad
|
||||
// codewords, but excluding the number of error correction codewords.
|
||||
let number_of_codewords: i32 = codewords[0];
|
||||
if number_of_codewords > codewords.len() {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
if number_of_codewords == 0 {
|
||||
// Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords)
|
||||
if num_e_c_codewords < codewords.len() {
|
||||
codewords[0] = codewords.len() - num_e_c_codewords;
|
||||
} else {
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bit_count_for_codeword( codeword: i32) -> Vec<i32> {
|
||||
let mut result: [i32; 8] = [0; 8];
|
||||
let previous_value: i32 = 0;
|
||||
let mut i: i32 = result.len() - 1;
|
||||
while true {
|
||||
if (codeword & 0x1) != previous_value {
|
||||
previous_value = codeword & 0x1;
|
||||
i -= 1;
|
||||
if i < 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result[i] += 1;
|
||||
codeword >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_codeword_bucket_number( codeword: i32) -> i32 {
|
||||
return ::get_codeword_bucket_number(&::get_bit_count_for_codeword(codeword));
|
||||
}
|
||||
|
||||
fn get_codeword_bucket_number( module_bit_count: &Vec<i32>) -> i32 {
|
||||
return (module_bit_count[0] - module_bit_count[2] + module_bit_count[4] - module_bit_count[6] + 9) % 9;
|
||||
}
|
||||
|
||||
pub fn to_string( barcode_matrix: &Vec<Vec<BarcodeValue>>) -> String {
|
||||
let tryResult1 = 0;
|
||||
'try1: loop {
|
||||
( let formatter: Formatter = Formatter::new()) {
|
||||
{
|
||||
let mut row: i32 = 0;
|
||||
while row < barcode_matrix.len() {
|
||||
{
|
||||
formatter.format("Row %2d: ", row);
|
||||
{
|
||||
let mut column: i32 = 0;
|
||||
while column < barcode_matrix[row].len() {
|
||||
{
|
||||
let barcode_value: BarcodeValue = barcode_matrix[row][column];
|
||||
if barcode_value.get_value().len() == 0 {
|
||||
formatter.format(" ", null as Vec<Object>);
|
||||
} else {
|
||||
formatter.format("%4d(%2d)", barcode_value.get_value()[0], &barcode_value.get_confidence(barcode_value.get_value()[0]));
|
||||
}
|
||||
}
|
||||
column += 1;
|
||||
}
|
||||
}
|
||||
|
||||
formatter.format("%n");
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return formatter.to_string();
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
0 => break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 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::encoder;
|
||||
|
||||
/**
|
||||
* Holds all of the information for a barcode in a format where it can be easily accessible
|
||||
*
|
||||
* @author Jacob Haynes
|
||||
*/
|
||||
pub struct BarcodeMatrix {
|
||||
|
||||
let mut matrix: Vec<BarcodeRow>;
|
||||
|
||||
let current_row: i32;
|
||||
|
||||
let height: i32;
|
||||
|
||||
let width: i32;
|
||||
}
|
||||
|
||||
impl BarcodeMatrix {
|
||||
|
||||
/**
|
||||
* @param height the height of the matrix (Rows)
|
||||
* @param width the width of the matrix (Cols)
|
||||
*/
|
||||
fn new( height: i32, width: i32) -> BarcodeMatrix {
|
||||
matrix = : [Option<BarcodeRow>; height] = [None; height];
|
||||
//Initializes the array to the correct width
|
||||
{
|
||||
let mut i: i32 = 0, let matrix_length: i32 = matrix.len();
|
||||
while i < matrix_length {
|
||||
{
|
||||
matrix[i] = BarcodeRow::new((width + 4) * 17 + 1);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let .width = width * 17;
|
||||
let .height = height;
|
||||
let .currentRow = -1;
|
||||
}
|
||||
|
||||
fn set(&self, x: i32, y: i32, value: i8) {
|
||||
self.matrix[y].set(x, value);
|
||||
}
|
||||
|
||||
fn start_row(&self) {
|
||||
self.current_row += 1;
|
||||
}
|
||||
|
||||
fn get_current_row(&self) -> BarcodeRow {
|
||||
return self.matrix[self.current_row];
|
||||
}
|
||||
|
||||
pub fn get_matrix(&self) -> Vec<Vec<i8>> {
|
||||
return self.get_scaled_matrix(1, 1);
|
||||
}
|
||||
|
||||
pub fn get_scaled_matrix(&self, x_scale: i32, y_scale: i32) -> Vec<Vec<i8>> {
|
||||
let matrix_out: [[i8; self.width * x_scale]; self.height * y_scale] = [[0; self.width * x_scale]; self.height * y_scale];
|
||||
let y_max: i32 = self.height * y_scale;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < y_max {
|
||||
{
|
||||
matrix_out[y_max - i - 1] = self.matrix[i / y_scale].get_scaled_row(x_scale);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return matrix_out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 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::encoder;
|
||||
|
||||
/**
|
||||
* @author Jacob Haynes
|
||||
*/
|
||||
struct BarcodeRow {
|
||||
|
||||
let mut row: Vec<i8>;
|
||||
|
||||
//A tacker for position in the bar
|
||||
let current_location: i32;
|
||||
}
|
||||
|
||||
impl BarcodeRow {
|
||||
|
||||
/**
|
||||
* Creates a Barcode row of the width
|
||||
*/
|
||||
fn new( width: i32) -> BarcodeRow {
|
||||
let .row = : [i8; width] = [0; width];
|
||||
current_location = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific location in the bar
|
||||
*
|
||||
* @param x The location in the bar
|
||||
* @param value Black if true, white if false;
|
||||
*/
|
||||
fn set(&self, x: i32, value: i8) {
|
||||
self.row[x] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific location in the bar
|
||||
*
|
||||
* @param x The location in the bar
|
||||
* @param black Black if true, white if false;
|
||||
*/
|
||||
fn set(&self, x: i32, black: bool) {
|
||||
self.row[x] = ( if black { 1 } else { 0 }) as i8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param black A boolean which is true if the bar black false if it is white
|
||||
* @param width How many spots wide the bar is.
|
||||
*/
|
||||
fn add_bar(&self, black: bool, width: i32) {
|
||||
{
|
||||
let mut ii: i32 = 0;
|
||||
while ii < width {
|
||||
{
|
||||
self.set(self.current_location += 1 !!!check!!! post increment, black);
|
||||
}
|
||||
ii += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function scales the row
|
||||
*
|
||||
* @param scale How much you want the image to be scaled, must be greater than or equal to 1.
|
||||
* @return the scaled row
|
||||
*/
|
||||
fn get_scaled_row(&self, scale: i32) -> Vec<i8> {
|
||||
let mut output: [i8; self.row.len() * scale] = [0; self.row.len() * scale];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < output.len() {
|
||||
{
|
||||
output[i] = self.row[i / scale];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 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::encoder;
|
||||
|
||||
/**
|
||||
* Represents possible PDF417 barcode compaction types.
|
||||
*/
|
||||
pub enum Compaction {
|
||||
|
||||
AUTO(), TEXT(), BYTE(), NUMERIC()
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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::encoder;
|
||||
|
||||
/**
|
||||
* Data object to specify the minimum and maximum number of rows and columns for a PDF417 barcode.
|
||||
*
|
||||
* @author qwandor@google.com (Andrew Walbran)
|
||||
*/
|
||||
pub struct Dimensions {
|
||||
|
||||
let min_cols: i32;
|
||||
|
||||
let max_cols: i32;
|
||||
|
||||
let min_rows: i32;
|
||||
|
||||
let max_rows: i32;
|
||||
}
|
||||
|
||||
impl Dimensions {
|
||||
|
||||
pub fn new( min_cols: i32, max_cols: i32, min_rows: i32, max_rows: i32) -> Dimensions {
|
||||
let .minCols = min_cols;
|
||||
let .maxCols = max_cols;
|
||||
let .minRows = min_rows;
|
||||
let .maxRows = max_rows;
|
||||
}
|
||||
|
||||
pub fn get_min_cols(&self) -> i32 {
|
||||
return self.min_cols;
|
||||
}
|
||||
|
||||
pub fn get_max_cols(&self) -> i32 {
|
||||
return self.max_cols;
|
||||
}
|
||||
|
||||
pub fn get_min_rows(&self) -> i32 {
|
||||
return self.min_rows;
|
||||
}
|
||||
|
||||
pub fn get_max_rows(&self) -> i32 {
|
||||
return self.max_rows;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part
|
||||
*
|
||||
* 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::encoder;
|
||||
|
||||
/**
|
||||
* PDF417 error correction code following the algorithm described in ISO/IEC 15438:2001(E) in
|
||||
* chapter 4.10.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tables of coefficients for calculating error correction words
|
||||
* (see annex F, ISO/IEC 15438:2001(E))
|
||||
*/
|
||||
const EC_COEFFICIENTS: vec![vec![Vec<Vec<i32>>; 512]; 9] = vec![vec![27, 917, ]
|
||||
, vec![522, 568, 723, 809, ]
|
||||
, vec![237, 308, 436, 284, 646, 653, 428, 379, ]
|
||||
, vec![274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65, ]
|
||||
, vec![361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410, ]
|
||||
, vec![539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 400, 672, 762, 283, 184, 440, 35, 519, 31, 460, 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, 648, 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, 623, 264, 543, ]
|
||||
, vec![521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 292, 908, 490, 704, 516, 258, 457, 907, 594, 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, 193, 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, 463, 646, 776, 171, 491, 297, 763, 156, 732, 95, 270, 447, 90, 507, 48, 228, 821, 808, 898, 784, 663, 627, 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157, 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 804, 34, 211, 330, 539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 801, 4, 108, 539, ]
|
||||
, vec![524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 280, 201, 280, 828, 757, 710, 814, 919, 89, 68, 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, 439, 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, 549, 209, 884, 315, 70, 329, 793, 490, 274, 877, 162, 749, 812, 684, 461, 334, 376, 849, 521, 307, 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, 637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 538, 906, 90, 2, 290, 743, 199, 655, 903, 329, 49, 802, 580, 355, 588, 188, 462, 10, 134, 628, 320, 479, 130, 739, 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, 722, 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, 60, 732, 621, 895, 544, 261, 852, 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528, 503, 118, 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 73, 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 922, 191, 910, 532, 609, 829, 189, 20, 167, 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, 404, 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, 55, 497, 10, ]
|
||||
, vec![352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 87, 193, 352, 781, 846, 75, 327, 520, 435, 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, 539, 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, 916, 552, 41, 542, 289, 122, 272, 383, 800, 485, 98, 752, 472, 761, 107, 784, 860, 658, 741, 290, 204, 681, 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808, 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 258, 240, 518, 794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 596, 786, 303, 570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, 40, 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, 92, 358, 785, 288, 357, 850, 836, 827, 736, 707, 94, 8, 494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248, 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, 669, 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578, 37, 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 911, 283, 711, 472, 420, 245, 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, 842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, 159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 343, 693, 109, 608, 563, 365, 181, 772, 677, 310, 248, 353, 708, 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618, 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45, 787, 680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 905, 789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, 242, 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, 665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 459, 806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673, 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, 660, 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437, 375, 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 842, 37, 357, 720, 742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, 342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, 610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762, 752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596, 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, 407, 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, 223, 849, 647, 63, 310, 863, 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263, ]
|
||||
, ]
|
||||
;
|
||||
struct PDF417ErrorCorrection {
|
||||
}
|
||||
|
||||
impl PDF417ErrorCorrection {
|
||||
|
||||
fn new() -> PDF417ErrorCorrection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the number of error correction codewords for a specified error correction
|
||||
* level.
|
||||
*
|
||||
* @param errorCorrectionLevel the error correction level (0-8)
|
||||
* @return the number of codewords generated for error correction
|
||||
*/
|
||||
fn get_error_correction_codeword_count( error_correction_level: i32) -> i32 {
|
||||
if error_correction_level < 0 || error_correction_level > 8 {
|
||||
throw IllegalArgumentException::new("Error correction level must be between 0 and 8!");
|
||||
}
|
||||
return 1 << (error_correction_level + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recommended minimum error correction level as described in annex E of
|
||||
* ISO/IEC 15438:2001(E).
|
||||
*
|
||||
* @param n the number of data codewords
|
||||
* @return the recommended minimum error correction level
|
||||
*/
|
||||
fn get_recommended_minimum_error_correction_level( n: i32) -> /* throws WriterException */Result<i32, Rc<Exception>> {
|
||||
if n <= 0 {
|
||||
throw IllegalArgumentException::new("n must be > 0");
|
||||
}
|
||||
if n <= 40 {
|
||||
return Ok(2);
|
||||
}
|
||||
if n <= 160 {
|
||||
return Ok(3);
|
||||
}
|
||||
if n <= 320 {
|
||||
return Ok(4);
|
||||
}
|
||||
if n <= 863 {
|
||||
return Ok(5);
|
||||
}
|
||||
throw WriterException::new("No recommendation possible");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the error correction codewords according to 4.10 in ISO/IEC 15438:2001(E).
|
||||
*
|
||||
* @param dataCodewords the data codewords
|
||||
* @param errorCorrectionLevel the error correction level (0-8)
|
||||
* @return the String representing the error correction codewords
|
||||
*/
|
||||
fn generate_error_correction( data_codewords: &CharSequence, error_correction_level: i32) -> String {
|
||||
let k: i32 = ::get_error_correction_codeword_count(error_correction_level);
|
||||
let mut e: [Option<char>; k] = [None; k];
|
||||
let sld: i32 = data_codewords.length();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < sld {
|
||||
{
|
||||
let t1: i32 = (data_codewords.char_at(i) + e[e.len() - 1]) % 929;
|
||||
let mut t2: i32;
|
||||
let mut t3: i32;
|
||||
{
|
||||
let mut j: i32 = k - 1;
|
||||
while j >= 1 {
|
||||
{
|
||||
t2 = (t1 * EC_COEFFICIENTS[error_correction_level][j]) % 929;
|
||||
t3 = 929 - t2;
|
||||
e[j] = ((e[j - 1] + t3) % 929) as char;
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
t2 = (t1 * EC_COEFFICIENTS[error_correction_level][0]) % 929;
|
||||
t3 = 929 - t2;
|
||||
e[0] = (t3 % 929) as char;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let sb: StringBuilder = StringBuilder::new(k);
|
||||
{
|
||||
let mut j: i32 = k - 1;
|
||||
while j >= 0 {
|
||||
{
|
||||
if e[j] != 0 {
|
||||
e[j] = (929 - e[j]) as char;
|
||||
}
|
||||
sb.append(e[j]);
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return sb.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,778 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part
|
||||
*
|
||||
* 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::encoder;
|
||||
|
||||
/**
|
||||
* PDF417 high-level encoder following the algorithm described in ISO/IEC 15438:2001(E) in
|
||||
* annex P.
|
||||
*/
|
||||
|
||||
/**
|
||||
* code for Text compaction
|
||||
*/
|
||||
const TEXT_COMPACTION: i32 = 0;
|
||||
|
||||
/**
|
||||
* code for Byte compaction
|
||||
*/
|
||||
const BYTE_COMPACTION: i32 = 1;
|
||||
|
||||
/**
|
||||
* code for Numeric compaction
|
||||
*/
|
||||
const NUMERIC_COMPACTION: i32 = 2;
|
||||
|
||||
/**
|
||||
* Text compaction submode Alpha
|
||||
*/
|
||||
const SUBMODE_ALPHA: i32 = 0;
|
||||
|
||||
/**
|
||||
* Text compaction submode Lower
|
||||
*/
|
||||
const SUBMODE_LOWER: i32 = 1;
|
||||
|
||||
/**
|
||||
* Text compaction submode Mixed
|
||||
*/
|
||||
const SUBMODE_MIXED: i32 = 2;
|
||||
|
||||
/**
|
||||
* Text compaction submode Punctuation
|
||||
*/
|
||||
const SUBMODE_PUNCTUATION: i32 = 3;
|
||||
|
||||
/**
|
||||
* mode latch to Text Compaction mode
|
||||
*/
|
||||
const LATCH_TO_TEXT: i32 = 900;
|
||||
|
||||
/**
|
||||
* mode latch to Byte Compaction mode (number of characters NOT a multiple of 6)
|
||||
*/
|
||||
const LATCH_TO_BYTE_PADDED: i32 = 901;
|
||||
|
||||
/**
|
||||
* mode latch to Numeric Compaction mode
|
||||
*/
|
||||
const LATCH_TO_NUMERIC: i32 = 902;
|
||||
|
||||
/**
|
||||
* mode shift to Byte Compaction mode
|
||||
*/
|
||||
const SHIFT_TO_BYTE: i32 = 913;
|
||||
|
||||
/**
|
||||
* mode latch to Byte Compaction mode (number of characters a multiple of 6)
|
||||
*/
|
||||
const LATCH_TO_BYTE: i32 = 924;
|
||||
|
||||
/**
|
||||
* identifier for a user defined Extended Channel Interpretation (ECI)
|
||||
*/
|
||||
const ECI_USER_DEFINED: i32 = 925;
|
||||
|
||||
/**
|
||||
* identifier for a general purpose ECO format
|
||||
*/
|
||||
const ECI_GENERAL_PURPOSE: i32 = 926;
|
||||
|
||||
/**
|
||||
* identifier for an ECI of a character set of code page
|
||||
*/
|
||||
const ECI_CHARSET: i32 = 927;
|
||||
|
||||
/**
|
||||
* Raw code table for text compaction Mixed sub-mode
|
||||
*/
|
||||
const TEXT_MIXED_RAW: vec![Vec<i8>; 30] = vec![48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58, 35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0, ]
|
||||
;
|
||||
|
||||
/**
|
||||
* Raw code table for text compaction: Punctuation sub-mode
|
||||
*/
|
||||
const TEXT_PUNCTUATION_RAW: vec![Vec<i8>; 30] = vec![59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58, 10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0, ]
|
||||
;
|
||||
|
||||
const MIXED: [i8; 128] = [0; 128];
|
||||
|
||||
const PUNCTUATION: [i8; 128] = [0; 128];
|
||||
|
||||
const DEFAULT_ENCODING: Charset = StandardCharsets::ISO_8859_1;
|
||||
struct PDF417HighLevelEncoder {
|
||||
}
|
||||
|
||||
impl PDF417HighLevelEncoder {
|
||||
|
||||
fn new() -> PDF417HighLevelEncoder {
|
||||
}
|
||||
|
||||
static {
|
||||
//Construct inverse lookups
|
||||
Arrays::fill(&MIXED, -1 as i8);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < TEXT_MIXED_RAW.len() {
|
||||
{
|
||||
let mut b: i8 = TEXT_MIXED_RAW[i];
|
||||
if b > 0 {
|
||||
MIXED[b] = i as i8;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Arrays::fill(&PUNCTUATION, -1 as i8);
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < TEXT_PUNCTUATION_RAW.len() {
|
||||
{
|
||||
let mut b: i8 = TEXT_PUNCTUATION_RAW[i];
|
||||
if b > 0 {
|
||||
PUNCTUATION[b] = i as i8;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs high-level encoding of a PDF417 message using the algorithm described in annex P
|
||||
* of ISO/IEC 15438:2001(E). If byte compaction has been selected, then only byte compaction
|
||||
* is used.
|
||||
*
|
||||
* @param msg the message
|
||||
* @param compaction compaction mode to use
|
||||
* @param encoding character encoding used to encode in default or byte compaction
|
||||
* or {@code null} for default / not applicable
|
||||
* @param autoECI encode input minimally using multiple ECIs if needed
|
||||
* If autoECI encoding is specified and additionally {@code encoding} is specified, then the encoder
|
||||
* will use the specified {@link Charset} for any character that can be encoded by it, regardless
|
||||
* if a different encoding would lead to a more compact encoding. When no {@code encoding} is specified
|
||||
* then charsets will be chosen so that the byte representation is minimal.
|
||||
* @return the encoded message (the char values range from 0 to 928)
|
||||
*/
|
||||
fn encode_high_level( msg: &String, compaction: &Compaction, encoding: &Charset, auto_e_c_i: bool) -> /* throws WriterException */Result<String, Rc<Exception>> {
|
||||
if msg.is_empty() {
|
||||
throw WriterException::new("Empty message not allowed");
|
||||
}
|
||||
if encoding == null && !auto_e_c_i {
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < msg.length() {
|
||||
{
|
||||
if msg.char_at(i) > 255 {
|
||||
throw WriterException::new(format!("Non-encodable character detected: {} (Unicode: {}). Consider specifying EncodeHintType.PDF417_AUTO_ECI and/or EncodeTypeHint.CHARACTER_SET.", msg.char_at(i), msg.char_at(i) as i32));
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//the codewords 0..928 are encoded as Unicode characters
|
||||
let sb: StringBuilder = StringBuilder::new(&msg.length());
|
||||
let mut input: ECIInput;
|
||||
if auto_e_c_i {
|
||||
input = MinimalECIInput::new(&msg, &encoding, -1);
|
||||
} else {
|
||||
input = NoECIInput::new(&msg);
|
||||
if encoding == null {
|
||||
encoding = DEFAULT_ENCODING;
|
||||
} else if !DEFAULT_ENCODING::equals(&encoding) {
|
||||
let eci: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i(&encoding);
|
||||
if eci != null {
|
||||
::encoding_e_c_i(&eci.get_value(), &sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
let len: i32 = input.length();
|
||||
let mut p: i32 = 0;
|
||||
let text_sub_mode: i32 = SUBMODE_ALPHA;
|
||||
// User selected encoding mode
|
||||
match compaction {
|
||||
TEXT =>
|
||||
{
|
||||
::encode_text(input, p, len, &sb, text_sub_mode);
|
||||
break;
|
||||
}
|
||||
BYTE =>
|
||||
{
|
||||
if auto_e_c_i {
|
||||
::encode_multi_e_c_i_binary(input, 0, &input.length(), TEXT_COMPACTION, &sb);
|
||||
} else {
|
||||
let msg_bytes: Vec<i8> = input.to_string().get_bytes(&encoding);
|
||||
::encode_binary(&msg_bytes, p, msg_bytes.len(), BYTE_COMPACTION, &sb);
|
||||
}
|
||||
break;
|
||||
}
|
||||
NUMERIC =>
|
||||
{
|
||||
sb.append(LATCH_TO_NUMERIC as char);
|
||||
::encode_numeric(input, p, len, &sb);
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
//Default mode, see 4.4.2.1
|
||||
let encoding_mode: i32 = TEXT_COMPACTION;
|
||||
while p < len {
|
||||
while p < len && input.is_e_c_i(p) {
|
||||
::encoding_e_c_i(&input.get_e_c_i_value(p), &sb);
|
||||
p += 1;
|
||||
}
|
||||
if p >= len {
|
||||
break;
|
||||
}
|
||||
let n: i32 = ::determine_consecutive_digit_count(input, p);
|
||||
if n >= 13 {
|
||||
sb.append(LATCH_TO_NUMERIC as char);
|
||||
encoding_mode = NUMERIC_COMPACTION;
|
||||
//Reset after latch
|
||||
text_sub_mode = SUBMODE_ALPHA;
|
||||
::encode_numeric(input, p, n, &sb);
|
||||
p += n;
|
||||
} else {
|
||||
let t: i32 = ::determine_consecutive_text_count(input, p);
|
||||
if t >= 5 || n == len {
|
||||
if encoding_mode != TEXT_COMPACTION {
|
||||
sb.append(LATCH_TO_TEXT as char);
|
||||
encoding_mode = TEXT_COMPACTION;
|
||||
//start with submode alpha after latch
|
||||
text_sub_mode = SUBMODE_ALPHA;
|
||||
}
|
||||
text_sub_mode = ::encode_text(input, p, t, &sb, text_sub_mode);
|
||||
p += t;
|
||||
} else {
|
||||
let mut b: i32 = ::determine_consecutive_binary_count(input, p, if auto_e_c_i { null } else { encoding });
|
||||
if b == 0 {
|
||||
b = 1;
|
||||
}
|
||||
let bytes: Vec<i8> = if auto_e_c_i { null } else { input.sub_sequence(p, p + b).to_string().get_bytes(&encoding) };
|
||||
if ((bytes == null && b == 1) || (bytes != null && bytes.len() == 1)) && encoding_mode == TEXT_COMPACTION {
|
||||
//Switch for one byte (instead of latch)
|
||||
if auto_e_c_i {
|
||||
::encode_multi_e_c_i_binary(input, p, 1, TEXT_COMPACTION, &sb);
|
||||
} else {
|
||||
::encode_binary(&bytes, 0, 1, TEXT_COMPACTION, &sb);
|
||||
}
|
||||
} else {
|
||||
//Mode latch performed by encodeBinary()
|
||||
if auto_e_c_i {
|
||||
::encode_multi_e_c_i_binary(input, p, p + b, encoding_mode, &sb);
|
||||
} else {
|
||||
::encode_binary(&bytes, 0, bytes.len(), encoding_mode, &sb);
|
||||
}
|
||||
encoding_mode = BYTE_COMPACTION;
|
||||
//Reset after latch
|
||||
text_sub_mode = SUBMODE_ALPHA;
|
||||
}
|
||||
p += b;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Ok(sb.to_string());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E),
|
||||
* chapter 4.4.2.
|
||||
*
|
||||
* @param input the input
|
||||
* @param startpos the start position within the message
|
||||
* @param count the number of characters to encode
|
||||
* @param sb receives the encoded codewords
|
||||
* @param initialSubmode should normally be SUBMODE_ALPHA
|
||||
* @return the text submode in which this method ends
|
||||
*/
|
||||
fn encode_text( input: &ECIInput, startpos: i32, count: i32, sb: &StringBuilder, initial_submode: i32) -> /* throws WriterException */Result<i32, Rc<Exception>> {
|
||||
let tmp: StringBuilder = StringBuilder::new(count);
|
||||
let mut submode: i32 = initial_submode;
|
||||
let mut idx: i32 = 0;
|
||||
while true {
|
||||
if input.is_e_c_i(startpos + idx) {
|
||||
::encoding_e_c_i(&input.get_e_c_i_value(startpos + idx), &sb);
|
||||
idx += 1;
|
||||
} else {
|
||||
let ch: char = input.char_at(startpos + idx);
|
||||
match submode {
|
||||
SUBMODE_ALPHA =>
|
||||
{
|
||||
if ::is_alpha_upper(ch) {
|
||||
if ch == ' ' {
|
||||
//space
|
||||
tmp.append(26 as char);
|
||||
} else {
|
||||
tmp.append((ch - 65) as char);
|
||||
}
|
||||
} else {
|
||||
if ::is_alpha_lower(ch) {
|
||||
submode = SUBMODE_LOWER;
|
||||
//ll
|
||||
tmp.append(27 as char);
|
||||
continue;
|
||||
} else if ::is_mixed(ch) {
|
||||
submode = SUBMODE_MIXED;
|
||||
//ml
|
||||
tmp.append(28 as char);
|
||||
continue;
|
||||
} else {
|
||||
//ps
|
||||
tmp.append(29 as char);
|
||||
tmp.append(PUNCTUATION[ch] as char);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
SUBMODE_LOWER =>
|
||||
{
|
||||
if ::is_alpha_lower(ch) {
|
||||
if ch == ' ' {
|
||||
//space
|
||||
tmp.append(26 as char);
|
||||
} else {
|
||||
tmp.append((ch - 97) as char);
|
||||
}
|
||||
} else {
|
||||
if ::is_alpha_upper(ch) {
|
||||
//as
|
||||
tmp.append(27 as char);
|
||||
tmp.append((ch - 65) as char);
|
||||
//space cannot happen here, it is also in "Lower"
|
||||
break;
|
||||
} else if ::is_mixed(ch) {
|
||||
submode = SUBMODE_MIXED;
|
||||
//ml
|
||||
tmp.append(28 as char);
|
||||
continue;
|
||||
} else {
|
||||
//ps
|
||||
tmp.append(29 as char);
|
||||
tmp.append(PUNCTUATION[ch] as char);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
SUBMODE_MIXED =>
|
||||
{
|
||||
if ::is_mixed(ch) {
|
||||
tmp.append(MIXED[ch] as char);
|
||||
} else {
|
||||
if ::is_alpha_upper(ch) {
|
||||
submode = SUBMODE_ALPHA;
|
||||
//al
|
||||
tmp.append(28 as char);
|
||||
continue;
|
||||
} else if ::is_alpha_lower(ch) {
|
||||
submode = SUBMODE_LOWER;
|
||||
//ll
|
||||
tmp.append(27 as char);
|
||||
continue;
|
||||
} else {
|
||||
if startpos + idx + 1 < count {
|
||||
if !input.is_e_c_i(startpos + idx + 1) && ::is_punctuation(&input.char_at(startpos + idx + 1)) {
|
||||
submode = SUBMODE_PUNCTUATION;
|
||||
//pl
|
||||
tmp.append(25 as char);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//ps
|
||||
tmp.append(29 as char);
|
||||
tmp.append(PUNCTUATION[ch] as char);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
//SUBMODE_PUNCTUATION
|
||||
if ::is_punctuation(ch) {
|
||||
tmp.append(PUNCTUATION[ch] as char);
|
||||
} else {
|
||||
submode = SUBMODE_ALPHA;
|
||||
//al
|
||||
tmp.append(29 as char);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
idx += 1;
|
||||
if idx >= count {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut h: char = 0;
|
||||
let len: i32 = tmp.length();
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < len {
|
||||
{
|
||||
let odd: bool = (i % 2) != 0;
|
||||
if odd {
|
||||
h = ((h * 30) + tmp.char_at(i)) as char;
|
||||
sb.append(h);
|
||||
} else {
|
||||
h = tmp.char_at(i);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len % 2) != 0 {
|
||||
//ps
|
||||
sb.append(((h * 30) + 29) as char);
|
||||
}
|
||||
return Ok(submode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode all of the message using Byte Compaction as described in ISO/IEC 15438:2001(E)
|
||||
*
|
||||
* @param input the input
|
||||
* @param startpos the start position within the message
|
||||
* @param count the number of bytes to encode
|
||||
* @param startmode the mode from which this method starts
|
||||
* @param sb receives the encoded codewords
|
||||
*/
|
||||
fn encode_multi_e_c_i_binary( input: &ECIInput, startpos: i32, count: i32, startmode: i32, sb: &StringBuilder) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
let end: i32 = Math::min(startpos + count, &input.length());
|
||||
let local_start: i32 = startpos;
|
||||
while true {
|
||||
//encode all leading ECIs and advance localStart
|
||||
while local_start < end && input.is_e_c_i(local_start) {
|
||||
::encoding_e_c_i(&input.get_e_c_i_value(local_start), &sb);
|
||||
local_start += 1;
|
||||
}
|
||||
let local_end: i32 = local_start;
|
||||
//advance end until before the next ECI
|
||||
while local_end < end && !input.is_e_c_i(local_end) {
|
||||
local_end += 1;
|
||||
}
|
||||
let local_count: i32 = local_end - local_start;
|
||||
if local_count <= 0 {
|
||||
//done
|
||||
break;
|
||||
} else {
|
||||
//encode the segment
|
||||
::encode_binary(&::sub_bytes(input, local_start, local_end), 0, local_count, if local_start == startpos { startmode } else { BYTE_COMPACTION }, &sb);
|
||||
local_start = local_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_bytes( input: &ECIInput, start: i32, end: i32) -> Vec<i8> {
|
||||
let count: i32 = end - start;
|
||||
let mut result: [i8; count] = [0; count];
|
||||
{
|
||||
let mut i: i32 = start;
|
||||
while i < end {
|
||||
{
|
||||
result[i - start] = (input.char_at(i) & 0xff) as i8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode parts of the message using Byte Compaction as described in ISO/IEC 15438:2001(E),
|
||||
* chapter 4.4.3. The Unicode characters will be converted to binary using the cp437
|
||||
* codepage.
|
||||
*
|
||||
* @param bytes the message converted to a byte array
|
||||
* @param startpos the start position within the message
|
||||
* @param count the number of bytes to encode
|
||||
* @param startmode the mode from which this method starts
|
||||
* @param sb receives the encoded codewords
|
||||
*/
|
||||
fn encode_binary( bytes: &Vec<i8>, startpos: i32, count: i32, startmode: i32, sb: &StringBuilder) {
|
||||
if count == 1 && startmode == TEXT_COMPACTION {
|
||||
sb.append(SHIFT_TO_BYTE as char);
|
||||
} else {
|
||||
if (count % 6) == 0 {
|
||||
sb.append(LATCH_TO_BYTE as char);
|
||||
} else {
|
||||
sb.append(LATCH_TO_BYTE_PADDED as char);
|
||||
}
|
||||
}
|
||||
let mut idx: i32 = startpos;
|
||||
// Encode sixpacks
|
||||
if count >= 6 {
|
||||
let mut chars: [Option<char>; 5] = [None; 5];
|
||||
while (startpos + count - idx) >= 6 {
|
||||
let mut t: i64 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 6 {
|
||||
{
|
||||
t <<= 8;
|
||||
t += bytes[idx + i] & 0xff;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 5 {
|
||||
{
|
||||
chars[i] = (t % 900) as char;
|
||||
t /= 900;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut i: i32 = chars.len() - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
sb.append(chars[i]);
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
idx += 6;
|
||||
}
|
||||
}
|
||||
//Encode rest (remaining n<5 bytes if any)
|
||||
{
|
||||
let mut i: i32 = idx;
|
||||
while i < startpos + count {
|
||||
{
|
||||
let ch: i32 = bytes[i] & 0xff;
|
||||
sb.append(ch as char);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn encode_numeric( input: &ECIInput, startpos: i32, count: i32, sb: &StringBuilder) {
|
||||
let mut idx: i32 = 0;
|
||||
let tmp: StringBuilder = StringBuilder::new(count / 3 + 1);
|
||||
let num900: BigInteger = BigInteger::value_of(900);
|
||||
let num0: BigInteger = BigInteger::value_of(0);
|
||||
while idx < count {
|
||||
tmp.set_length(0);
|
||||
let len: i32 = Math::min(44, count - idx);
|
||||
let part: String = format!("1{}", input.sub_sequence(startpos + idx, startpos + idx + len));
|
||||
let mut bigint: BigInteger = BigInteger::new(&part);
|
||||
loop { {
|
||||
tmp.append(bigint.mod(&num900).int_value() as char);
|
||||
bigint = bigint.divide(&num900);
|
||||
}if !(!bigint.equals(&num0)) break;}
|
||||
//Reverse temporary string
|
||||
{
|
||||
let mut i: i32 = tmp.length() - 1;
|
||||
while i >= 0 {
|
||||
{
|
||||
sb.append(&tmp.char_at(i));
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
idx += len;
|
||||
}
|
||||
}
|
||||
|
||||
fn is_digit( ch: char) -> bool {
|
||||
return ch >= '0' && ch <= '9';
|
||||
}
|
||||
|
||||
fn is_alpha_upper( ch: char) -> bool {
|
||||
return ch == ' ' || (ch >= 'A' && ch <= 'Z');
|
||||
}
|
||||
|
||||
fn is_alpha_lower( ch: char) -> bool {
|
||||
return ch == ' ' || (ch >= 'a' && ch <= 'z');
|
||||
}
|
||||
|
||||
fn is_mixed( ch: char) -> bool {
|
||||
return MIXED[ch] != -1;
|
||||
}
|
||||
|
||||
fn is_punctuation( ch: char) -> bool {
|
||||
return PUNCTUATION[ch] != -1;
|
||||
}
|
||||
|
||||
fn is_text( ch: char) -> bool {
|
||||
return ch == '\t' || ch == '\n' || ch == '\r' || (ch >= 32 && ch <= 126);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the number of consecutive characters that are encodable using numeric compaction.
|
||||
*
|
||||
* @param input the input
|
||||
* @param startpos the start position within the input
|
||||
* @return the requested character count
|
||||
*/
|
||||
fn determine_consecutive_digit_count( input: &ECIInput, startpos: i32) -> i32 {
|
||||
let mut count: i32 = 0;
|
||||
let len: i32 = input.length();
|
||||
let mut idx: i32 = startpos;
|
||||
if idx < len {
|
||||
while idx < len && !input.is_e_c_i(idx) && ::is_digit(&input.char_at(idx)) {
|
||||
count += 1;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the number of consecutive characters that are encodable using text compaction.
|
||||
*
|
||||
* @param input the input
|
||||
* @param startpos the start position within the input
|
||||
* @return the requested character count
|
||||
*/
|
||||
fn determine_consecutive_text_count( input: &ECIInput, startpos: i32) -> i32 {
|
||||
let len: i32 = input.length();
|
||||
let mut idx: i32 = startpos;
|
||||
while idx < len {
|
||||
let numeric_count: i32 = 0;
|
||||
while numeric_count < 13 && idx < len && !input.is_e_c_i(idx) && ::is_digit(&input.char_at(idx)) {
|
||||
numeric_count += 1;
|
||||
idx += 1;
|
||||
}
|
||||
if numeric_count >= 13 {
|
||||
return idx - startpos - numeric_count;
|
||||
}
|
||||
if numeric_count > 0 {
|
||||
//Heuristic: All text-encodable chars or digits are binary encodable
|
||||
continue;
|
||||
}
|
||||
//Check if character is encodable
|
||||
if input.is_e_c_i(idx) || !::is_text(&input.char_at(idx)) {
|
||||
break;
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
return idx - startpos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the number of consecutive characters that are encodable using binary compaction.
|
||||
*
|
||||
* @param input the input
|
||||
* @param startpos the start position within the message
|
||||
* @param encoding the charset used to convert the message to a byte array
|
||||
* @return the requested character count
|
||||
*/
|
||||
fn determine_consecutive_binary_count( input: &ECIInput, startpos: i32, encoding: &Charset) -> /* throws WriterException */Result<i32, Rc<Exception>> {
|
||||
let encoder: CharsetEncoder = if encoding == null { null } else { encoding.new_encoder() };
|
||||
let len: i32 = input.length();
|
||||
let mut idx: i32 = startpos;
|
||||
while idx < len {
|
||||
let numeric_count: i32 = 0;
|
||||
let mut i: i32 = idx;
|
||||
while numeric_count < 13 && !input.is_e_c_i(i) && ::is_digit(&input.char_at(i)) {
|
||||
numeric_count += 1;
|
||||
//textCount++;
|
||||
i = idx + numeric_count;
|
||||
if i >= len {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if numeric_count >= 13 {
|
||||
return Ok(idx - startpos);
|
||||
}
|
||||
if encoder != null && !encoder.can_encode(&input.char_at(idx)) {
|
||||
assert!( input instanceof NoECIInput);
|
||||
let ch: char = input.char_at(idx);
|
||||
throw WriterException::new(format!("Non-encodable character detected: {} (Unicode: {})", ch, ch as i32));
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
return Ok(idx - startpos);
|
||||
}
|
||||
|
||||
fn encoding_e_c_i( eci: i32, sb: &StringBuilder) -> /* throws WriterException */Result<Void, Rc<Exception>> {
|
||||
if eci >= 0 && eci < 900 {
|
||||
sb.append(ECI_CHARSET as char);
|
||||
sb.append(eci as char);
|
||||
} else if eci < 810900 {
|
||||
sb.append(ECI_GENERAL_PURPOSE as char);
|
||||
sb.append((eci / 900 - 1) as char);
|
||||
sb.append((eci % 900) as char);
|
||||
} else if eci < 811800 {
|
||||
sb.append(ECI_USER_DEFINED as char);
|
||||
sb.append((810900 - eci) as char);
|
||||
} else {
|
||||
throw WriterException::new(format!("ECI number not in valid range from 0..811799, but was {}", eci));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ECIInput)]
|
||||
struct NoECIInput {
|
||||
|
||||
let input: String;
|
||||
}
|
||||
|
||||
impl NoECIInput {
|
||||
|
||||
fn new( input: &String) -> NoECIInput {
|
||||
let .input = input;
|
||||
}
|
||||
|
||||
pub fn length(&self) -> i32 {
|
||||
return self.input.length();
|
||||
}
|
||||
|
||||
pub fn char_at(&self, index: i32) -> char {
|
||||
return self.input.char_at(index);
|
||||
}
|
||||
|
||||
pub fn is_e_c_i(&self, index: i32) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn get_e_c_i_value(&self, index: i32) -> i32 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pub fn have_n_characters(&self, index: i32, n: i32) -> bool {
|
||||
return index + n <= self.input.length();
|
||||
}
|
||||
|
||||
pub fn sub_sequence(&self, start: i32, end: i32) -> CharSequence {
|
||||
return self.input.sub_sequence(start, end);
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
return self.input;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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::encoder;
|
||||
|
||||
pub struct PDF417HighLevelEncoderTestAdapter {
|
||||
}
|
||||
|
||||
impl PDF417HighLevelEncoderTestAdapter {
|
||||
|
||||
fn new() -> PDF417HighLevelEncoderTestAdapter {
|
||||
}
|
||||
|
||||
pub fn encode_high_level( msg: &String, compaction: &Compaction, encoding: &Charset, auto_e_c_i: bool) -> /* throws WriterException */Result<String, Rc<Exception>> {
|
||||
return Ok(PDF417HighLevelEncoder::encode_high_level(&msg, compaction, &encoding, auto_e_c_i));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode PDF417 codes in an image.
|
||||
*
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
const EMPTY_RESULT_ARRAY: [Option<Result>; 0] = [None; 0];
|
||||
#[derive(Reader, MultipleBarcodeReader)]
|
||||
pub struct PDF417Reader {
|
||||
}
|
||||
|
||||
impl PDF417Reader {
|
||||
|
||||
/**
|
||||
* Locates and decodes a PDF417 code in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the PDF417 code
|
||||
* @throws NotFoundException if a PDF417 code cannot be found,
|
||||
* @throws FormatException if a PDF417 cannot be decoded
|
||||
*/
|
||||
pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, FormatException, ChecksumException */Result<Result, Rc<Exception>> {
|
||||
return Ok(::decode(image, null));
|
||||
}
|
||||
|
||||
pub fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, FormatException, ChecksumException */Result<Result, Rc<Exception>> {
|
||||
let result: Vec<Result> = ::decode(image, &hints, false);
|
||||
if result.len() == 0 || result[0] == null {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
return Ok(result[0]);
|
||||
}
|
||||
|
||||
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 tryResult1 = 0;
|
||||
'try1: loop {
|
||||
{
|
||||
return Ok(::decode(image, &hints, true));
|
||||
}
|
||||
break 'try1
|
||||
}
|
||||
match tryResult1 {
|
||||
catch ( ignored: &FormatExceptionChecksumException | ) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
} 0 => break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn decode( image: &BinaryBitmap, hints: &Map<DecodeHintType, ?>, multiple: bool) -> /* throws NotFoundException, FormatException, ChecksumException */Result<Vec<Result>, Rc<Exception>> {
|
||||
let results: List<Result> = ArrayList<>::new();
|
||||
let detector_result: PDF417DetectorResult = Detector::detect(image, &hints, multiple);
|
||||
for let points: Vec<ResultPoint> in detector_result.get_points() {
|
||||
let decoder_result: DecoderResult = PDF417ScanningDecoder::decode(&detector_result.get_bits(), points[4], points[5], points[6], points[7], &::get_min_codeword_width(points), &::get_max_codeword_width(points));
|
||||
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::PDF_417);
|
||||
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &decoder_result.get_e_c_level());
|
||||
let pdf417_result_metadata: PDF417ResultMetadata = decoder_result.get_other() as PDF417ResultMetadata;
|
||||
if pdf417_result_metadata != null {
|
||||
result.put_metadata(ResultMetadataType::PDF417_EXTRA_METADATA, pdf417_result_metadata);
|
||||
}
|
||||
result.put_metadata(ResultMetadataType::ORIENTATION, &detector_result.get_rotation());
|
||||
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]L{}", decoder_result.get_symbology_modifier()));
|
||||
results.add(result);
|
||||
}
|
||||
return Ok(results.to_array(EMPTY_RESULT_ARRAY));
|
||||
}
|
||||
|
||||
fn get_max_width( p1: &ResultPoint, p2: &ResultPoint) -> i32 {
|
||||
if p1 == null || p2 == null {
|
||||
return 0;
|
||||
}
|
||||
return Math::abs(p1.get_x() - p2.get_x()) as i32;
|
||||
}
|
||||
|
||||
fn get_min_width( p1: &ResultPoint, p2: &ResultPoint) -> i32 {
|
||||
if p1 == null || p2 == null {
|
||||
return Integer::MAX_VALUE;
|
||||
}
|
||||
return Math::abs(p1.get_x() - p2.get_x()) as i32;
|
||||
}
|
||||
|
||||
fn get_max_codeword_width( p: &Vec<ResultPoint>) -> i32 {
|
||||
return Math::max(&Math::max(&::get_max_width(p[0], p[4]), ::get_max_width(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD / PDF417Common.MODULES_IN_STOP_PATTERN), &Math::max(&::get_max_width(p[1], p[5]), ::get_max_width(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD / PDF417Common.MODULES_IN_STOP_PATTERN));
|
||||
}
|
||||
|
||||
fn get_min_codeword_width( p: &Vec<ResultPoint>) -> i32 {
|
||||
return Math::min(&Math::min(&::get_min_width(p[0], p[4]), ::get_min_width(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD / PDF417Common.MODULES_IN_STOP_PATTERN), &Math::min(&::get_min_width(p[1], p[5]), ::get_min_width(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD / PDF417Common.MODULES_IN_STOP_PATTERN));
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
// nothing needs to be reset
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::pdf417;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
pub struct PDF417ResultMetadata {
|
||||
|
||||
let segment_index: i32;
|
||||
|
||||
let file_id: String;
|
||||
|
||||
let last_segment: bool;
|
||||
|
||||
let segment_count: i32 = -1;
|
||||
|
||||
let sender: String;
|
||||
|
||||
let addressee: String;
|
||||
|
||||
let file_name: String;
|
||||
|
||||
let file_size: i64 = -1;
|
||||
|
||||
let timestamp: i64 = -1;
|
||||
|
||||
let checksum: i32 = -1;
|
||||
|
||||
let optional_data: Vec<i32>;
|
||||
}
|
||||
|
||||
impl PDF417ResultMetadata {
|
||||
|
||||
/**
|
||||
* The Segment ID represents the segment of the whole file distributed over different symbols.
|
||||
*
|
||||
* @return File segment index
|
||||
*/
|
||||
pub fn get_segment_index(&self) -> i32 {
|
||||
return self.segment_index;
|
||||
}
|
||||
|
||||
pub fn set_segment_index(&self, segment_index: i32) {
|
||||
self.segmentIndex = segment_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the same for each related PDF417 symbol
|
||||
*
|
||||
* @return File ID
|
||||
*/
|
||||
pub fn get_file_id(&self) -> String {
|
||||
return self.file_id;
|
||||
}
|
||||
|
||||
pub fn set_file_id(&self, file_id: &String) {
|
||||
self.fileId = file_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always null
|
||||
* @deprecated use dedicated already parsed fields
|
||||
*/
|
||||
pub fn get_optional_data(&self) -> Vec<i32> {
|
||||
return self.optional_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param optionalData old optional data format as int array
|
||||
* @deprecated parse and use new fields
|
||||
*/
|
||||
pub fn set_optional_data(&self, optional_data: &Vec<i32>) {
|
||||
self.optionalData = optional_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if it is the last segment
|
||||
*/
|
||||
pub fn is_last_segment(&self) -> bool {
|
||||
return self.last_segment;
|
||||
}
|
||||
|
||||
pub fn set_last_segment(&self, last_segment: bool) {
|
||||
self.lastSegment = last_segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return count of segments, -1 if not set
|
||||
*/
|
||||
pub fn get_segment_count(&self) -> i32 {
|
||||
return self.segment_count;
|
||||
}
|
||||
|
||||
pub fn set_segment_count(&self, segment_count: i32) {
|
||||
self.segmentCount = segment_count;
|
||||
}
|
||||
|
||||
pub fn get_sender(&self) -> String {
|
||||
return self.sender;
|
||||
}
|
||||
|
||||
pub fn set_sender(&self, sender: &String) {
|
||||
self.sender = sender;
|
||||
}
|
||||
|
||||
pub fn get_addressee(&self) -> String {
|
||||
return self.addressee;
|
||||
}
|
||||
|
||||
pub fn set_addressee(&self, addressee: &String) {
|
||||
self.addressee = addressee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename of the encoded file
|
||||
*
|
||||
* @return filename
|
||||
*/
|
||||
pub fn get_file_name(&self) -> String {
|
||||
return self.file_name;
|
||||
}
|
||||
|
||||
pub fn set_file_name(&self, file_name: &String) {
|
||||
self.fileName = file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* filesize in bytes of the encoded file
|
||||
*
|
||||
* @return filesize in bytes, -1 if not set
|
||||
*/
|
||||
pub fn get_file_size(&self) -> i64 {
|
||||
return self.file_size;
|
||||
}
|
||||
|
||||
pub fn set_file_size(&self, file_size: i64) {
|
||||
self.fileSize = file_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 16-bit CRC checksum using CCITT-16
|
||||
*
|
||||
* @return crc checksum, -1 if not set
|
||||
*/
|
||||
pub fn get_checksum(&self) -> i32 {
|
||||
return self.checksum;
|
||||
}
|
||||
|
||||
pub fn set_checksum(&self, checksum: i32) {
|
||||
self.checksum = checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* unix epock timestamp, elapsed seconds since 1970-01-01
|
||||
*
|
||||
* @return elapsed seconds, -1 if not set
|
||||
*/
|
||||
pub fn get_timestamp(&self) -> i64 {
|
||||
return self.timestamp;
|
||||
}
|
||||
|
||||
pub fn set_timestamp(&self, timestamp: i64) {
|
||||
self.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Jacob Haynes
|
||||
* @author qwandor@google.com (Andrew Walbran)
|
||||
*/
|
||||
|
||||
/**
|
||||
* default white space (margin) around the code
|
||||
*/
|
||||
const WHITE_SPACE: i32 = 30;
|
||||
|
||||
/**
|
||||
* default error correction level
|
||||
*/
|
||||
const DEFAULT_ERROR_CORRECTION_LEVEL: i32 = 2;
|
||||
#[derive(Writer)]
|
||||
pub struct PDF417Writer {
|
||||
}
|
||||
|
||||
impl PDF417Writer {
|
||||
|
||||
pub fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, ?>) -> /* throws WriterException */Result<BitMatrix, Rc<Exception>> {
|
||||
if format != BarcodeFormat::PDF_417 {
|
||||
throw IllegalArgumentException::new(format!("Can only encode PDF_417, but got {}", format));
|
||||
}
|
||||
let encoder: PDF417 = PDF417::new();
|
||||
let mut margin: i32 = WHITE_SPACE;
|
||||
let error_correction_level: i32 = DEFAULT_ERROR_CORRECTION_LEVEL;
|
||||
let auto_e_c_i: bool = false;
|
||||
if hints != null {
|
||||
if hints.contains_key(EncodeHintType::PDF417_COMPACT) {
|
||||
encoder.set_compact(&Boolean::parse_boolean(&hints.get(EncodeHintType::PDF417_COMPACT).to_string()));
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::PDF417_COMPACTION) {
|
||||
encoder.set_compaction(&Compaction::value_of(&hints.get(EncodeHintType::PDF417_COMPACTION).to_string()));
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::PDF417_DIMENSIONS) {
|
||||
let dimensions: Dimensions = hints.get(EncodeHintType::PDF417_DIMENSIONS) as Dimensions;
|
||||
encoder.set_dimensions(&dimensions.get_max_cols(), &dimensions.get_min_cols(), &dimensions.get_max_rows(), &dimensions.get_min_rows());
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::MARGIN) {
|
||||
margin = Integer::parse_int(&hints.get(EncodeHintType::MARGIN).to_string());
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::ERROR_CORRECTION) {
|
||||
error_correction_level = Integer::parse_int(&hints.get(EncodeHintType::ERROR_CORRECTION).to_string());
|
||||
}
|
||||
if hints.contains_key(EncodeHintType::CHARACTER_SET) {
|
||||
let encoding: Charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
|
||||
encoder.set_encoding(&encoding);
|
||||
}
|
||||
auto_e_c_i = hints.contains_key(EncodeHintType::PDF417_AUTO_ECI) && Boolean::parse_boolean(&hints.get(EncodeHintType::PDF417_AUTO_ECI).to_string());
|
||||
}
|
||||
return Ok(::bit_matrix_from_encoder(encoder, &contents, error_correction_level, width, height, margin, auto_e_c_i));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes encoder, accounts for width/height, and retrieves bit matrix
|
||||
*/
|
||||
fn bit_matrix_from_encoder( encoder: &PDF417, contents: &String, error_correction_level: i32, width: i32, height: i32, margin: i32, auto_e_c_i: bool) -> /* throws WriterException */Result<BitMatrix, Rc<Exception>> {
|
||||
encoder.generate_barcode_logic(&contents, error_correction_level, auto_e_c_i);
|
||||
let aspect_ratio: i32 = 4;
|
||||
let original_scale: Vec<Vec<i8>> = encoder.get_barcode_matrix().get_scaled_matrix(1, aspect_ratio);
|
||||
let mut rotated: bool = false;
|
||||
if (height > width) != (original_scale[0].len() < original_scale.len()) {
|
||||
original_scale = ::rotate_array(&original_scale);
|
||||
rotated = true;
|
||||
}
|
||||
let scale_x: i32 = width / original_scale[0].len();
|
||||
let scale_y: i32 = height / original_scale.len();
|
||||
let scale: i32 = Math::min(scale_x, scale_y);
|
||||
if scale > 1 {
|
||||
let scaled_matrix: Vec<Vec<i8>> = encoder.get_barcode_matrix().get_scaled_matrix(scale, scale * aspect_ratio);
|
||||
if rotated {
|
||||
scaled_matrix = ::rotate_array(&scaled_matrix);
|
||||
}
|
||||
return Ok(::bit_matrix_from_bit_array(&scaled_matrix, margin));
|
||||
}
|
||||
return Ok(::bit_matrix_from_bit_array(&original_scale, margin));
|
||||
}
|
||||
|
||||
/**
|
||||
* This takes an array holding the values of the PDF 417
|
||||
*
|
||||
* @param input a byte array of information with 0 is black, and 1 is white
|
||||
* @param margin border around the barcode
|
||||
* @return BitMatrix of the input
|
||||
*/
|
||||
fn bit_matrix_from_bit_array( input: &Vec<Vec<i8>>, margin: i32) -> BitMatrix {
|
||||
// Creates the bit matrix with extra space for whitespace
|
||||
let output: BitMatrix = BitMatrix::new(input[0].len() + 2 * margin, input.len() + 2 * margin);
|
||||
output.clear();
|
||||
{
|
||||
let mut y: i32 = 0, let y_output: i32 = output.get_height() - margin - 1;
|
||||
while y < input.len() {
|
||||
{
|
||||
let input_y: Vec<i8> = input[y];
|
||||
{
|
||||
let mut x: i32 = 0;
|
||||
while x < input[0].len() {
|
||||
{
|
||||
// Zero is white in the byte matrix
|
||||
if input_y[x] == 1 {
|
||||
output.set(x + margin, y_output);
|
||||
}
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
y += 1;
|
||||
y_output -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes and rotates the it 90 degrees
|
||||
*/
|
||||
fn rotate_array( bitarray: &Vec<Vec<i8>>) -> Vec<Vec<i8>> {
|
||||
let mut temp: [[i8; bitarray.len()]; bitarray[0].len()] = [[0; bitarray.len()]; bitarray[0].len()];
|
||||
{
|
||||
let mut ii: i32 = 0;
|
||||
while ii < bitarray.len() {
|
||||
{
|
||||
// This makes the direction consistent on screen when rotating the
|
||||
// screen;
|
||||
let mut inverseii: i32 = bitarray.len() - ii - 1;
|
||||
{
|
||||
let mut jj: i32 = 0;
|
||||
while jj < bitarray[0].len() {
|
||||
{
|
||||
temp[jj][inverseii] = bitarray[ii][jj];
|
||||
}
|
||||
jj += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ii += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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