mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
oned moved
This commit is contained in:
@@ -1,437 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::oned;
|
||||
|
||||
/**
|
||||
* <p>Decodes Codabar barcodes.</p>
|
||||
*
|
||||
* @author Bas Vijfwinkel
|
||||
* @author David Walker
|
||||
*/
|
||||
|
||||
// These values are critical for determining how permissive the decoding
|
||||
// will be. All stripe sizes must be within the window these define, as
|
||||
// compared to the average stripe size.
|
||||
const MAX_ACCEPTABLE: f32 = 2.0f;
|
||||
|
||||
const PADDING: f32 = 1.5f;
|
||||
|
||||
const ALPHABET_STRING: &'static str = "0123456789-$:/.+ABCD";
|
||||
|
||||
const ALPHABET: Vec<char> = ALPHABET_STRING::to_char_array();
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of
|
||||
* each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow.
|
||||
*/
|
||||
const CHARACTER_ENCODINGS: vec![Vec<i32>; 20] = vec![// 0-9
|
||||
0x003, // 0-9
|
||||
0x006, // 0-9
|
||||
0x009, // 0-9
|
||||
0x060, // 0-9
|
||||
0x012, // 0-9
|
||||
0x042, // 0-9
|
||||
0x021, // 0-9
|
||||
0x024, // 0-9
|
||||
0x030, // 0-9
|
||||
0x048, // -$:/.+ABCD
|
||||
0x00c, // -$:/.+ABCD
|
||||
0x018, // -$:/.+ABCD
|
||||
0x045, // -$:/.+ABCD
|
||||
0x051, // -$:/.+ABCD
|
||||
0x054, // -$:/.+ABCD
|
||||
0x015, // -$:/.+ABCD
|
||||
0x01A, // -$:/.+ABCD
|
||||
0x029, // -$:/.+ABCD
|
||||
0x00B, // -$:/.+ABCD
|
||||
0x00E, ]
|
||||
;
|
||||
|
||||
// minimal number of characters that should be present (including start and stop characters)
|
||||
// under normal circumstances this should be set to 3, but can be set higher
|
||||
// as a last-ditch attempt to reduce false positives.
|
||||
const MIN_CHARACTER_LENGTH: i32 = 3;
|
||||
|
||||
// official start and end patterns
|
||||
const STARTEND_ENCODING: vec![Vec<char>; 4] = vec!['A', 'B', 'C', 'D', ]
|
||||
;
|
||||
pub struct CodaBarReader {
|
||||
super: OneDReader;
|
||||
|
||||
// some Codabar generator allow the Codabar string to be closed by every
|
||||
// character. This will cause lots of false positives!
|
||||
// some industries use a checksum standard but this is not part of the original Codabar standard
|
||||
// for more information see : http://www.mecsw.com/specs/codabar.html
|
||||
// Keep some instance variables to avoid reallocations
|
||||
let decode_row_result: StringBuilder;
|
||||
|
||||
let mut counters: Vec<i32>;
|
||||
|
||||
let counter_length: i32;
|
||||
}
|
||||
|
||||
impl CodaBarReader {
|
||||
|
||||
pub fn new() -> CodaBarReader {
|
||||
decode_row_result = StringBuilder::new(20);
|
||||
counters = : [i32; 80] = [0; 80];
|
||||
counter_length = 0;
|
||||
}
|
||||
|
||||
pub fn decode_row(&self, row_number: i32, row: &BitArray, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException */Result<Result, Rc<Exception>> {
|
||||
Arrays::fill(&self.counters, 0);
|
||||
self.set_counters(row);
|
||||
let start_offset: i32 = self.find_start_pattern();
|
||||
let next_start: i32 = start_offset;
|
||||
self.decode_row_result.set_length(0);
|
||||
loop { {
|
||||
let char_offset: i32 = self.to_narrow_wide_pattern(next_start);
|
||||
if char_offset == -1 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// Hack: We store the position in the alphabet table into a
|
||||
// StringBuilder, so that we can access the decoded patterns in
|
||||
// validatePattern. We'll translate to the actual characters later.
|
||||
self.decode_row_result.append(char_offset as char);
|
||||
next_start += 8;
|
||||
// Stop as soon as we see the end character.
|
||||
if self.decode_row_result.length() > 1 && ::array_contains(&STARTEND_ENCODING, ALPHABET[char_offset]) {
|
||||
break;
|
||||
}
|
||||
}if !(// no fixed end pattern so keep on reading while data is available
|
||||
next_start < self.counter_length) break;}
|
||||
// Look for whitespace after pattern:
|
||||
let trailing_whitespace: i32 = self.counters[next_start - 1];
|
||||
let last_pattern_size: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = -8;
|
||||
while i < -1 {
|
||||
{
|
||||
last_pattern_size += self.counters[next_start + i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// at the end of the row. (I.e. the barcode barely fits.)
|
||||
if next_start < self.counter_length && trailing_whitespace < last_pattern_size / 2 {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
self.validate_pattern(start_offset);
|
||||
// Translate character table offsets to actual characters.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < self.decode_row_result.length() {
|
||||
{
|
||||
self.decode_row_result.set_char_at(i, ALPHABET[self.decode_row_result.char_at(i)]);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure a valid start and end character
|
||||
let startchar: char = self.decode_row_result.char_at(0);
|
||||
if !::array_contains(&STARTEND_ENCODING, startchar) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let endchar: char = self.decode_row_result.char_at(self.decode_row_result.length() - 1);
|
||||
if !::array_contains(&STARTEND_ENCODING, endchar) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// remove stop/start characters character and check if a long enough string is contained
|
||||
if self.decode_row_result.length() <= MIN_CHARACTER_LENGTH {
|
||||
// Almost surely a false positive ( start + stop + at least 1 character)
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
if hints == null || !hints.contains_key(DecodeHintType::RETURN_CODABAR_START_END) {
|
||||
self.decode_row_result.delete_char_at(self.decode_row_result.length() - 1);
|
||||
self.decode_row_result.delete_char_at(0);
|
||||
}
|
||||
let running_count: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < start_offset {
|
||||
{
|
||||
running_count += self.counters[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let left: f32 = running_count;
|
||||
{
|
||||
let mut i: i32 = start_offset;
|
||||
while i < next_start - 1 {
|
||||
{
|
||||
running_count += self.counters[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let right: f32 = running_count;
|
||||
let result: Result = Result::new(&self.decode_row_result.to_string(), null, : vec![ResultPoint; 2] = vec![ResultPoint::new(left, row_number), ResultPoint::new(right, row_number), ]
|
||||
, BarcodeFormat::CODABAR);
|
||||
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, "]F0");
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
fn validate_pattern(&self, start: i32) -> /* throws NotFoundException */Result<Void, Rc<Exception>> {
|
||||
// First, sum up the total size of our four categories of stripe sizes;
|
||||
let mut sizes: vec![Vec<i32>; 4] = vec![0, 0, 0, 0, ]
|
||||
;
|
||||
let mut counts: vec![Vec<i32>; 4] = vec![0, 0, 0, 0, ]
|
||||
;
|
||||
let end: i32 = self.decode_row_result.length() - 1;
|
||||
// We break out of this loop in the middle, in order to handle
|
||||
// inter-character spaces properly.
|
||||
let mut pos: i32 = start;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i <= end {
|
||||
{
|
||||
let mut pattern: i32 = CHARACTER_ENCODINGS[self.decode_row_result.char_at(i)];
|
||||
{
|
||||
let mut j: i32 = 6;
|
||||
while j >= 0 {
|
||||
{
|
||||
// Even j = bars, while odd j = spaces. Categories 2 and 3 are for
|
||||
// long stripes, while 0 and 1 are for short stripes.
|
||||
let mut category: i32 = (j & 1) + (pattern & 1) * 2;
|
||||
sizes[category] += self.counters[pos + j];
|
||||
counts[category] += 1;
|
||||
pattern >>= 1;
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// We ignore the inter-character space - it could be of any size.
|
||||
pos += 8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate our allowable size thresholds using fixed-point math.
|
||||
let mut maxes: [f32; 4.0] = [0.0; 4.0];
|
||||
let mut mins: [f32; 4.0] = [0.0; 4.0];
|
||||
// should be on the "wrong" side of that line.
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 2 {
|
||||
{
|
||||
// Accept arbitrarily small "short" stripes.
|
||||
mins[i] = 0.0f;
|
||||
mins[i + 2] = (sizes[i] as f32 / counts[i] + sizes[i + 2] as f32 / counts[i + 2]) / 2.0f;
|
||||
maxes[i] = mins[i + 2];
|
||||
maxes[i + 2] = (sizes[i + 2] * MAX_ACCEPTABLE + PADDING) / counts[i + 2];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now verify that all of the stripes are within the thresholds.
|
||||
pos = start;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i <= end {
|
||||
{
|
||||
let mut pattern: i32 = CHARACTER_ENCODINGS[self.decode_row_result.char_at(i)];
|
||||
{
|
||||
let mut j: i32 = 6;
|
||||
while j >= 0 {
|
||||
{
|
||||
// Even j = bars, while odd j = spaces. Categories 2 and 3 are for
|
||||
// long stripes, while 0 and 1 are for short stripes.
|
||||
let category: i32 = (j & 1) + (pattern & 1) * 2;
|
||||
let size: i32 = self.counters[pos + j];
|
||||
if size < mins[category] || size > maxes[category] {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
pattern >>= 1;
|
||||
}
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pos += 8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the size of all runs of white and black pixels, starting with white.
|
||||
* This is just like recordPattern, except it records all the counters, and
|
||||
* uses our builtin "counters" member for storage.
|
||||
* @param row row to count from
|
||||
*/
|
||||
fn set_counters(&self, row: &BitArray) -> /* throws NotFoundException */Result<Void, Rc<Exception>> {
|
||||
self.counter_length = 0;
|
||||
// Start from the first white bit.
|
||||
let mut i: i32 = row.get_next_unset(0);
|
||||
let end: i32 = row.get_size();
|
||||
if i >= end {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
let is_white: bool = true;
|
||||
let mut count: i32 = 0;
|
||||
while i < end {
|
||||
if row.get(i) != is_white {
|
||||
count += 1;
|
||||
} else {
|
||||
self.counter_append(count);
|
||||
count = 1;
|
||||
is_white = !is_white;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
self.counter_append(count);
|
||||
}
|
||||
|
||||
fn counter_append(&self, e: i32) {
|
||||
self.counters[self.counter_length] = e;
|
||||
self.counter_length += 1;
|
||||
if self.counter_length >= self.counters.len() {
|
||||
let temp: [i32; self.counter_length * 2] = [0; self.counter_length * 2];
|
||||
System::arraycopy(&self.counters, 0, &temp, 0, self.counter_length);
|
||||
self.counters = temp;
|
||||
}
|
||||
}
|
||||
|
||||
fn find_start_pattern(&self) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i < self.counter_length {
|
||||
{
|
||||
let char_offset: i32 = self.to_narrow_wide_pattern(i);
|
||||
if char_offset != -1 && ::array_contains(&STARTEND_ENCODING, ALPHABET[char_offset]) {
|
||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||
// We make an exception if the whitespace is the first element.
|
||||
let pattern_size: i32 = 0;
|
||||
{
|
||||
let mut j: i32 = i;
|
||||
while j < i + 7 {
|
||||
{
|
||||
pattern_size += self.counters[j];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if i == 1 || self.counters[i - 1] >= pattern_size / 2 {
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
|
||||
fn array_contains( array: &Vec<char>, key: char) -> bool {
|
||||
if array != null {
|
||||
for let c: char in array {
|
||||
if c == key {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assumes that counters[position] is a bar.
|
||||
fn to_narrow_wide_pattern(&self, position: i32) -> i32 {
|
||||
let end: i32 = position + 7;
|
||||
if end >= self.counter_length {
|
||||
return -1;
|
||||
}
|
||||
let the_counters: Vec<i32> = self.counters;
|
||||
let max_bar: i32 = 0;
|
||||
let min_bar: i32 = Integer::MAX_VALUE;
|
||||
{
|
||||
let mut j: i32 = position;
|
||||
while j < end {
|
||||
{
|
||||
let current_counter: i32 = the_counters[j];
|
||||
if current_counter < min_bar {
|
||||
min_bar = current_counter;
|
||||
}
|
||||
if current_counter > max_bar {
|
||||
max_bar = current_counter;
|
||||
}
|
||||
}
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
|
||||
let threshold_bar: i32 = (min_bar + max_bar) / 2;
|
||||
let max_space: i32 = 0;
|
||||
let min_space: i32 = Integer::MAX_VALUE;
|
||||
{
|
||||
let mut j: i32 = position + 1;
|
||||
while j < end {
|
||||
{
|
||||
let current_counter: i32 = the_counters[j];
|
||||
if current_counter < min_space {
|
||||
min_space = current_counter;
|
||||
}
|
||||
if current_counter > max_space {
|
||||
max_space = current_counter;
|
||||
}
|
||||
}
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
|
||||
let threshold_space: i32 = (min_space + max_space) / 2;
|
||||
let mut bitmask: i32 = 1 << 7;
|
||||
let mut pattern: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < 7 {
|
||||
{
|
||||
let threshold: i32 = if (i & 1) == 0 { threshold_bar } else { threshold_space };
|
||||
bitmask >>= 1;
|
||||
if the_counters[position + i] > threshold {
|
||||
pattern |= bitmask;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < CHARACTER_ENCODINGS.len() {
|
||||
{
|
||||
if CHARACTER_ENCODINGS[i] == pattern {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,170 +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::oned;
|
||||
|
||||
/**
|
||||
* This class renders CodaBar as {@code boolean[]}.
|
||||
*
|
||||
* @author dsbnatut@gmail.com (Kazuki Nishiura)
|
||||
*/
|
||||
|
||||
const START_END_CHARS: vec![Vec<char>; 4] = vec!['A', 'B', 'C', 'D', ]
|
||||
;
|
||||
|
||||
const ALT_START_END_CHARS: vec![Vec<char>; 4] = vec!['T', 'N', '*', 'E', ]
|
||||
;
|
||||
|
||||
const CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED: vec![Vec<char>; 4] = vec!['/', ':', '+', '.', ]
|
||||
;
|
||||
|
||||
const DEFAULT_GUARD: char = START_END_CHARS[0];
|
||||
pub struct CodaBarWriter {
|
||||
super: OneDimensionalCodeWriter;
|
||||
}
|
||||
|
||||
impl CodaBarWriter {
|
||||
|
||||
pub fn get_supported_write_formats(&self) -> Collection<BarcodeFormat> {
|
||||
return Collections::singleton(BarcodeFormat::CODABAR);
|
||||
}
|
||||
|
||||
pub fn encode(&self, contents: &String) -> Vec<bool> {
|
||||
if contents.length() < 2 {
|
||||
// Can't have a start/end guard, so tentatively add default guards
|
||||
contents = format!("{}{}{}", DEFAULT_GUARD, contents, DEFAULT_GUARD);
|
||||
} else {
|
||||
// Verify input and calculate decoded length.
|
||||
let first_char: char = Character::to_upper_case(&contents.char_at(0));
|
||||
let last_char: char = Character::to_upper_case(&contents.char_at(contents.length() - 1));
|
||||
let starts_normal: bool = CodaBarReader::array_contains(&START_END_CHARS, first_char);
|
||||
let ends_normal: bool = CodaBarReader::array_contains(&START_END_CHARS, last_char);
|
||||
let starts_alt: bool = CodaBarReader::array_contains(&ALT_START_END_CHARS, first_char);
|
||||
let ends_alt: bool = CodaBarReader::array_contains(&ALT_START_END_CHARS, last_char);
|
||||
if starts_normal {
|
||||
if !ends_normal {
|
||||
throw IllegalArgumentException::new(format!("Invalid start/end guards: {}", contents));
|
||||
}
|
||||
// else already has valid start/end
|
||||
} else if starts_alt {
|
||||
if !ends_alt {
|
||||
throw IllegalArgumentException::new(format!("Invalid start/end guards: {}", contents));
|
||||
}
|
||||
// else already has valid start/end
|
||||
} else {
|
||||
// Doesn't start with a guard
|
||||
if ends_normal || ends_alt {
|
||||
throw IllegalArgumentException::new(format!("Invalid start/end guards: {}", contents));
|
||||
}
|
||||
// else doesn't end with guard either, so add a default
|
||||
contents = format!("{}{}{}", DEFAULT_GUARD, contents, DEFAULT_GUARD);
|
||||
}
|
||||
}
|
||||
// The start character and the end character are decoded to 10 length each.
|
||||
let result_length: i32 = 20;
|
||||
{
|
||||
let mut i: i32 = 1;
|
||||
while i < contents.length() - 1 {
|
||||
{
|
||||
if Character::is_digit(&contents.char_at(i)) || contents.char_at(i) == '-' || contents.char_at(i) == '$' {
|
||||
result_length += 9;
|
||||
} else if CodaBarReader::array_contains(&CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED, &contents.char_at(i)) {
|
||||
result_length += 10;
|
||||
} else {
|
||||
throw IllegalArgumentException::new(format!("Cannot encode : '{}\'", contents.char_at(i)));
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// A blank is placed between each character.
|
||||
result_length += contents.length() - 1;
|
||||
let mut result: [bool; result_length] = [false; result_length];
|
||||
let mut position: i32 = 0;
|
||||
{
|
||||
let mut index: i32 = 0;
|
||||
while index < contents.length() {
|
||||
{
|
||||
let mut c: char = Character::to_upper_case(&contents.char_at(index));
|
||||
if index == 0 || index == contents.length() - 1 {
|
||||
// The start/end chars are not in the CodaBarReader.ALPHABET.
|
||||
match c {
|
||||
'T' =>
|
||||
{
|
||||
c = 'A';
|
||||
break;
|
||||
}
|
||||
'N' =>
|
||||
{
|
||||
c = 'B';
|
||||
break;
|
||||
}
|
||||
'*' =>
|
||||
{
|
||||
c = 'C';
|
||||
break;
|
||||
}
|
||||
'E' =>
|
||||
{
|
||||
c = 'D';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut code: i32 = 0;
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < CodaBarReader::ALPHABET::len() {
|
||||
{
|
||||
// Found any, because I checked above.
|
||||
if c == CodaBarReader::ALPHABET[i] {
|
||||
code = CodaBarReader::CHARACTER_ENCODINGS[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut color: bool = true;
|
||||
let mut counter: i32 = 0;
|
||||
let mut bit: i32 = 0;
|
||||
while bit < 7 {
|
||||
// A character consists of 7 digit.
|
||||
result[position] = color;
|
||||
position += 1;
|
||||
if ((code >> (6 - bit)) & 1) == 0 || counter == 1 {
|
||||
// Flip the color.
|
||||
color = !color;
|
||||
bit += 1;
|
||||
counter = 0;
|
||||
} else {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
if index < contents.length() - 1 {
|
||||
result[position] = false;
|
||||
position += 1;
|
||||
}
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,630 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::oned;
|
||||
|
||||
/**
|
||||
* <p>Decodes Code 128 barcodes.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const CODE_PATTERNS: vec![vec![Vec<Vec<i32>>; 7]; 107] = vec![// 0
|
||||
vec![2, 1, 2, 2, 2, 2, ]
|
||||
, vec![2, 2, 2, 1, 2, 2, ]
|
||||
, vec![2, 2, 2, 2, 2, 1, ]
|
||||
, vec![1, 2, 1, 2, 2, 3, ]
|
||||
, vec![1, 2, 1, 3, 2, 2, ]
|
||||
, // 5
|
||||
vec![1, 3, 1, 2, 2, 2, ]
|
||||
, vec![1, 2, 2, 2, 1, 3, ]
|
||||
, vec![1, 2, 2, 3, 1, 2, ]
|
||||
, vec![1, 3, 2, 2, 1, 2, ]
|
||||
, vec![2, 2, 1, 2, 1, 3, ]
|
||||
, // 10
|
||||
vec![2, 2, 1, 3, 1, 2, ]
|
||||
, vec![2, 3, 1, 2, 1, 2, ]
|
||||
, vec![1, 1, 2, 2, 3, 2, ]
|
||||
, vec![1, 2, 2, 1, 3, 2, ]
|
||||
, vec![1, 2, 2, 2, 3, 1, ]
|
||||
, // 15
|
||||
vec![1, 1, 3, 2, 2, 2, ]
|
||||
, vec![1, 2, 3, 1, 2, 2, ]
|
||||
, vec![1, 2, 3, 2, 2, 1, ]
|
||||
, vec![2, 2, 3, 2, 1, 1, ]
|
||||
, vec![2, 2, 1, 1, 3, 2, ]
|
||||
, // 20
|
||||
vec![2, 2, 1, 2, 3, 1, ]
|
||||
, vec![2, 1, 3, 2, 1, 2, ]
|
||||
, vec![2, 2, 3, 1, 1, 2, ]
|
||||
, vec![3, 1, 2, 1, 3, 1, ]
|
||||
, vec![3, 1, 1, 2, 2, 2, ]
|
||||
, // 25
|
||||
vec![3, 2, 1, 1, 2, 2, ]
|
||||
, vec![3, 2, 1, 2, 2, 1, ]
|
||||
, vec![3, 1, 2, 2, 1, 2, ]
|
||||
, vec![3, 2, 2, 1, 1, 2, ]
|
||||
, vec![3, 2, 2, 2, 1, 1, ]
|
||||
, // 30
|
||||
vec![2, 1, 2, 1, 2, 3, ]
|
||||
, vec![2, 1, 2, 3, 2, 1, ]
|
||||
, vec![2, 3, 2, 1, 2, 1, ]
|
||||
, vec![1, 1, 1, 3, 2, 3, ]
|
||||
, vec![1, 3, 1, 1, 2, 3, ]
|
||||
, // 35
|
||||
vec![1, 3, 1, 3, 2, 1, ]
|
||||
, vec![1, 1, 2, 3, 1, 3, ]
|
||||
, vec![1, 3, 2, 1, 1, 3, ]
|
||||
, vec![1, 3, 2, 3, 1, 1, ]
|
||||
, vec![2, 1, 1, 3, 1, 3, ]
|
||||
, // 40
|
||||
vec![2, 3, 1, 1, 1, 3, ]
|
||||
, vec![2, 3, 1, 3, 1, 1, ]
|
||||
, vec![1, 1, 2, 1, 3, 3, ]
|
||||
, vec![1, 1, 2, 3, 3, 1, ]
|
||||
, vec![1, 3, 2, 1, 3, 1, ]
|
||||
, // 45
|
||||
vec![1, 1, 3, 1, 2, 3, ]
|
||||
, vec![1, 1, 3, 3, 2, 1, ]
|
||||
, vec![1, 3, 3, 1, 2, 1, ]
|
||||
, vec![3, 1, 3, 1, 2, 1, ]
|
||||
, vec![2, 1, 1, 3, 3, 1, ]
|
||||
, // 50
|
||||
vec![2, 3, 1, 1, 3, 1, ]
|
||||
, vec![2, 1, 3, 1, 1, 3, ]
|
||||
, vec![2, 1, 3, 3, 1, 1, ]
|
||||
, vec![2, 1, 3, 1, 3, 1, ]
|
||||
, vec![3, 1, 1, 1, 2, 3, ]
|
||||
, // 55
|
||||
vec![3, 1, 1, 3, 2, 1, ]
|
||||
, vec![3, 3, 1, 1, 2, 1, ]
|
||||
, vec![3, 1, 2, 1, 1, 3, ]
|
||||
, vec![3, 1, 2, 3, 1, 1, ]
|
||||
, vec![3, 3, 2, 1, 1, 1, ]
|
||||
, // 60
|
||||
vec![3, 1, 4, 1, 1, 1, ]
|
||||
, vec![2, 2, 1, 4, 1, 1, ]
|
||||
, vec![4, 3, 1, 1, 1, 1, ]
|
||||
, vec![1, 1, 1, 2, 2, 4, ]
|
||||
, vec![1, 1, 1, 4, 2, 2, ]
|
||||
, // 65
|
||||
vec![1, 2, 1, 1, 2, 4, ]
|
||||
, vec![1, 2, 1, 4, 2, 1, ]
|
||||
, vec![1, 4, 1, 1, 2, 2, ]
|
||||
, vec![1, 4, 1, 2, 2, 1, ]
|
||||
, vec![1, 1, 2, 2, 1, 4, ]
|
||||
, // 70
|
||||
vec![1, 1, 2, 4, 1, 2, ]
|
||||
, vec![1, 2, 2, 1, 1, 4, ]
|
||||
, vec![1, 2, 2, 4, 1, 1, ]
|
||||
, vec![1, 4, 2, 1, 1, 2, ]
|
||||
, vec![1, 4, 2, 2, 1, 1, ]
|
||||
, // 75
|
||||
vec![2, 4, 1, 2, 1, 1, ]
|
||||
, vec![2, 2, 1, 1, 1, 4, ]
|
||||
, vec![4, 1, 3, 1, 1, 1, ]
|
||||
, vec![2, 4, 1, 1, 1, 2, ]
|
||||
, vec![1, 3, 4, 1, 1, 1, ]
|
||||
, // 80
|
||||
vec![1, 1, 1, 2, 4, 2, ]
|
||||
, vec![1, 2, 1, 1, 4, 2, ]
|
||||
, vec![1, 2, 1, 2, 4, 1, ]
|
||||
, vec![1, 1, 4, 2, 1, 2, ]
|
||||
, vec![1, 2, 4, 1, 1, 2, ]
|
||||
, // 85
|
||||
vec![1, 2, 4, 2, 1, 1, ]
|
||||
, vec![4, 1, 1, 2, 1, 2, ]
|
||||
, vec![4, 2, 1, 1, 1, 2, ]
|
||||
, vec![4, 2, 1, 2, 1, 1, ]
|
||||
, vec![2, 1, 2, 1, 4, 1, ]
|
||||
, // 90
|
||||
vec![2, 1, 4, 1, 2, 1, ]
|
||||
, vec![4, 1, 2, 1, 2, 1, ]
|
||||
, vec![1, 1, 1, 1, 4, 3, ]
|
||||
, vec![1, 1, 1, 3, 4, 1, ]
|
||||
, vec![1, 3, 1, 1, 4, 1, ]
|
||||
, // 95
|
||||
vec![1, 1, 4, 1, 1, 3, ]
|
||||
, vec![1, 1, 4, 3, 1, 1, ]
|
||||
, vec![4, 1, 1, 1, 1, 3, ]
|
||||
, vec![4, 1, 1, 3, 1, 1, ]
|
||||
, vec![1, 1, 3, 1, 4, 1, ]
|
||||
, // 100
|
||||
vec![1, 1, 4, 1, 3, 1, ]
|
||||
, vec![3, 1, 1, 1, 4, 1, ]
|
||||
, vec![4, 1, 1, 1, 3, 1, ]
|
||||
, vec![2, 1, 1, 4, 1, 2, ]
|
||||
, vec![2, 1, 1, 2, 1, 4, ]
|
||||
, // 105
|
||||
vec![2, 1, 1, 2, 3, 2, ]
|
||||
, vec![2, 3, 3, 1, 1, 1, 2, ]
|
||||
, ]
|
||||
;
|
||||
|
||||
const MAX_AVG_VARIANCE: f32 = 0.25f;
|
||||
|
||||
const MAX_INDIVIDUAL_VARIANCE: f32 = 0.7f;
|
||||
|
||||
const CODE_SHIFT: i32 = 98;
|
||||
|
||||
const CODE_CODE_C: i32 = 99;
|
||||
|
||||
const CODE_CODE_B: i32 = 100;
|
||||
|
||||
const CODE_CODE_A: i32 = 101;
|
||||
|
||||
const CODE_FNC_1: i32 = 102;
|
||||
|
||||
const CODE_FNC_2: i32 = 97;
|
||||
|
||||
const CODE_FNC_3: i32 = 96;
|
||||
|
||||
const CODE_FNC_4_A: i32 = 101;
|
||||
|
||||
const CODE_FNC_4_B: i32 = 100;
|
||||
|
||||
const CODE_START_A: i32 = 103;
|
||||
|
||||
const CODE_START_B: i32 = 104;
|
||||
|
||||
const CODE_START_C: i32 = 105;
|
||||
|
||||
const CODE_STOP: i32 = 106;
|
||||
pub struct Code128Reader {
|
||||
super: OneDReader;
|
||||
}
|
||||
|
||||
impl Code128Reader {
|
||||
|
||||
fn find_start_pattern( row: &BitArray) -> /* throws NotFoundException */Result<Vec<i32>, Rc<Exception>> {
|
||||
let width: i32 = row.get_size();
|
||||
let row_offset: i32 = row.get_next_set(0);
|
||||
let counter_position: i32 = 0;
|
||||
let mut counters: [i32; 6] = [0; 6];
|
||||
let pattern_start: i32 = row_offset;
|
||||
let is_white: bool = false;
|
||||
let pattern_length: i32 = counters.len();
|
||||
{
|
||||
let mut i: i32 = row_offset;
|
||||
while i < width {
|
||||
{
|
||||
if row.get(i) != is_white {
|
||||
counters[counter_position] += 1;
|
||||
} else {
|
||||
if counter_position == pattern_length - 1 {
|
||||
let best_variance: f32 = MAX_AVG_VARIANCE;
|
||||
let best_match: i32 = -1;
|
||||
{
|
||||
let start_code: i32 = CODE_START_A;
|
||||
while start_code <= CODE_START_C {
|
||||
{
|
||||
let variance: f32 = pattern_match_variance(&counters, CODE_PATTERNS[start_code], MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < best_variance {
|
||||
best_variance = variance;
|
||||
best_match = start_code;
|
||||
}
|
||||
}
|
||||
start_code += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||
if best_match >= 0 && row.is_range(&Math::max(0, pattern_start - (i - pattern_start) / 2), pattern_start, false) {
|
||||
return Ok( : vec![i32; 3] = vec![pattern_start, i, best_match, ]
|
||||
);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
|
||||
fn decode_code( row: &BitArray, counters: &Vec<i32>, row_offset: i32) -> /* throws NotFoundException */Result<i32, Rc<Exception>> {
|
||||
record_pattern(row, row_offset, &counters);
|
||||
// worst variance we'll accept
|
||||
let best_variance: f32 = MAX_AVG_VARIANCE;
|
||||
let best_match: i32 = -1;
|
||||
{
|
||||
let mut d: i32 = 0;
|
||||
while d < CODE_PATTERNS.len() {
|
||||
{
|
||||
let pattern: Vec<i32> = CODE_PATTERNS[d];
|
||||
let variance: f32 = pattern_match_variance(&counters, &pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if variance < best_variance {
|
||||
best_variance = variance;
|
||||
best_match = d;
|
||||
}
|
||||
}
|
||||
d += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO We're overlooking the fact that the STOP pattern has 7 values, not 6.
|
||||
if best_match >= 0 {
|
||||
return Ok(best_match);
|
||||
} else {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_row(&self, row_number: i32, row: &BitArray, hints: &Map<DecodeHintType, ?>) -> /* throws NotFoundException, FormatException, ChecksumException */Result<Result, Rc<Exception>> {
|
||||
let convert_f_n_c1: bool = hints != null && hints.contains_key(DecodeHintType::ASSUME_GS1);
|
||||
let symbology_modifier: i32 = 0;
|
||||
let start_pattern_info: Vec<i32> = ::find_start_pattern(row);
|
||||
let start_code: i32 = start_pattern_info[2];
|
||||
let raw_codes: List<Byte> = ArrayList<>::new(20);
|
||||
raw_codes.add(start_code as i8);
|
||||
let code_set: i32;
|
||||
match start_code {
|
||||
CODE_START_A =>
|
||||
{
|
||||
code_set = CODE_CODE_A;
|
||||
break;
|
||||
}
|
||||
CODE_START_B =>
|
||||
{
|
||||
code_set = CODE_CODE_B;
|
||||
break;
|
||||
}
|
||||
CODE_START_C =>
|
||||
{
|
||||
code_set = CODE_CODE_C;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
let mut done: bool = false;
|
||||
let is_next_shifted: bool = false;
|
||||
let result: StringBuilder = StringBuilder::new(20);
|
||||
let last_start: i32 = start_pattern_info[0];
|
||||
let next_start: i32 = start_pattern_info[1];
|
||||
let counters: [i32; 6] = [0; 6];
|
||||
let last_code: i32 = 0;
|
||||
let mut code: i32 = 0;
|
||||
let checksum_total: i32 = start_code;
|
||||
let mut multiplier: i32 = 0;
|
||||
let last_character_was_printable: bool = true;
|
||||
let upper_mode: bool = false;
|
||||
let shift_upper_mode: bool = false;
|
||||
while !done {
|
||||
let unshift: bool = is_next_shifted;
|
||||
is_next_shifted = false;
|
||||
// Save off last code
|
||||
last_code = code;
|
||||
// Decode another code from image
|
||||
code = ::decode_code(row, &counters, next_start);
|
||||
raw_codes.add(code as i8);
|
||||
// Remember whether the last code was printable or not (excluding CODE_STOP)
|
||||
if code != CODE_STOP {
|
||||
last_character_was_printable = true;
|
||||
}
|
||||
// Add to checksum computation (if not CODE_STOP of course)
|
||||
if code != CODE_STOP {
|
||||
multiplier += 1;
|
||||
checksum_total += multiplier * code;
|
||||
}
|
||||
// Advance to where the next code will to start
|
||||
last_start = next_start;
|
||||
for let counter: i32 in counters {
|
||||
next_start += counter;
|
||||
}
|
||||
// Take care of illegal start codes
|
||||
match code {
|
||||
CODE_START_A =>
|
||||
{
|
||||
}
|
||||
CODE_START_B =>
|
||||
{
|
||||
}
|
||||
CODE_START_C =>
|
||||
{
|
||||
throw FormatException::get_format_instance();
|
||||
}
|
||||
}
|
||||
match code_set {
|
||||
CODE_CODE_A =>
|
||||
{
|
||||
if code < 64 {
|
||||
if shift_upper_mode == upper_mode {
|
||||
result.append((' ' + code) as char);
|
||||
} else {
|
||||
result.append((' ' + code + 128) as char);
|
||||
}
|
||||
shift_upper_mode = false;
|
||||
} else if code < 96 {
|
||||
if shift_upper_mode == upper_mode {
|
||||
result.append((code - 64) as char);
|
||||
} else {
|
||||
result.append((code + 64) as char);
|
||||
}
|
||||
shift_upper_mode = false;
|
||||
} else {
|
||||
// code was printable or not.
|
||||
if code != CODE_STOP {
|
||||
last_character_was_printable = false;
|
||||
}
|
||||
match code {
|
||||
CODE_FNC_1 =>
|
||||
{
|
||||
if result.length() == 0 {
|
||||
// FNC1 at first or second character determines the symbology
|
||||
symbology_modifier = 1;
|
||||
} else if result.length() == 1 {
|
||||
symbology_modifier = 2;
|
||||
}
|
||||
if convert_f_n_c1 {
|
||||
if result.length() == 0 {
|
||||
// GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code
|
||||
// is FNC1 then this is GS1-128. We add the symbology identifier.
|
||||
result.append("]C1");
|
||||
} else {
|
||||
// GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS)
|
||||
result.append(29 as char);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_FNC_2 =>
|
||||
{
|
||||
symbology_modifier = 4;
|
||||
break;
|
||||
}
|
||||
CODE_FNC_3 =>
|
||||
{
|
||||
// do nothing?
|
||||
break;
|
||||
}
|
||||
CODE_FNC_4_A =>
|
||||
{
|
||||
if !upper_mode && shift_upper_mode {
|
||||
upper_mode = true;
|
||||
shift_upper_mode = false;
|
||||
} else if upper_mode && shift_upper_mode {
|
||||
upper_mode = false;
|
||||
shift_upper_mode = false;
|
||||
} else {
|
||||
shift_upper_mode = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_SHIFT =>
|
||||
{
|
||||
is_next_shifted = true;
|
||||
code_set = CODE_CODE_B;
|
||||
break;
|
||||
}
|
||||
CODE_CODE_B =>
|
||||
{
|
||||
code_set = CODE_CODE_B;
|
||||
break;
|
||||
}
|
||||
CODE_CODE_C =>
|
||||
{
|
||||
code_set = CODE_CODE_C;
|
||||
break;
|
||||
}
|
||||
CODE_STOP =>
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_CODE_B =>
|
||||
{
|
||||
if code < 96 {
|
||||
if shift_upper_mode == upper_mode {
|
||||
result.append((' ' + code) as char);
|
||||
} else {
|
||||
result.append((' ' + code + 128) as char);
|
||||
}
|
||||
shift_upper_mode = false;
|
||||
} else {
|
||||
if code != CODE_STOP {
|
||||
last_character_was_printable = false;
|
||||
}
|
||||
match code {
|
||||
CODE_FNC_1 =>
|
||||
{
|
||||
if result.length() == 0 {
|
||||
// FNC1 at first or second character determines the symbology
|
||||
symbology_modifier = 1;
|
||||
} else if result.length() == 1 {
|
||||
symbology_modifier = 2;
|
||||
}
|
||||
if convert_f_n_c1 {
|
||||
if result.length() == 0 {
|
||||
// GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code
|
||||
// is FNC1 then this is GS1-128. We add the symbology identifier.
|
||||
result.append("]C1");
|
||||
} else {
|
||||
// GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS)
|
||||
result.append(29 as char);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_FNC_2 =>
|
||||
{
|
||||
symbology_modifier = 4;
|
||||
break;
|
||||
}
|
||||
CODE_FNC_3 =>
|
||||
{
|
||||
// do nothing?
|
||||
break;
|
||||
}
|
||||
CODE_FNC_4_B =>
|
||||
{
|
||||
if !upper_mode && shift_upper_mode {
|
||||
upper_mode = true;
|
||||
shift_upper_mode = false;
|
||||
} else if upper_mode && shift_upper_mode {
|
||||
upper_mode = false;
|
||||
shift_upper_mode = false;
|
||||
} else {
|
||||
shift_upper_mode = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_SHIFT =>
|
||||
{
|
||||
is_next_shifted = true;
|
||||
code_set = CODE_CODE_A;
|
||||
break;
|
||||
}
|
||||
CODE_CODE_A =>
|
||||
{
|
||||
code_set = CODE_CODE_A;
|
||||
break;
|
||||
}
|
||||
CODE_CODE_C =>
|
||||
{
|
||||
code_set = CODE_CODE_C;
|
||||
break;
|
||||
}
|
||||
CODE_STOP =>
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_CODE_C =>
|
||||
{
|
||||
if code < 100 {
|
||||
if code < 10 {
|
||||
result.append('0');
|
||||
}
|
||||
result.append(code);
|
||||
} else {
|
||||
if code != CODE_STOP {
|
||||
last_character_was_printable = false;
|
||||
}
|
||||
match code {
|
||||
CODE_FNC_1 =>
|
||||
{
|
||||
if result.length() == 0 {
|
||||
// FNC1 at first or second character determines the symbology
|
||||
symbology_modifier = 1;
|
||||
} else if result.length() == 1 {
|
||||
symbology_modifier = 2;
|
||||
}
|
||||
if convert_f_n_c1 {
|
||||
if result.length() == 0 {
|
||||
// GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code
|
||||
// is FNC1 then this is GS1-128. We add the symbology identifier.
|
||||
result.append("]C1");
|
||||
} else {
|
||||
// GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS)
|
||||
result.append(29 as char);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_CODE_A =>
|
||||
{
|
||||
code_set = CODE_CODE_A;
|
||||
break;
|
||||
}
|
||||
CODE_CODE_B =>
|
||||
{
|
||||
code_set = CODE_CODE_B;
|
||||
break;
|
||||
}
|
||||
CODE_STOP =>
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Unshift back to another code set if we were shifted
|
||||
if unshift {
|
||||
code_set = if code_set == CODE_CODE_A { CODE_CODE_B } else { CODE_CODE_A };
|
||||
}
|
||||
}
|
||||
let last_pattern_size: i32 = next_start - last_start;
|
||||
// Check for ample whitespace following pattern, but, to do this we first need to remember that
|
||||
// we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left
|
||||
// to read off. Would be slightly better to properly read. Here we just skip it:
|
||||
next_start = row.get_next_unset(next_start);
|
||||
if !row.is_range(next_start, &Math::min(&row.get_size(), next_start + (next_start - last_start) / 2), false) {
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// Pull out from sum the value of the penultimate check code
|
||||
checksum_total -= multiplier * last_code;
|
||||
// lastCode is the checksum then:
|
||||
if checksum_total % 103 != last_code {
|
||||
throw ChecksumException::get_checksum_instance();
|
||||
}
|
||||
// Need to pull out the check digits from string
|
||||
let result_length: i32 = result.length();
|
||||
if result_length == 0 {
|
||||
// false positive
|
||||
throw NotFoundException::get_not_found_instance();
|
||||
}
|
||||
// be a printable character. If it was just interpreted as a control code, nothing to remove.
|
||||
if result_length > 0 && last_character_was_printable {
|
||||
if code_set == CODE_CODE_C {
|
||||
result.delete(result_length - 2, result_length);
|
||||
} else {
|
||||
result.delete(result_length - 1, result_length);
|
||||
}
|
||||
}
|
||||
let left: f32 = (start_pattern_info[1] + start_pattern_info[0]) / 2.0f;
|
||||
let right: f32 = last_start + last_pattern_size / 2.0f;
|
||||
let raw_codes_size: i32 = raw_codes.size();
|
||||
let raw_bytes: [i8; raw_codes_size] = [0; raw_codes_size];
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < raw_codes_size {
|
||||
{
|
||||
raw_bytes[i] = raw_codes.get(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let result_object: Result = Result::new(&result.to_string(), &raw_bytes, : vec![ResultPoint; 2] = vec![ResultPoint::new(left, row_number), ResultPoint::new(right, row_number), ]
|
||||
, BarcodeFormat::CODE_128);
|
||||
result_object.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]C{}", symbology_modifier));
|
||||
return Ok(result_object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,661 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// package com::google::zxing::oned;
|
||||
|
||||
/**
|
||||
* This object renders a CODE128 code as a {@link BitMatrix}.
|
||||
*
|
||||
* @author erik.barbara@gmail.com (Erik Barbara)
|
||||
*/
|
||||
|
||||
const CODE_START_A: i32 = 103;
|
||||
|
||||
const CODE_START_B: i32 = 104;
|
||||
|
||||
const CODE_START_C: i32 = 105;
|
||||
|
||||
const CODE_CODE_A: i32 = 101;
|
||||
|
||||
const CODE_CODE_B: i32 = 100;
|
||||
|
||||
const CODE_CODE_C: i32 = 99;
|
||||
|
||||
const CODE_STOP: i32 = 106;
|
||||
|
||||
// Dummy characters used to specify control characters in input
|
||||
const ESCAPE_FNC_1: char = 'ñ';
|
||||
|
||||
const ESCAPE_FNC_2: char = 'ò';
|
||||
|
||||
const ESCAPE_FNC_3: char = 'ó';
|
||||
|
||||
const ESCAPE_FNC_4: char = 'ô';
|
||||
|
||||
// Code A, Code B, Code C
|
||||
const CODE_FNC_1: i32 = 102;
|
||||
|
||||
// Code A, Code B
|
||||
const CODE_FNC_2: i32 = 97;
|
||||
|
||||
// Code A, Code B
|
||||
const CODE_FNC_3: i32 = 96;
|
||||
|
||||
// Code A
|
||||
const CODE_FNC_4_A: i32 = 101;
|
||||
|
||||
// Code B
|
||||
const CODE_FNC_4_B: i32 = 100;
|
||||
pub struct Code128Writer {
|
||||
super: OneDimensionalCodeWriter;
|
||||
}
|
||||
|
||||
impl Code128Writer {
|
||||
|
||||
// Results of minimal lookahead for code C
|
||||
enum CType {
|
||||
|
||||
UNCODABLE(), ONE_DIGIT(), TWO_DIGITS(), FNC_1()
|
||||
}
|
||||
|
||||
pub fn get_supported_write_formats(&self) -> Collection<BarcodeFormat> {
|
||||
return Collections::singleton(BarcodeFormat::CODE_128);
|
||||
}
|
||||
|
||||
pub fn encode(&self, contents: &String) -> Vec<bool> {
|
||||
return self.encode(&contents, null);
|
||||
}
|
||||
|
||||
pub fn encode(&self, contents: &String, hints: &Map<EncodeHintType, ?>) -> Vec<bool> {
|
||||
let forced_code_set: i32 = ::check(&contents, &hints);
|
||||
let has_compaction_hint: bool = hints != null && hints.contains_key(EncodeHintType::CODE128_COMPACT) && Boolean::parse_boolean(&hints.get(EncodeHintType::CODE128_COMPACT).to_string());
|
||||
return if has_compaction_hint { MinimalEncoder::new().encode(&contents) } else { ::encode_fast(&contents, forced_code_set) };
|
||||
}
|
||||
|
||||
fn check( contents: &String, hints: &Map<EncodeHintType, ?>) -> i32 {
|
||||
let length: i32 = contents.length();
|
||||
// Check length
|
||||
if length < 1 || length > 80 {
|
||||
throw IllegalArgumentException::new(format!("Contents length should be between 1 and 80 characters, but got {}", length));
|
||||
}
|
||||
// Check for forced code set hint.
|
||||
let forced_code_set: i32 = -1;
|
||||
if hints != null && hints.contains_key(EncodeHintType::FORCE_CODE_SET) {
|
||||
let code_set_hint: String = hints.get(EncodeHintType::FORCE_CODE_SET).to_string();
|
||||
match code_set_hint {
|
||||
"A" =>
|
||||
{
|
||||
forced_code_set = CODE_CODE_A;
|
||||
break;
|
||||
}
|
||||
"B" =>
|
||||
{
|
||||
forced_code_set = CODE_CODE_B;
|
||||
break;
|
||||
}
|
||||
"C" =>
|
||||
{
|
||||
forced_code_set = CODE_CODE_C;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
throw IllegalArgumentException::new(format!("Unsupported code set hint: {}", code_set_hint));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check content
|
||||
{
|
||||
let mut i: i32 = 0;
|
||||
while i < length {
|
||||
{
|
||||
let c: char = contents.char_at(i);
|
||||
// check for non ascii characters that are not special GS1 characters
|
||||
match c {
|
||||
// special function characters
|
||||
ESCAPE_FNC_1 =>
|
||||
{
|
||||
}
|
||||
ESCAPE_FNC_2 =>
|
||||
{
|
||||
}
|
||||
ESCAPE_FNC_3 =>
|
||||
{
|
||||
}
|
||||
ESCAPE_FNC_4 =>
|
||||
{
|
||||
break;
|
||||
}
|
||||
// non ascii characters
|
||||
_ =>
|
||||
{
|
||||
if c > 127 {
|
||||
// shift and manual code change are not supported
|
||||
throw IllegalArgumentException::new(format!("Bad character in input: ASCII value={}", c as i32));
|
||||
}
|
||||
}
|
||||
}
|
||||
// check characters for compatibility with forced code set
|
||||
match forced_code_set {
|
||||
CODE_CODE_A =>
|
||||
{
|
||||
// allows no ascii above 95 (no lower caps, no special symbols)
|
||||
if c > 95 && c <= 127 {
|
||||
throw IllegalArgumentException::new(format!("Bad character in input for forced code set A: ASCII value={}", c as i32));
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_CODE_B =>
|
||||
{
|
||||
// allows no ascii below 32 (terminal symbols)
|
||||
if c <= 32 {
|
||||
throw IllegalArgumentException::new(format!("Bad character in input for forced code set B: ASCII value={}", c as i32));
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_CODE_C =>
|
||||
{
|
||||
// allows only numbers and no FNC 2/3/4
|
||||
if c < 48 || (c > 57 && c <= 127) || c == ESCAPE_FNC_2 || c == ESCAPE_FNC_3 || c == ESCAPE_FNC_4 {
|
||||
throw IllegalArgumentException::new(format!("Bad character in input for forced code set C: ASCII value={}", c as i32));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return forced_code_set;
|
||||
}
|
||||
|
||||
fn encode_fast( contents: &String, forced_code_set: i32) -> Vec<bool> {
|
||||
let length: i32 = contents.length();
|
||||
// temporary storage for patterns
|
||||
let patterns: Collection<Vec<i32>> = ArrayList<>::new();
|
||||
let check_sum: i32 = 0;
|
||||
let check_weight: i32 = 1;
|
||||
// selected code (CODE_CODE_B or CODE_CODE_C)
|
||||
let code_set: i32 = 0;
|
||||
// position in contents
|
||||
let mut position: i32 = 0;
|
||||
while position < length {
|
||||
//Select code to use
|
||||
let new_code_set: i32;
|
||||
if forced_code_set == -1 {
|
||||
new_code_set = ::choose_code(&contents, position, code_set);
|
||||
} else {
|
||||
new_code_set = forced_code_set;
|
||||
}
|
||||
//Get the pattern index
|
||||
let pattern_index: i32;
|
||||
if new_code_set == code_set {
|
||||
// First handle escapes
|
||||
match contents.char_at(position) {
|
||||
ESCAPE_FNC_1 =>
|
||||
{
|
||||
pattern_index = CODE_FNC_1;
|
||||
break;
|
||||
}
|
||||
ESCAPE_FNC_2 =>
|
||||
{
|
||||
pattern_index = CODE_FNC_2;
|
||||
break;
|
||||
}
|
||||
ESCAPE_FNC_3 =>
|
||||
{
|
||||
pattern_index = CODE_FNC_3;
|
||||
break;
|
||||
}
|
||||
ESCAPE_FNC_4 =>
|
||||
{
|
||||
if code_set == CODE_CODE_A {
|
||||
pattern_index = CODE_FNC_4_A;
|
||||
} else {
|
||||
pattern_index = CODE_FNC_4_B;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// Then handle normal characters otherwise
|
||||
match code_set {
|
||||
CODE_CODE_A =>
|
||||
{
|
||||
pattern_index = contents.char_at(position) - ' ';
|
||||
if pattern_index < 0 {
|
||||
// everything below a space character comes behind the underscore in the code patterns table
|
||||
pattern_index += '`';
|
||||
}
|
||||
break;
|
||||
}
|
||||
CODE_CODE_B =>
|
||||
{
|
||||
pattern_index = contents.char_at(position) - ' ';
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
// CODE_CODE_C
|
||||
if position + 1 == length {
|
||||
// this is the last character, but the encoding is C, which always encodes two characers
|
||||
throw IllegalArgumentException::new("Bad number of characters for digit only encoding.");
|
||||
}
|
||||
pattern_index = Integer::parse_int(&contents.substring(position, position + 2));
|
||||
// Also incremented below
|
||||
position += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
position += 1;
|
||||
} else {
|
||||
// Do we have a code set?
|
||||
if code_set == 0 {
|
||||
// No, we don't have a code set
|
||||
match new_code_set {
|
||||
CODE_CODE_A =>
|
||||
{
|
||||
pattern_index = CODE_START_A;
|
||||
break;
|
||||
}
|
||||
CODE_CODE_B =>
|
||||
{
|
||||
pattern_index = CODE_START_B;
|
||||
break;
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
pattern_index = CODE_START_C;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Yes, we have a code set
|
||||
pattern_index = new_code_set;
|
||||
}
|
||||
code_set = new_code_set;
|
||||
}
|
||||
// Get the pattern
|
||||
patterns.add(Code128Reader::CODE_PATTERNS[pattern_index]);
|
||||
// Compute checksum
|
||||
check_sum += pattern_index * check_weight;
|
||||
if position != 0 {
|
||||
check_weight += 1;
|
||||
}
|
||||
}
|
||||
return ::produce_result(&patterns, check_sum);
|
||||
}
|
||||
|
||||
fn produce_result( patterns: &Collection<Vec<i32>>, check_sum: i32) -> Vec<bool> {
|
||||
// Compute and append checksum
|
||||
check_sum %= 103;
|
||||
patterns.add(Code128Reader::CODE_PATTERNS[check_sum]);
|
||||
// Append stop code
|
||||
patterns.add(Code128Reader::CODE_PATTERNS[CODE_STOP]);
|
||||
// Compute code width
|
||||
let code_width: i32 = 0;
|
||||
for let pattern: Vec<i32> in patterns {
|
||||
for let width: i32 in pattern {
|
||||
code_width += width;
|
||||
}
|
||||
}
|
||||
// Compute result
|
||||
let result: [bool; code_width] = [false; code_width];
|
||||
let mut pos: i32 = 0;
|
||||
for let pattern: Vec<i32> in patterns {
|
||||
pos += append_pattern(&result, pos, &pattern, true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn find_c_type( value: &CharSequence, start: i32) -> CType {
|
||||
let last: i32 = value.length();
|
||||
if start >= last {
|
||||
return CType.UNCODABLE;
|
||||
}
|
||||
let mut c: char = value.char_at(start);
|
||||
if c == ESCAPE_FNC_1 {
|
||||
return CType.FNC_1;
|
||||
}
|
||||
if c < '0' || c > '9' {
|
||||
return CType.UNCODABLE;
|
||||
}
|
||||
if start + 1 >= last {
|
||||
return CType.ONE_DIGIT;
|
||||
}
|
||||
c = value.char_at(start + 1);
|
||||
if c < '0' || c > '9' {
|
||||
return CType.ONE_DIGIT;
|
||||
}
|
||||
return CType.TWO_DIGITS;
|
||||
}
|
||||
|
||||
fn choose_code( value: &CharSequence, start: i32, old_code: i32) -> i32 {
|
||||
let mut lookahead: CType = ::find_c_type(&value, start);
|
||||
if lookahead == CType.ONE_DIGIT {
|
||||
if old_code == CODE_CODE_A {
|
||||
return CODE_CODE_A;
|
||||
}
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
if lookahead == CType.UNCODABLE {
|
||||
if start < value.length() {
|
||||
let c: char = value.char_at(start);
|
||||
if c < ' ' || (old_code == CODE_CODE_A && (c < '`' || (c >= ESCAPE_FNC_1 && c <= ESCAPE_FNC_4))) {
|
||||
// can continue in code A, encodes ASCII 0 to 95 or FNC1 to FNC4
|
||||
return CODE_CODE_A;
|
||||
}
|
||||
}
|
||||
// no choice
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
if old_code == CODE_CODE_A && lookahead == CType.FNC_1 {
|
||||
return CODE_CODE_A;
|
||||
}
|
||||
if old_code == CODE_CODE_C {
|
||||
// can continue in code C
|
||||
return CODE_CODE_C;
|
||||
}
|
||||
if old_code == CODE_CODE_B {
|
||||
if lookahead == CType.FNC_1 {
|
||||
// can continue in code B
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
// Seen two consecutive digits, see what follows
|
||||
lookahead = ::find_c_type(&value, start + 2);
|
||||
if lookahead == CType.UNCODABLE || lookahead == CType.ONE_DIGIT {
|
||||
// not worth switching now
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
if lookahead == CType.FNC_1 {
|
||||
// two digits, then FNC_1...
|
||||
lookahead = ::find_c_type(&value, start + 3);
|
||||
if lookahead == CType.TWO_DIGITS {
|
||||
// then two more digits, switch
|
||||
return CODE_CODE_C;
|
||||
} else {
|
||||
// otherwise not worth switching
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
}
|
||||
// At this point, there are at least 4 consecutive digits.
|
||||
// Look ahead to choose whether to switch now or on the next round.
|
||||
let mut index: i32 = start + 4;
|
||||
while (lookahead = ::find_c_type(&value, index)) == CType.TWO_DIGITS {
|
||||
index += 2;
|
||||
}
|
||||
if lookahead == CType.ONE_DIGIT {
|
||||
// odd number of digits, switch later
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
// even number of digits, switch now
|
||||
return CODE_CODE_C;
|
||||
}
|
||||
// Here oldCode == 0, which means we are choosing the initial code
|
||||
if lookahead == CType.FNC_1 {
|
||||
// ignore FNC_1
|
||||
lookahead = ::find_c_type(&value, start + 1);
|
||||
}
|
||||
if lookahead == CType.TWO_DIGITS {
|
||||
// at least two digits, start in code C
|
||||
return CODE_CODE_C;
|
||||
}
|
||||
return CODE_CODE_B;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes minimally using Divide-And-Conquer with Memoization
|
||||
**/
|
||||
|
||||
const A: &'static str = format!(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ | ||||