mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 12:22: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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user