/* * 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; /** *

Decodes Code 128 barcodes.

* * @author Sean Owen */ const CODE_PATTERNS: vec![vec![Vec>; 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, Rc> { 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, row_offset: i32) -> /* throws NotFoundException */Result> { 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 = 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) -> /* throws NotFoundException, FormatException, ChecksumException */Result> { let convert_f_n_c1: bool = hints != null && hints.contains_key(DecodeHintType::ASSUME_GS1); let symbology_modifier: i32 = 0; let start_pattern_info: Vec = ::find_start_pattern(row); let start_code: i32 = start_pattern_info[2]; let raw_codes: List = 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); } }